Merge pull request #1205 from corda/os-merge-244167d

O/S merge from 244167d
This commit is contained in:
Shams Asari 2018-07-05 17:16:52 +01:00 committed by GitHub
commit 300e0573fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
143 changed files with 881 additions and 926 deletions

9
.idea/compiler.xml generated
View File

@ -54,6 +54,12 @@
<module name="contracts-states_test" target="1.8" />
<module name="corda-core_integrationTest" target="1.8" />
<module name="corda-core_smokeTest" target="1.8" />
<module name="corda-enterprise-testing_main" target="1.8" />
<module name="corda-enterprise-testing_test" target="1.8" />
<module name="corda-enterprise-tools_main" target="1.8" />
<module name="corda-enterprise-tools_test" target="1.8" />
<module name="corda-enterprise_main" target="1.8" />
<module name="corda-enterprise_test" target="1.8" />
<module name="corda-finance_integrationTest" target="1.8" />
<module name="corda-project-testing_main" target="1.8" />
<module name="corda-project-testing_test" target="1.8" />
@ -93,6 +99,7 @@
<module name="demobench_main" target="1.8" />
<module name="demobench_test" target="1.8" />
<module name="dist_binFiles" target="1.8" />
<module name="dist_installerFiles" target="1.8" />
<module name="dist_licenseFiles" target="1.8" />
<module name="dist_main" target="1.8" />
<module name="dist_readmeFiles" target="1.8" />
@ -170,6 +177,8 @@
<module name="mock_test" target="1.8" />
<module name="network-bootstrapper_main" target="1.8" />
<module name="network-bootstrapper_test" target="1.8" />
<module name="network-verifier_main" target="1.8" />
<module name="network-verifier_test" target="1.8" />
<module name="network-visualiser_main" target="1.8" />
<module name="network-visualiser_test" target="1.8" />
<module name="node-api_main" target="1.8" />

View File

@ -7,12 +7,10 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.*
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NotaryInfo
import net.corda.core.node.services.AttachmentId
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.node.services.config.CertChainPolicyConfig
import net.corda.node.services.config.EnterpriseConfiguration
import net.corda.node.services.config.MutualExclusionConfiguration
import net.corda.node.services.config.NodeConfiguration
@ -102,7 +100,7 @@ class BridgeSmokeTest {
bridgeJar.copyToDirectory(testDir)
}
fun createNetworkParams(baseDirectory: Path) {
private fun createNetworkParams(baseDirectory: Path) {
val dummyNotaryParty = TestIdentity(DUMMY_NOTARY_NAME)
val notaryInfo = NotaryInfo(dummyNotaryParty.party, false)
val copier = NetworkParametersCopier(NetworkParameters(
@ -112,18 +110,18 @@ class BridgeSmokeTest {
maxMessageSize = 10485760,
maxTransactionSize = 40000,
epoch = 1,
whitelistedContractImplementations = emptyMap<String, List<AttachmentId>>()
whitelistedContractImplementations = emptyMap()
), overwriteFile = true)
copier.install(baseDirectory)
}
fun SSLConfiguration.createBridgeKeyStores(legalName: CordaX500Name,
rootCert: X509Certificate = DEV_ROOT_CA.certificate,
intermediateCa: CertificateAndKeyPair = DEV_INTERMEDIATE_CA) {
private fun SSLConfiguration.createBridgeKeyStores(legalName: CordaX500Name,
rootCert: X509Certificate = DEV_ROOT_CA.certificate,
intermediateCa: CertificateAndKeyPair = DEV_INTERMEDIATE_CA) {
certificatesDirectory.createDirectories()
if (!trustStoreFile.exists()) {
loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/${DEV_CA_TRUST_STORE_FILE}"), DEV_CA_TRUST_STORE_PASS).save(trustStoreFile, trustStorePassword)
loadKeyStore(javaClass.classLoader.getResourceAsStream("certificates/$DEV_CA_TRUST_STORE_FILE"), DEV_CA_TRUST_STORE_PASS).save(trustStoreFile, trustStorePassword)
}
val (nodeCaCert, nodeCaKeyPair) = createDevNodeCa(intermediateCa, legalName)
@ -189,13 +187,13 @@ class BridgeSmokeTest {
}
}
fun serverListening(host: String, port: Int): Boolean {
private fun serverListening(host: String, port: Int): Boolean {
var s: Socket? = null
try {
return try {
s = Socket(host, port)
return true
true
} catch (e: Exception) {
return false
false
} finally {
try {
s?.close()
@ -212,7 +210,6 @@ class BridgeSmokeTest {
doReturn("cordacadevpass").whenever(it).keyStorePassword
doReturn(NetworkHostAndPort("localhost", 11005)).whenever(it).p2pAddress
doReturn(null).whenever(it).jmxMonitoringHttpPort
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000), externalBridge = true)).whenever(it).enterpriseConfiguration
}
val artemisServer = ArtemisMessagingServer(artemisConfig, NetworkHostAndPort("0.0.0.0", 11005), MAX_MESSAGE_SIZE)

View File

@ -17,7 +17,6 @@ import net.corda.bridge.createBridgeKeyStores
import net.corda.bridge.createNetworkParams
import net.corda.bridge.services.artemis.BridgeArtemisConnectionServiceImpl
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.services.config.CertChainPolicyConfig
import net.corda.node.services.config.EnterpriseConfiguration
import net.corda.node.services.config.MutualExclusionConfiguration
import net.corda.node.services.config.NodeConfiguration
@ -102,7 +101,6 @@ class ArtemisConnectionTest {
doReturn("cordacadevpass").whenever(it).keyStorePassword
doReturn(NetworkHostAndPort("localhost", 11005)).whenever(it).p2pAddress
doReturn(null).whenever(it).jmxMonitoringHttpPort
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000), externalBridge = true)).whenever(it).enterpriseConfiguration
}
val artemisServer = ArtemisMessagingServer(artemisConfig, NetworkHostAndPort("0.0.0.0", 11005), MAX_MESSAGE_SIZE)

View File

@ -188,6 +188,7 @@ allprojects {
jvmTarget = "1.8"
javaParameters = true // Useful for reflection.
freeCompilerArgs = ['-Xjvm-default=compatibility']
allWarningsAsErrors = true
}
}

View File

@ -39,7 +39,6 @@ task metadata(type: ProGuardTask) {
keepattributes '*'
dontoptimize
printseeds
verbose
dontwarn 'com.sun.jna.**'
@ -47,6 +46,7 @@ task metadata(type: ProGuardTask) {
dontwarn 'org.jetbrains.kotlin.com.intellij.**'
dontwarn 'org.jetbrains.kotlin.com.google.j2objc.annotations.**'
dontwarn 'org.jetbrains.kotlin.com.google.errorprone.annotations.**'
dontnote
keep 'class org.jetbrains.kotlin.load.java.JvmAnnotationNames { *; }'
keep 'class org.jetbrains.kotlin.metadata.** { *; }', includedescriptorclasses: true
@ -68,6 +68,7 @@ task validate(type: ProGuardTask) {
verbose
dontwarn 'org.jetbrains.kotlin.com.google.errorprone.annotations.**'
dontnote
keep 'class *'
}
@ -77,5 +78,4 @@ artifacts {
}
defaultTasks "metadata"
assemble.dependsOn metadata
metadata.finalizedBy validate

View File

@ -401,6 +401,11 @@ class JacksonSupportTest(@Suppress("unused") private val name: String, factory:
testToStringSerialisation(UUID.randomUUID())
}
@Test
fun Instant() {
testToStringSerialisation(Instant.now())
}
@Test
fun `Date is treated as Instant`() {
val date = Date()

View File

@ -13,7 +13,6 @@ package net.corda.client.jfx
import net.corda.client.jfx.model.NodeMonitorModel
import net.corda.client.jfx.model.ProgressTrackingEvent
import net.corda.core.context.InvocationOrigin
import net.corda.core.contracts.Amount
import net.corda.core.contracts.ContractState
import net.corda.core.crypto.isFulfilledBy
import net.corda.core.crypto.keys
@ -32,12 +31,9 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS
import net.corda.finance.USD
import net.corda.finance.flows.CashExitFlow
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.node.services.Permissions.Companion.all
import net.corda.testing.core.*
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.driver
@ -75,18 +71,7 @@ class NodeMonitorModelTest : IntegrationTest() {
private fun setup(runTest: () -> Unit) {
driver(DriverParameters(extraCordappPackagesToScan = listOf("net.corda.finance"))) {
val cashUser = User("user1", "test", permissions = setOf(
startFlow<CashIssueFlow>(),
startFlow<CashPaymentFlow>(),
startFlow<CashExitFlow>(),
invokeRpc(CordaRPCOps::notaryIdentities),
invokeRpc("vaultTrackBy"),
invokeRpc("vaultQueryBy"),
invokeRpc(CordaRPCOps::internalVerifiedTransactionsFeed),
invokeRpc(CordaRPCOps::stateMachineRecordedTransactionMappingFeed),
invokeRpc(CordaRPCOps::stateMachinesFeed),
invokeRpc(CordaRPCOps::networkMapFeed))
)
val cashUser = User("user1", "test", permissions = setOf(all()))
val aliceNodeHandle = startNode(providedName = ALICE_NAME, rpcUsers = listOf(cashUser)).getOrThrow()
aliceNode = aliceNodeHandle.nodeInfo
newNode = { nodeName -> startNode(providedName = nodeName).getOrThrow().nodeInfo }
@ -135,11 +120,7 @@ class NodeMonitorModelTest : IntegrationTest() {
@Test
fun `cash issue works end to end`() = setup {
rpc.startFlow(::CashIssueFlow,
Amount(100, USD),
OpaqueBytes(ByteArray(1, { 1 })),
notaryParty
)
rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), notaryParty)
vaultUpdates.expectEvents(isStrict = false) {
sequence(

View File

@ -111,12 +111,12 @@ class NodeMonitorModel : AutoCloseable {
* TODO provide an unsubscribe mechanism
*/
fun register(nodeHostAndPort: NetworkHostAndPort, username: String, password: String) {
// `retryableStateMachineUpdatesSubject` will change it's upstream subscriber in case of RPC connection failure, this `Observable` should
// never produce an error.
// `stateMachineUpdatesSubject` will stay firmly subscribed to `retryableStateMachineUpdatesSubject`
retryableStateMachineUpdatesSubject.subscribe(stateMachineUpdatesSubject)
@Suppress("DEPRECATION")
// Proxy may change during re-connect, ensure that subject wiring accurately reacts to this activity.
proxyObservable.addListener { _, _, wrapper ->
if (wrapper != null) {

View File

@ -57,14 +57,16 @@ class StateMachineDataModel {
private val progressTracking by observable(NodeMonitorModel::progressTracking)
private val progressEvents = progressTracking.recordAsAssociation(ProgressTrackingEvent::stateMachineId)
val counter = Counter()
private val counter = Counter()
private val stateMachineIndexMap = HashMap<StateMachineRunId, Int>()
private val stateMachineStatus = stateMachineUpdates.fold(FXCollections.observableArrayList<SimpleObjectProperty<StateMachineStatus>>()) { list, update ->
when (update) {
is StateMachineUpdate.Added -> {
counter.addSmm()
val flowInitiator= update.stateMachineInfo.initiator
// TODO Use invocationContext instead
@Suppress("DEPRECATION")
val flowInitiator = update.stateMachineInfo.initiator
val added: SimpleObjectProperty<StateMachineStatus> =
SimpleObjectProperty(StateMachineStatus.Added(update.id, update.stateMachineInfo.flowLogicClassName, flowInitiator))
list.add(added)
@ -83,7 +85,7 @@ class StateMachineDataModel {
private val stateMachineDataList = stateMachineStatus.map {
val smStatus = it.value as StateMachineStatus.Added
val id = smStatus.id
val progress = SimpleObjectProperty(progressEvents.get(id))
val progress = SimpleObjectProperty(progressEvents[id])
StateMachineData(id, smStatus.stateMachineName, smStatus.flowInitiator,
Pair(it, EasyBind.map(progress) { ProgressStatus(it?.message) }))
}

View File

@ -58,7 +58,7 @@ data class PartiallyResolvedTransaction(
return PartiallyResolvedTransaction(
transaction = transaction,
inputs = transaction.inputs.map { stateRef ->
val tx = inputTransactions.get(stateRef)
val tx = inputTransactions[stateRef]
if (tx == null) {
InputResolution.Unresolved(stateRef)
} else {
@ -74,7 +74,7 @@ data class PartiallyResolvedTransaction(
val outputCount = transaction.coreTransaction.inputs.size
val stateRefs = (0 until outputCount).map { StateRef(transaction.id, it) }
stateRefs.map { stateRef ->
val tx = inputTransactions.get(stateRef)
val tx = inputTransactions[stateRef]
if (tx == null) {
OutputResolution.Unresolved(stateRef)
} else {
@ -94,6 +94,7 @@ class TransactionDataModel {
private val collectedTransactions = transactions.recordInSequence().distinctBy { it.id }
private val rpcProxy by observableValue(NodeMonitorModel::proxyObservable)
@Suppress("DEPRECATION")
val partiallyResolvedTransactions = collectedTransactions.map {
PartiallyResolvedTransaction.fromSignedTransaction(it,
it.inputs.map { stateRef ->

View File

@ -84,14 +84,12 @@ class FlowsExecutionModeTests : NodeBasedTest(listOf("net.corda.finance.contract
@Before
fun setup() {
node = startNode(ALICE_NAME, rpcUsers = listOf(rpcUser))
client = CordaRPCClient(node.internals.configuration.rpcOptions.address!!)
client = CordaRPCClient(node.internals.configuration.rpcOptions.address)
}
@Test
fun `flows draining mode can be enabled and queried`() {
asALoggerUser { rpcOps ->
val newValue = true
rpcOps.setFlowsDrainingModeEnabled(true)
@ -104,7 +102,6 @@ class FlowsExecutionModeTests : NodeBasedTest(listOf("net.corda.finance.contract
@Test
fun `flows draining mode can be disabled and queried`() {
asALoggerUser { rpcOps ->
rpcOps.setFlowsDrainingModeEnabled(true)
val newValue = false
@ -118,7 +115,6 @@ class FlowsExecutionModeTests : NodeBasedTest(listOf("net.corda.finance.contract
@Test
fun `node starts with flows draining mode disabled`() {
asALoggerUser { rpcOps ->
val defaultStartingMode = rpcOps.isFlowsDrainingModeEnabled()
@ -127,14 +123,12 @@ class FlowsExecutionModeTests : NodeBasedTest(listOf("net.corda.finance.contract
}
private fun login(username: String, password: String, externalTrace: Trace? = null, impersonatedActor: Actor? = null): CordaRPCConnection {
return client.start(username, password, externalTrace, impersonatedActor)
}
private fun asALoggerUser(action: (CordaRPCOps) -> Unit) {
login(rpcUser.username, rpcUser.password).use {
action(it.proxy)
}
}
}
}

View File

@ -90,6 +90,7 @@ task predeterminise(type: ProGuardTask) {
dontpreverify
dontobfuscate
dontoptimize
dontnote
printseeds
verbose
@ -133,6 +134,7 @@ task determinise(type: ProGuardTask) {
keepattributes '*'
keepdirectories
dontobfuscate
dontnote
printseeds
verbose
@ -178,7 +180,6 @@ task checkDeterminism(type: ProGuardTask, dependsOn: jdkTask) {
defaultTasks "determinise"
determinise.finalizedBy metafix
metafix.finalizedBy checkDeterminism
assemble.dependsOn checkDeterminism
def deterministicJar = metafix.outputs.files.singleFile
artifacts {

View File

@ -18,10 +18,10 @@ import java.util.*
* A unique identifier for a single state machine run, valid across node restarts. Note that a single run always
* has at least one flow, but that flow may also invoke sub-flows: they all share the same run id.
*/
@DeleteForDJVM
@CordaSerializable
data class StateMachineRunId(val uuid: UUID) {
companion object {
@DeleteForDJVM
fun createRandom(): StateMachineRunId = StateMachineRunId(UUID.randomUUID())
}

View File

@ -11,6 +11,7 @@
package net.corda.core.internal
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.DeleteForDJVM
import net.corda.core.DoNotImplement
import net.corda.core.concurrent.CordaFuture
import net.corda.core.context.InvocationContext
@ -20,6 +21,7 @@ import net.corda.core.node.ServiceHub
import org.slf4j.Logger
/** This is an internal interface that is implemented by code in the node module. You should look at [FlowLogic]. */
@DeleteForDJVM
@DoNotImplement
interface FlowStateMachine<FLOWRETURN> {
@Suspendable

View File

@ -52,7 +52,7 @@ data class StateMachineInfo @JvmOverloads constructor(
* An object representing information about the initiator of the flow. Note that this field is
* superceded by the [invocationContext] property, which has more detail.
*/
@Deprecated("There is more info available using 'context'") val initiator: FlowInitiator,
@Deprecated("There is more info available using 'invocationContext'") val initiator: FlowInitiator,
/** A [DataFeed] of the current progress step as a human readable string, and updates to that string. */
val progressTrackerStepAndUpdates: DataFeed<String, String>?,
/** An [InvocationContext] describing why and by whom the flow was started. */

View File

@ -12,11 +12,15 @@ package net.corda.core.node.services
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.DoNotImplement
import net.corda.core.crypto.CompositeKey
import net.corda.core.crypto.DigitalSignature
import net.corda.core.crypto.SignableData
import net.corda.core.crypto.TransactionSignature
import net.corda.core.identity.PartyAndCertificate
import java.security.KeyPair
import java.security.PrivateKey
import java.security.PublicKey
import java.security.cert.X509Certificate
/**
* The KMS is responsible for storing and using private keys to sign things. An implementation of this may, for example,

View File

@ -140,7 +140,7 @@ object MappedSchemaValidator {
fieldsFromOtherMappedSchema(schema) + methodsFromOtherMappedSchema(schema)
/** Returns true if [javax.persistence] annotation expect [javax.persistence.Transient] is found. */
private inline fun hasJpaAnnotation(annotations: Array<Annotation>) =
private fun hasJpaAnnotation(annotations: Array<Annotation>) =
annotations.any { annotation -> annotation.toString().startsWith("@javax.persistence.") && annotation !is javax.persistence.Transient }
class SchemaCrossReferenceReport(private val schema: String, private val entity: String, private val referencedSchema: String,

View File

@ -58,7 +58,7 @@ class WireTransaction(componentGroups: List<ComponentGroup>, val privacySalt: Pr
@DeleteForDJVM
constructor(componentGroups: List<ComponentGroup>) : this(componentGroups, PrivacySalt())
@Deprecated("Required only in some unit-tests and for backwards compatibility purposes.", ReplaceWith("WireTransaction(val componentGroups: List<ComponentGroup>, override val privacySalt: PrivacySalt)"), DeprecationLevel.WARNING)
@Deprecated("Required only for backwards compatibility purposes.", ReplaceWith("WireTransaction(val componentGroups: List<ComponentGroup>, override val privacySalt: PrivacySalt)"), DeprecationLevel.WARNING)
@DeleteForDJVM
constructor(inputs: List<StateRef>,
attachments: List<SecureHash>,

View File

@ -41,7 +41,8 @@ class ContractsDSLTests {
}
@RunWith(Parameterized::class)
class RequireSingleCommandTests(private val testFunction: (Collection<CommandWithParties<CommandData>>) -> CommandWithParties<CommandData>, description: String) {
class RequireSingleCommandTests(private val testFunction: (Collection<CommandWithParties<CommandData>>) -> CommandWithParties<CommandData>,
@Suppress("UNUSED_PARAMETER") description: String) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{1}")
@ -74,7 +75,8 @@ class ContractsDSLTests {
}
@RunWith(Parameterized::class)
class SelectWithSingleInputsTests(private val testFunction: (Collection<CommandWithParties<CommandData>>, PublicKey?, AbstractParty?) -> Iterable<CommandWithParties<CommandData>>, description: String) {
class SelectWithSingleInputsTests(private val testFunction: (Collection<CommandWithParties<CommandData>>, PublicKey?, AbstractParty?) -> Iterable<CommandWithParties<CommandData>>,
@Suppress("UNUSED_PARAMETER") description: String) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{1}")
@ -122,7 +124,8 @@ class ContractsDSLTests {
}
@RunWith(Parameterized::class)
class SelectWithMultipleInputsTests(private val testFunction: (Collection<CommandWithParties<CommandData>>, Collection<PublicKey>?, Collection<Party>?) -> Iterable<CommandWithParties<CommandData>>, description: String) {
class SelectWithMultipleInputsTests(private val testFunction: (Collection<CommandWithParties<CommandData>>, Collection<PublicKey>?, Collection<Party>?) -> Iterable<CommandWithParties<CommandData>>,
@Suppress("UNUSED_PARAMETER") description: String) {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{1}")

View File

@ -30,6 +30,7 @@ import net.corda.testing.dsl.LedgerDSL
import net.corda.testing.dsl.TestLedgerDSLInterpreter
import net.corda.testing.dsl.TestTransactionDSLInterpreter
import net.corda.testing.internal.TEST_TX_TIME
import net.corda.testing.internal.createWireTransaction
import net.corda.testing.internal.rigorousMock
import net.corda.testing.node.MockServices
import net.corda.testing.node.ledger
@ -274,7 +275,7 @@ class PartialMerkleTreeTest {
timeWindow: TimeWindow? = null,
attachments: List<SecureHash> = emptyList()
): WireTransaction {
return WireTransaction(
return createWireTransaction(
inputs = testTx.inputs,
attachments = attachments,
outputs = testTx.outputs,

View File

@ -67,7 +67,7 @@ class AttachmentTests {
bobNode.registerInitiatedFlow(FetchAttachmentsResponse::class.java)
// Insert an attachment into node zero's store directly.
val id = aliceNode.database.transaction {
aliceNode.attachments.importAttachment(fakeAttachment().inputStream())
aliceNode.attachments.importAttachment(fakeAttachment().inputStream(), "test", null)
}
// Get node one to run a flow to fetch it and insert it.
@ -120,7 +120,7 @@ class AttachmentTests {
val attachment = fakeAttachment()
// Insert an attachment into node zero's store directly.
val id = aliceNode.database.transaction {
aliceNode.attachments.importAttachment(attachment.inputStream())
aliceNode.attachments.importAttachment(attachment.inputStream(), "test", null)
}
// Corrupt its store.

View File

@ -156,7 +156,7 @@ class ResolveTransactionsFlowTest {
}
// TODO: this operation should not require an explicit transaction
val id = megaCorpNode.transaction {
megaCorpNode.services.attachments.importAttachment(makeJar())
megaCorpNode.services.attachments.importAttachment(makeJar(), "test", null)
}
val stx2 = makeTransactions(withAttachment = id).second
val p = TestFlow(stx2, megaCorp)
@ -211,6 +211,7 @@ class ResolveTransactionsFlowTest {
}
}
@Suppress("unused")
@InitiatedBy(TestFlow::class)
private class TestResponseFlow(val otherSideSession: FlowSession) : FlowLogic<Void?>() {
@Suspendable

View File

@ -21,10 +21,10 @@ import rx.Observable
import java.util.*
class TopologicalSortTest {
class DummyTransaction(
class DummyTransaction constructor(
override val id: SecureHash,
override val inputs: List<StateRef>,
val numberOfOutputs: Int,
@Suppress("CanBeParameter") private val numberOfOutputs: Int,
override val notary: Party
) : CoreTransaction() {
override val outputs: List<TransactionState<ContractState>> = (1..numberOfOutputs).map {
@ -78,7 +78,7 @@ class TopologicalSortTest {
}
// Swap two random items
transactions.combine(Generator.intRange(0, N - 1), Generator.intRange(0, N - 2)) { txs, i, j ->
transactions.combine(Generator.intRange(0, N - 1), Generator.intRange(0, N - 2)) { txs, i, _ ->
val k = 0 // if (i == j) i + 1 else j
val tmp = txs[i]
txs[i] = txs[k]
@ -94,7 +94,7 @@ class TopologicalSortTest {
}
}
fun checkTopologicallyOrdered(txs: List<SignedTransaction>) {
private fun checkTopologicallyOrdered(txs: List<SignedTransaction>) {
val outputs = HashSet<StateRef>()
for (tx in txs) {
if (!outputs.containsAll(tx.inputs)) {

View File

@ -18,6 +18,7 @@ import net.corda.core.crypto.CompositeKey
import net.corda.core.identity.Party
import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.*
import net.corda.testing.internal.createWireTransaction
import net.corda.testing.internal.rigorousMock
import org.junit.Rule
import org.junit.Test
@ -63,7 +64,7 @@ class TransactionTests {
val cpub = ck.public
val c1 = CompositeKey.Builder().addKeys(apub, bpub).build(2)
val compKey = CompositeKey.Builder().addKeys(c1, cpub).build(1)
val wtx = WireTransaction(
val wtx = createWireTransaction(
inputs = listOf(StateRef(SecureHash.randomSHA256(), 0)),
attachments = emptyList(),
outputs = emptyList(),
@ -89,7 +90,7 @@ class TransactionTests {
@Test
fun `signed transaction missing signatures`() {
val wtx = WireTransaction(
val wtx = createWireTransaction(
inputs = listOf(StateRef(SecureHash.randomSHA256(), 0)),
attachments = emptyList(),
outputs = emptyList(),
@ -129,8 +130,8 @@ class TransactionTests {
}, DummyContract.PROGRAM_ID))
val id = SecureHash.randomSHA256()
val timeWindow: TimeWindow? = null
val privacySalt: PrivacySalt = PrivacySalt()
val transaction: LedgerTransaction = LedgerTransaction(
val privacySalt = PrivacySalt()
val transaction = LedgerTransaction(
inputs,
outputs,
commands,
@ -147,7 +148,7 @@ class TransactionTests {
@Test
fun `transaction cannot have duplicate inputs`() {
val stateRef = StateRef(SecureHash.randomSHA256(), 0)
fun buildTransaction() = WireTransaction(
fun buildTransaction() = createWireTransaction(
inputs = listOf(stateRef, stateRef),
attachments = emptyList(),
outputs = emptyList(),
@ -170,7 +171,7 @@ class TransactionTests {
val attachments = emptyList<Attachment>()
val id = SecureHash.randomSHA256()
val timeWindow: TimeWindow? = null
val privacySalt: PrivacySalt = PrivacySalt()
val privacySalt = PrivacySalt()
fun buildTransaction() = LedgerTransaction(
inputs,
outputs,
@ -188,7 +189,7 @@ class TransactionTests {
@Test
fun `transactions with identical contents must have different ids`() {
val outputState = TransactionState(DummyContract.SingleOwnerState(0, ALICE), DummyContract.PROGRAM_ID, DUMMY_NOTARY)
fun buildTransaction() = WireTransaction(
fun buildTransaction() = createWireTransaction(
inputs = emptyList(),
attachments = emptyList(),
outputs = listOf(outputState),

View File

@ -136,7 +136,7 @@ class IntegrationTestingTutorial : IntegrationTest() {
// move to Bob
parallel(
(1..numberOfStates).map { i ->
expect(match = { it.moved() == i * 100 }) { update: Vault.Update<Cash.State> ->
expect(match = { it.moved() == i * 100 }) { _: Vault.Update<Cash.State> ->
}
}
),
@ -154,7 +154,7 @@ class IntegrationTestingTutorial : IntegrationTest() {
}
}
fun Vault.Update<Cash.State>.moved(): Int {
private fun Vault.Update<Cash.State>.moved(): Int {
val consumedSum = consumed.sumBy { it.state.data.amount.quantity.toInt() }
val producedSum = produced.sumBy { it.state.data.amount.quantity.toInt() }
return consumedSum - producedSum

View File

@ -40,6 +40,7 @@ import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
@ -134,7 +135,7 @@ public class FlowCookbookJava {
// We retrieve a notary from the network map.
// DOCSTART 01
CordaX500Name notaryName = new CordaX500Name("Notary Service", "London", "GB");
Party specificNotary = getServiceHub().getNetworkMapCache().getNotary(notaryName);
Party specificNotary = Objects.requireNonNull(getServiceHub().getNetworkMapCache().getNotary(notaryName));
// Alternatively, we can pick an arbitrary notary from the notary
// list. However, it is always preferable to specify the notary
// explicitly, as the notary list might change when new notaries are
@ -378,7 +379,7 @@ public class FlowCookbookJava {
// Or we can add the output state as a ``TransactionState``, which already specifies
// the output's contract and notary.
// DOCSTART 51
TransactionState txState = new TransactionState(ourOutputState, DummyContract.PROGRAM_ID, specificNotary);
TransactionState txState = new TransactionState<>(ourOutputState, DummyContract.PROGRAM_ID, specificNotary);
// DOCEND 51
// Commands can be added as ``Command``s.
@ -662,7 +663,7 @@ public class FlowCookbookJava {
}
@Override
protected void checkTransaction(SignedTransaction stx) {
protected void checkTransaction(@NotNull SignedTransaction stx) {
requireThat(require -> {
// Any additional checking we see fit...
DummyState outputState = (DummyState) stx.getTx().getOutputs().get(0).getData();

View File

@ -13,6 +13,7 @@ package net.corda.docs.java.tutorial.contract;
import net.corda.core.contracts.*;
import net.corda.core.transactions.LedgerTransaction;
import net.corda.core.transactions.LedgerTransaction.InOutGroup;
import org.jetbrains.annotations.NotNull;
import java.time.Instant;
import java.util.Currency;
@ -22,6 +23,7 @@ import static net.corda.core.contracts.ContractsDSL.requireSingleCommand;
import static net.corda.core.contracts.ContractsDSL.requireThat;
import static net.corda.finance.utils.StateSumming.sumCashBy;
@SuppressWarnings("unused")
public class CommercialPaper implements Contract {
// DOCSTART 1
public static final String IOU_CONTRACT_ID = "com.example.contract.IOUContract";
@ -29,7 +31,7 @@ public class CommercialPaper implements Contract {
// DOCSTART 3
@Override
public void verify(LedgerTransaction tx) {
public void verify(@NotNull LedgerTransaction tx) {
List<InOutGroup<State, State>> groups = tx.groupStates(State.class, State::withoutOwner);
CommandWithParties<Commands> cmd = requireSingleCommand(tx.getCommands(), Commands.class);
// DOCEND 3
@ -37,7 +39,7 @@ public class CommercialPaper implements Contract {
// DOCSTART 4
TimeWindow timeWindow = tx.getTimeWindow();
for (InOutGroup group : groups) {
for (InOutGroup<State, State> group : groups) {
List<State> inputs = group.getInputs();
List<State> outputs = group.getOutputs();
@ -57,6 +59,7 @@ public class CommercialPaper implements Contract {
Amount<Issued<Currency>> received = sumCashBy(tx.getOutputStates(), input.getOwner());
if (timeWindow == null) throw new IllegalArgumentException("Redemptions must be timestamped");
Instant time = timeWindow.getFromTime();
if (time == null) throw new IllegalArgumentException("Redemptions must have a from time");
requireThat(require -> {
require.using("the paper must have matured", time.isAfter(input.getMaturityDate()));
require.using("the received amount equals the face value", received == input.getFaceValue());
@ -68,6 +71,7 @@ public class CommercialPaper implements Contract {
State output = outputs.get(0);
if (timeWindow == null) throw new IllegalArgumentException("Issuances must have a time-window");
Instant time = timeWindow.getUntilTime();
if (time == null) throw new IllegalArgumentException("Issuances must have an until time");
requireThat(require -> {
// Don't allow people to issue commercial paper under other entities identities.
require.using("output states are issued by a command signer", cmd.getSigners().contains(output.getIssuance().getParty().getOwningKey()));

View File

@ -50,6 +50,7 @@ enum class PrintOrVisualise {
Visualise
}
@Suppress("DEPRECATION")
fun main(args: Array<String>) {
require(args.isNotEmpty()) { "Usage: <binary> [Print|Visualise]" }
val printOrVisualise = PrintOrVisualise.valueOf(args[0])
@ -109,6 +110,7 @@ fun main(args: Array<String>) {
}
}
// END 5
Unit
}
}

View File

@ -8,7 +8,7 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
@file:Suppress("UNUSED_VARIABLE", "unused")
@file:Suppress("UNUSED_VARIABLE", "unused", "DEPRECATION")
package net.corda.docs

View File

@ -8,6 +8,8 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
@file:Suppress("UNUSED_VARIABLE")
package net.corda.docs.tutorial.tearoffs
import net.corda.core.contracts.Command
@ -52,4 +54,4 @@ fun main(args: Array<String>) {
} catch (e: FilteredTransactionVerificationException) {
throw MerkleTreeException("Rate Fix Oracle: Couldn't verify partial Merkle tree.")
}
}
}

View File

@ -43,6 +43,27 @@ Optionally run the node's webserver as well by opening a terminal window in the
.. warning:: The node webserver is for testing purposes only and will be removed soon.
Command-line options
~~~~~~~~~~~~~~~~~~~~
The node can optionally be started with the following command-line options:
* ``--base-directory``: The node working directory where all the files are kept (default: ``.``)
* ``--bootstrap-raft-cluster``: Bootstraps Raft cluster. The node forms a single node cluster (ignoring otherwise configured peer
addresses), acting as a seed for other nodes to join the cluster
* ``--config-file``: The path to the config file (default: ``node.conf``)
* ``--help``
* ``--initial-registration``: Start initial node registration with Corda network to obtain certificate from the permissioning
server
* ``--just-generate-node-info``: Perform the node start-up task necessary to generate its nodeInfo, save it to disk, then
quit
* ``--log-to-console``: If set, prints logging to the console as well as to a file
* ``--logging-level <[ERROR,WARN,INFO, DEBUG,TRACE]>``: Enable logging at this level and higher (default: INFO)
* ``--network-root-truststore``: Network root trust store obtained from network operator
* ``--network-root-truststore-password``: Network root trust store password obtained from network operator
* ``--no-local-shell``: Do not start the embedded shell locally
* ``--sshd``: Enables SSHD server for node administration
* ``--version``: Print the version and exit
Enabling remote debugging
~~~~~~~~~~~~~~~~~~~~~~~~~
To enable remote debugging of the node, run the following from the terminal window:
@ -61,8 +82,11 @@ This command line will start the node with JMX metrics accessible via HTTP on po
See :ref:`Monitoring your node <jolokia_ref>` for further details.
Starting all nodes at once from the command line (native)
---------------------------------------------------------
Starting all nodes at once from the command line
------------------------------------------------
Native
~~~~~~
If you created your nodes using ``deployNodes``, a ``runnodes`` shell script (or batch file on Windows) will have been
generated to allow you to quickly start up all nodes and their webservers. ``runnodes`` should only be used for testing
purposes.
@ -79,8 +103,8 @@ If you receive an ``OutOfMemoryError`` exception when interacting with the nodes
Java heap memory available to them, which you can do when running them individually. See
:ref:`starting-an-individual-corda-node`.
Starting all nodes at once from the command line (docker-compose)
-----------------------------------------------------------------
docker-compose
~~~~~~~~~~~~~~
If you created your nodes using ``Dockerform``, the ``docker-compose.yml`` file and corresponding ``Dockerfile`` for
nodes has been created and configured appropriately. Navigate to ``build/nodes`` directory and run ``docker-compose up``
command. This will startup nodes inside new, internal network.

View File

@ -411,32 +411,38 @@ For more information on the client RPC interface and how to build an RPC client
Running nodes across machines
-----------------------------
The nodes can be split across different machines and configured to communicate across the network.
The nodes can be configured to communicate as a network even when distributed across several machines:
After deploying the nodes, navigate to the build folder (``kotlin-source/build/nodes``) and for each node that needs to
be moved to another machine open its config file and change the Artemis messaging address to the IP address of the machine
where the node will run (e.g. ``p2pAddress="10.18.0.166:10007"``).
* Deploy the nodes as usual:
These changes require new node-info files to be distributed amongst the nodes. Use the network bootstrapper tool
(see :doc:`network-bootstrapper` for more information on this and how to built it) to update the files and have
them distributed locally.
* Unix/Mac OSX: ``./gradlew deployNodes``
* Windows: ``gradlew.bat deployNodes``
``java -jar network-bootstrapper.jar kotlin-source/build/nodes``
* Navigate to the build folder (``kotlin-source/build/nodes``)
* For each node, open its ``node.conf`` file and change ``localhost`` in its ``p2pAddress`` to the IP address of the machine
where the node will be run (e.g. ``p2pAddress="10.18.0.166:10007"``)
* These changes require new node-info files to be distributed amongst the nodes. Use the network bootstrapper tool
(see :doc:`network-bootstrapper`) to update the files and have them distributed locally:
Once that's done move the node folders to their designated machines (e.g. using a USB key). It is important that none of the
nodes - including the notary - end up on more than one machine. Each computer should also have a copy of ``runnodes``
and ``runnodes.bat``.
``java -jar network-bootstrapper.jar kotlin-source/build/nodes``
For example, you may end up with the following layout:
* Move the node folders to their individual machines (e.g. using a USB key). It is important that none of the
nodes - including the notary - end up on more than one machine. Each computer should also have a copy of ``runnodes``
and ``runnodes.bat``.
* Machine 1: ``Notary``, ``PartyA``, ``runnodes``, ``runnodes.bat``
* Machine 2: ``PartyB``, ``PartyC``, ``runnodes``, ``runnodes.bat``
For example, you may end up with the following layout:
After starting each node, the nodes will be able to see one another and agree IOUs among themselves.
* Machine 1: ``Notary``, ``PartyA``, ``runnodes``, ``runnodes.bat``
* Machine 2: ``PartyB``, ``PartyC``, ``runnodes``, ``runnodes.bat``
.. note:: If you are using H2 and wish to use the same ``h2port`` value for all the nodes, then only assign them that
value after the nodes have been moved to their machines. The initial bootstrapping process requires access to the nodes'
databases and if they share the same H2 port then the process will fail.
* After starting each node, the nodes will be able to see one another and agree IOUs among themselves
.. warning:: The bootstrapper must be run **after** the ``node.conf`` files have been modified, but **before** the nodes
are distributed across machines. Otherwise, the nodes will not be able to communicate.
.. note:: If you are using H2 and wish to use the same ``h2port`` value for two or more nodes, you must only assign them that
value after the nodes have been moved to their individual machines. The initial bootstrapping process requires access to the
nodes' databases and if two nodes share the same H2 port, the process will fail.
Testing and debugging
---------------------

View File

@ -1,41 +1,23 @@
buildscript {
ext.kotlin_version = '1.2.40'
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.3'
classpath "com.github.jengelman.gradle.plugins:shadow:$shadow_version"
}
}
plugins {
id "org.jetbrains.kotlin.jvm"
id 'com.github.johnrengelman.shadow' version '2.0.3'
id 'java'
id 'application'
}
repositories {
mavenCentral()
}
apply plugin: 'kotlin'
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile group: 'info.picocli', name: 'picocli', version: '3.0.1'
testCompile group: 'junit', name: 'junit', version: '4.12'
}
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "1.8"
}
compile "info.picocli:picocli:3.0.1"
testCompile "junit:junit:$junit_version"
}
mainClassName = "net.corda.avalanche.MainKt"
shadowJar {
baseName = "avalanche"

View File

@ -8,37 +8,18 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
buildscript {
ext.commonsio_version = '2.6'
ext.commonslogging_version = '1.2'
ext.cucumber_version = '1.2.5'
ext.crash_version = 'cce5a00f114343c1145c1d7756e1dd6df3ea984e'
ext.docker_client_version = '8.11.0'
repositories {
maven {
jcenter()
url 'https://jitpack.io'
}
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
ext {
commonsio_version = '2.6'
cucumber_version = '1.2.5'
crash_version = 'cce5a00f114343c1145c1d7756e1dd6df3ea984e'
docker_client_version = '8.11.0'
}
group 'net.corda.behave'
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'net.corda.plugins.publish-utils'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
sourceSets {
behave {
kotlin {
@ -89,6 +70,7 @@ dependencies {
compile "org.slf4j:log4j-over-slf4j:$slf4j_version"
compile "org.slf4j:jul-to-slf4j:$slf4j_version"
compile "org.slf4j:jcl-over-slf4j:$slf4j_version"
compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4j_version"
compile "org.apache.logging.log4j:log4j-core:$log4j_version"
@ -96,10 +78,9 @@ dependencies {
compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version"
// FastClasspathScanner: classpath scanning
compile 'io.github.lukehutch:fast-classpath-scanner:2.12.3'
compile "io.github.lukehutch:fast-classpath-scanner:$fast_classpath_scanner_version"
compile "commons-io:commons-io:$commonsio_version"
compile "commons-logging:commons-logging:$commonslogging_version"
compile "com.spotify:docker-client:$docker_client_version"
compile "io.reactivex:rxjava:$rxjava_version"
@ -122,14 +103,6 @@ dependencies {
behaveCompile "info.cukes:cucumber-picocontainer:$cucumber_version"
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
test {
testLogging.showStandardStreams = true
}

View File

@ -11,19 +11,19 @@
package net.corda.behave.network
import net.corda.behave.database.DatabaseType
import net.corda.behave.file.*
import net.corda.behave.monitoring.PatternWatch
import net.corda.behave.file.LogSource
import net.corda.behave.file.currentDirectory
import net.corda.behave.file.stagingRoot
import net.corda.behave.file.tmpDirectory
import net.corda.behave.node.Distribution
import net.corda.behave.node.Node
import net.corda.behave.node.configuration.NotaryType
import net.corda.behave.process.Command
import net.corda.behave.process.JarCommand
import net.corda.core.CordaException
import net.corda.core.CordaRuntimeException
import net.corda.core.internal.*
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.minutes
import net.corda.core.utilities.seconds
import java.io.Closeable
import java.nio.file.Files
import java.nio.file.Path
@ -147,116 +147,8 @@ class Network private constructor(
* using Local signing and "Auto Approval" mode
*/
private fun bootstrapDoorman() {
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
signalFailure("Bootstrapping a Corda Enterprise network using the Doorman is no longer supported; exiting ...")
return
// WARNING!! Need to use the correct bootstrapper
// only if using OS nodes (need to choose the latest version)
val r3node = nodes.values
.find { it.config.distribution.type == Distribution.Type.CORDA_ENTERPRISE } ?: throw CordaRuntimeException("Missing R3 distribution node")
val distribution = r3node.config.distribution
// Copy over reference configuration files used in bootstrapping
val source = doormanConfigDirectory
val doormanTargetDirectory = targetDirectory / "doorman"
source.toFile().copyRecursively(doormanTargetDirectory.toFile(), true)
// Use master version of Bootstrapper
val doormanJar = Distribution.R3_MASTER.doormanJar
log.info("DoormanJar URL: $doormanJar\n")
// 1. Create key stores for local signer
// java -jar doorman-<version>.jar --mode ROOT_KEYGEN
log.info("Doorman target directory: $doormanTargetDirectory")
runCommand(JarCommand(doormanJar,
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf", "--mode", "ROOT_KEYGEN", "--trust-store-password", "password"),
doormanTargetDirectory, timeout))
// java -jar doorman-<version>.jar --mode CA_KEYGEN
runCommand(JarCommand(doormanJar,
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf", "--mode", "CA_KEYGEN"),
doormanTargetDirectory, timeout))
// 2. Start the doorman service for notary registration
doormanNMS = JarCommand(doormanJar,
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf"),
doormanTargetDirectory, timeout)
val doormanCommand = runCommand(doormanNMS, noWait = true)
log.info("Waiting for DoormanNMS to be alive")
PatternWatch(doormanCommand.output, "Network management web services started on").await(30.seconds)
log.info("DoormanNMS up and running")
// Notary Nodes
val notaryNodes = nodes.values.filter { it.config.notary.notaryType != NotaryType.NONE }
notaryNodes.forEach { notaryNode ->
val notaryTargetDirectory = targetDirectory / notaryNode.config.name
log.info("Notary target directory: $notaryTargetDirectory")
// 3. Create notary node and register with the doorman
runCommand(JarCommand(distribution.cordaJar,
arrayOf("--initial-registration",
"--base-directory", "$notaryTargetDirectory",
"--network-root-truststore", "../doorman/certificates/distribute-nodes/network-root-truststore.jks",
"--network-root-truststore-password", "password"),
notaryTargetDirectory, timeout))
// 4. Generate node info files for notary nodes
runCommand(JarCommand(distribution.cordaJar,
arrayOf("--just-generate-node-info",
"--base-directory", "$notaryTargetDirectory"),
notaryTargetDirectory, timeout))
// cp (or ln -s) nodeInfo* notary-node-info
val nodeInfoFile = notaryTargetDirectory.toFile().listFiles { _, filename -> filename.matches("nodeInfo-.+".toRegex()) }.firstOrNull() ?: throw CordaRuntimeException("Missing notary nodeInfo file")
Files.copy(nodeInfoFile.toPath(), (notaryTargetDirectory / "notary-node-info"), StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING)
}
// exit Doorman process
doormanCommand.interrupt()
doormanCommand.waitFor()
// 5. Add notary identities to the network parameters
// 6. Load initial network parameters file for network map service
val networkParamsConfig = if (notaryNodes.isEmpty()) "network-parameters-without-notary.conf" else "network-parameters.conf"
val updateNetworkParams = JarCommand(doormanJar,
arrayOf("--config-file", "$doormanTargetDirectory/node.conf", "--set-network-parameters", "$doormanTargetDirectory/$networkParamsConfig"),
doormanTargetDirectory, timeout)
runCommand(updateNetworkParams)
// 7. Start a fully configured Doorman / NMS
doormanNMS = JarCommand(doormanJar,
arrayOf("--config-file", "$doormanConfigDirectory/node.conf"),
doormanTargetDirectory, timeout)
val doormanNMSCommand = runCommand(doormanNMS, noWait = true)
log.info("Waiting for DoormanNMS to be alive")
PatternWatch(doormanNMSCommand.output, "Network management web services started on").await(30.seconds)
log.info("DoormanNMS up and running")
// 8. Register other participant nodes
val partyNodes = nodes.values.filter { it.config.notary.notaryType == NotaryType.NONE }
partyNodes.forEach { partyNode ->
val partyTargetDirectory = targetDirectory / partyNode.config.name
log.info("Party target directory: $partyTargetDirectory")
// 3. Create notary node and register with the doorman
runCommand(JarCommand(distribution.cordaJar,
arrayOf("--initial-registration",
"--network-root-truststore", "../doorman/certificates/distribute-nodes/network-root-truststore.jks",
"--network-root-truststore-password", "password",
"--base-directory", "$partyTargetDirectory"),
partyTargetDirectory, timeout))
}
isDoormanNMSRunning = true
}
private fun runCommand(command: Command, noWait: Boolean = false): Command {
@ -446,7 +338,7 @@ class Network private constructor(
val rpcProxyPortNo = node.config.nodeInterface.rpcProxy
val pid = Files.lines(tmpDirectory / "rpcProxy-pid-$rpcProxyPortNo").findFirst().get()
// TODO: consider generic implementation to support non *nix platforms
Command(listOf("kill", "-9", "$pid")).run()
Command(listOf("kill", "-9", pid)).run()
(tmpDirectory / "rpcProxy-pid-$rpcProxyPortNo").deleteIfExists()
}
catch (e: Exception) {

View File

@ -14,7 +14,6 @@ import net.corda.behave.database.DatabaseConnection
import net.corda.behave.database.DatabaseType
import net.corda.behave.file.LogSource
import net.corda.behave.file.currentDirectory
import net.corda.behave.file.stagingRoot
import net.corda.behave.monitoring.PatternWatch
import net.corda.behave.node.configuration.*
import net.corda.behave.process.JarCommand
@ -31,8 +30,8 @@ import net.corda.core.internal.div
import net.corda.core.internal.exists
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.minutes
import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.minutes
import net.corda.core.utilities.seconds
import org.apache.commons.io.FileUtils
import java.net.InetAddress
@ -45,7 +44,7 @@ import java.util.concurrent.CountDownLatch
*/
class Node(
val config: Configuration,
val rootDirectory: Path = currentDirectory,
private val rootDirectory: Path = currentDirectory,
private val settings: ServiceSettings = ServiceSettings(),
val rpcProxy: Boolean = false,
val networkType: Distribution.Type
@ -77,18 +76,6 @@ class Node(
private var haveDependenciesStopped = false
fun describe(): String {
val network = config.nodeInterface
val database = config.database
return """
|Node Information: ${config.name}
| - P2P: ${network.host}:${network.p2pPort}
| - RPC: ${network.host}:${network.rpcPort}
| - SSH: ${network.host}:${network.sshPort}
| - DB: ${network.host}:${database.port} (${database.type})
|""".trimMargin()
}
fun configure() {
if (isConfigured) { return }
isConfigured = true
@ -164,10 +151,6 @@ class Node(
}
}
val nodeInfoGenerationOutput: LogSource by lazy {
LogSource(logDirectory, "node-info-gen.log")
}
val logOutput: LogSource by lazy {
val hostname = InetAddress.getLocalHost().hostName
LogSource(logDirectory, "node-$hostname.*.log")
@ -387,10 +370,11 @@ class Node(
val name = name ?: error("Node name not set")
val directory = directory ?: error("Runtime directory not set")
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
val compatibilityZoneURL = null
if (networkType == Distribution.Type.CORDA_ENTERPRISE && System.getProperty("USE_NETWORK_SERVICES") != null)
"http://localhost:1300" // TODO: add additional USE_NETWORK_SERVICES_URL to specify location of existing operational environment to use.
else null
val compatibilityZoneURL = if (networkType == Distribution.Type.CORDA_ENTERPRISE && System.getProperty("USE_NETWORK_SERVICES") != null) {
"http://localhost:1300" // TODO: add additional USE_NETWORK_SERVICES_URL to specify location of existing operational environment to use.
} else {
null
}
return Node(
Configuration(
name,

View File

@ -72,7 +72,7 @@ class ScenarioState {
inline fun <T> withNetwork(action: ScenarioState.() -> T): T {
ensureNetworkIsRunning()
return action()
return this.action()
}
inline fun <T> withClient(nodeName: String, crossinline action: (CordaRPCOps) -> T): T {

View File

@ -10,34 +10,33 @@
package net.corda.behave.scenarios.helpers
import net.corda.behave.logging.getLogger
import net.corda.behave.scenarios.ScenarioState
import net.corda.core.messaging.CordaRPCOps
import org.slf4j.Logger
import org.slf4j.LoggerFactory
abstract class Substeps(protected val state: ScenarioState) {
protected val log: Logger = LoggerFactory.getLogger(javaClass)
protected val log = getLogger<Substeps>()
protected fun withNetwork(action: ScenarioState.() -> Unit) =
state.withNetwork(action)
protected fun withNetwork(action: ScenarioState.() -> Unit) = state.withNetwork(action)
protected fun <T> withClient(nodeName: String, action: ScenarioState.(CordaRPCOps) -> T): T {
return state.withClient(nodeName, {
return@withClient try {
return state.withClient(nodeName) {
try {
action(state, it)
} catch (ex: Exception) {
state.error<T>(ex.message ?: "Failed to execute RPC call")
state.error(ex.message ?: "Failed to execute RPC call")
}
})
}
}
protected fun <T> withClientProxy(nodeName: String, action: ScenarioState.(CordaRPCOps) -> T): T {
return state.withClientProxy(nodeName, {
return@withClientProxy try {
return state.withClientProxy(nodeName) {
try {
action(state, it)
} catch (ex: Exception) {
state.error<T>(ex.message ?: "Failed to execute HTTP call")
state.error(ex.message ?: "Failed to execute HTTP call")
}
})
}
}
}
}

View File

@ -15,7 +15,6 @@ import org.junit.Test
import rx.observers.TestSubscriber
class CommandTests {
@Test
fun `successful command returns zero`() {
val exitCode = Command(listOf("ls", "/")).run()

View File

@ -34,7 +34,7 @@ dependencies {
compile project(':finance')
// ObjectWeb Asm: a library for synthesising and working with JVM bytecode.
compile "org.ow2.asm:asm:5.0.4"
compile "org.ow2.asm:asm:$asm_version"
compile "com.google.guava:guava:$guava_version"

View File

@ -34,7 +34,6 @@ repositories {
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
apply plugin: 'idea'
description 'A javaagent to allow hooking into Kryo'

View File

@ -114,7 +114,6 @@ object FiberMonitor {
thread {
while (true) {
Thread.sleep(1000)
this
}
}
}

View File

@ -12,7 +12,7 @@ package net.corda.flowhook
import java.lang.instrument.Instrumentation
@Suppress("UNUSED")
@Suppress("UNUSED", "UNUSED_PARAMETER")
class FlowHookAgent {
companion object {
@JvmStatic
@ -22,4 +22,3 @@ class FlowHookAgent {
}
}
}

View File

@ -21,7 +21,7 @@ import org.apache.activemq.artemis.core.io.buffer.TimedBuffer
import java.sql.Connection
import java.util.concurrent.TimeUnit
@Suppress("UNUSED")
@Suppress("UNUSED", "UNUSED_PARAMETER")
object FlowHookContainer {
@JvmStatic

View File

@ -34,7 +34,6 @@ repositories {
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
apply plugin: 'idea'
apply plugin: 'net.corda.plugins.cordapp'

View File

@ -11,13 +11,11 @@ import java.util.concurrent.Callable
// Responsible for executing test scenario for a single node executing `LinearStateBatchNotariseFlow` and verifying the results
class LinearStateScenarioRunner(options: OptionSet) : AbstractScenarioRunner(options), Callable<Boolean> {
companion object {
private val logger = contextLogger()
}
override fun call(): Boolean {
scenarioInitialized()
try {
@ -42,6 +40,7 @@ class LinearStateScenarioRunner(options: OptionSet) : AbstractScenarioRunner(opt
}
}
@Suppress("UNUSED_PARAMETER")
private fun verifyResultsAndStatesTally(results: MutableList<LinearStateBatchNotariseFlow.Result>, states: Vault.Page<LinearStateBatchNotariseContract.State>): Boolean {
// Unfortunately, there is absolutely nothing in `LinearStateBatchNotariseFlow.Result` which can link it to the original transaction
return true

View File

@ -8,33 +8,11 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
buildscript {
// For sharing constants between builds
Properties constants = new Properties()
file("$projectDir/../../constants.properties").withInputStream { constants.load(it) }
ext.kotlin_version = constants.getProperty("kotlinVersion")
ext.javaassist_version = "3.12.1.GA"
repositories {
mavenLocal()
mavenCentral()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
repositories {
mavenLocal()
mavenCentral()
jcenter()
ext {
javaassist_version = "3.12.1.GA"
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
apply plugin: 'idea'
description 'A javaagent to allow hooking into Kryo'

View File

@ -8,33 +8,11 @@
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
buildscript {
// For sharing constants between builds
Properties constants = new Properties()
file("$projectDir/../../constants.properties").withInputStream { constants.load(it) }
ext.kotlin_version = constants.getProperty("kotlinVersion")
ext.javaassist_version = "3.12.1.GA"
repositories {
mavenLocal()
mavenCentral()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
repositories {
mavenLocal()
mavenCentral()
jcenter()
ext {
javaassist_version = "3.12.1.GA"
}
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
apply plugin: 'idea'
description 'A javaagent to allow hooking into the instrumentation by Quasar'

View File

@ -12,12 +12,12 @@ package net.corda.finance.contracts.universal
import net.corda.core.crypto.toStringShort
import net.corda.core.identity.Party
import net.corda.core.internal.uncheckedCast
import java.math.BigDecimal
import java.security.PublicKey
import java.time.Instant
private class PrettyPrint(arr : Arrangement) {
val parties = involvedParties(arr)
private val sb = StringBuilder()
@ -26,21 +26,21 @@ private class PrettyPrint(arr : Arrangement) {
private var atStart = true
private fun print(msg: String) {
if (atStart)
repeat(indentLevel, { sb.append(' ') })
repeat(indentLevel) { sb.append(' ') }
sb.append(msg)
atStart = false
}
private fun println(message: Any?) {
if (atStart)
repeat(indentLevel, { sb.append(' ') })
repeat(indentLevel) { sb.append(' ') }
sb.appendln(message)
atStart = true
}
private fun print(msg: Any?) {
if (atStart)
repeat(indentLevel, { sb.append(' ') })
repeat(indentLevel) { sb.append(' ') }
sb.append(msg)
atStart = false
}
@ -55,8 +55,7 @@ private class PrettyPrint(arr : Arrangement) {
val partyMap = mutableMapOf<PublicKey, String>()
val usedPartyNames = mutableSetOf<String>()
fun createPartyName(party : Party) : String
{
fun createPartyName(party : Party): String {
val parts = party.name.organisation.toLowerCase().split(' ')
var camelName = parts.drop(1).fold(parts.first()) {
@ -79,38 +78,38 @@ private class PrettyPrint(arr : Arrangement) {
}
}
fun prettyPrint(per: Perceivable<Boolean>, x: Boolean? = null) {
fun prettyPrintBoolean(per: Perceivable<Boolean>) {
when (per) {
is Const -> print("\"${per.value}\"")
is PerceivableOr -> {
prettyPrint(per.left)
prettyPrintBoolean(per.left)
print(" or ")
prettyPrint(per.right)
prettyPrintBoolean(per.right)
}
is PerceivableAnd -> {
prettyPrint(per.left)
prettyPrintBoolean(per.left)
print(" and ")
prettyPrint(per.right)
prettyPrintBoolean(per.right)
}
is TimePerceivable -> {
when (per.cmp) {
Comparison.GT, Comparison.GTE -> {
print("after(")
prettyPrint(per.instant)
prettyPrintInstant(per.instant)
print(")")
}
Comparison.LT, Comparison.LTE -> {
print("before(")
prettyPrint(per.instant)
prettyPrintInstant(per.instant)
print(")")
}
}
}
is PerceivableComparison<*> -> {
when (per.type) {
BigDecimal::class.java -> prettyPrint(per.left as Perceivable<BigDecimal>)
Instant::class.java -> prettyPrint(per.left as Perceivable<Instant>)
Boolean::class.java -> prettyPrint(per.left as Perceivable<Boolean>)
BigDecimal::class.java -> prettyPrintBigDecimal(uncheckedCast(per.left))
Instant::class.java -> prettyPrintInstant(uncheckedCast(per.left))
Boolean::class.java -> prettyPrintBoolean(uncheckedCast(per.left))
}
when (per.cmp) {
Comparison.GT -> print(" > ")
@ -119,9 +118,9 @@ private class PrettyPrint(arr : Arrangement) {
Comparison.LTE -> print(" <= ")
}
when (per.type) {
BigDecimal::class.java -> prettyPrint(per.right as Perceivable<BigDecimal>)
Instant::class.java -> prettyPrint(per.right as Perceivable<Instant>)
Boolean::class.java -> prettyPrint(per.right as Perceivable<Boolean>)
BigDecimal::class.java -> prettyPrintBigDecimal(uncheckedCast(per.right))
Instant::class.java -> prettyPrintInstant(uncheckedCast(per.right))
Boolean::class.java -> prettyPrintBoolean(uncheckedCast(per.right))
}
}
is TerminalEvent -> print("TerminalEvent(${partyMap[per.reference.owningKey]}, \"${per.source}\")")
@ -130,7 +129,7 @@ private class PrettyPrint(arr : Arrangement) {
}
}
fun prettyPrint(per: Perceivable<Instant>, x: Instant? = null) {
fun prettyPrintInstant(per: Perceivable<Instant>) {
when (per) {
is Const -> print("\"${per.value}\"")
is StartDate -> print("startDate")
@ -139,34 +138,33 @@ private class PrettyPrint(arr : Arrangement) {
}
}
fun prettyPrint(per: Perceivable<BigDecimal>, x: BigDecimal? = null) {
fun prettyPrintBigDecimal(per: Perceivable<BigDecimal>) {
when (per) {
is PerceivableOperation<BigDecimal> -> {
prettyPrint(per.left)
prettyPrintBigDecimal(per.left)
when (per.op) {
Operation.PLUS -> print(" + ")
Operation.MINUS -> print(" - ")
Operation.DIV -> print(" / ")
Operation.TIMES -> print(" * ")
else -> print(per.op)
}
prettyPrint(per.right)
prettyPrintBigDecimal(per.right)
}
is UnaryPlus -> {
print("(")
prettyPrint(per.arg)
prettyPrintBigDecimal(per.arg)
print(".).plus()")
}
is Const -> print(per.value)
is Interest -> {
print("Interest(")
prettyPrint(per.amount)
prettyPrintBigDecimal(per.amount)
print(", \"${per.dayCountConvention}\", ")
prettyPrint(per.amount)
prettyPrintBigDecimal(per.amount)
print(", ")
prettyPrint(per.start)
prettyPrintInstant(per.start)
print(", ")
prettyPrint(per.end)
prettyPrintInstant(per.end)
print(")")
}
is CurrencyCross -> print("${per.foreign}/${per.domestic}")
@ -175,7 +173,6 @@ private class PrettyPrint(arr : Arrangement) {
}
fun prettyPrint(arr: Arrangement) {
when (arr) {
is Zero -> println("zero")
is RollOut -> {
@ -193,7 +190,7 @@ private class PrettyPrint(arr : Arrangement) {
is Continuation -> println("next()")
is Obligation -> {
print("${partyMap[arr.from.owningKey]}.gives( ${partyMap[arr.to.owningKey]}, ")
prettyPrint(arr.amount)
prettyPrintBigDecimal(arr.amount)
println(", ${arr.currency})")
}
is Actions -> {
@ -201,7 +198,7 @@ private class PrettyPrint(arr : Arrangement) {
indent {
for ((name, condition, arrangement) in arr.actions) {
print("\"$name\".givenThat(")
prettyPrint(condition)
prettyPrintBoolean(condition)
println(") {")
indent {
prettyPrint(arrangement)

View File

@ -46,46 +46,45 @@ class UniversalContract : Contract {
class Split(val ratio: BigDecimal) : Commands
}
fun eval(@Suppress("UNUSED_PARAMETER") tx: LedgerTransaction, expr: Perceivable<Instant>): Instant? = when (expr) {
fun evalInstant(expr: Perceivable<Instant>): Instant? = when (expr) {
is Const -> expr.value
is StartDate -> null
is EndDate -> null
else -> throw Error("Unable to evaluate")
}
fun eval(tx: LedgerTransaction, expr: Perceivable<Boolean>): Boolean = when (expr) {
is PerceivableAnd -> eval(tx, expr.left) && eval(tx, expr.right)
is PerceivableOr -> eval(tx, expr.left) || eval(tx, expr.right)
fun evalBoolean(tx: LedgerTransaction, expr: Perceivable<Boolean>): Boolean = when (expr) {
is PerceivableAnd -> evalBoolean(tx, expr.left) && evalBoolean(tx, expr.right)
is PerceivableOr -> evalBoolean(tx, expr.left) || evalBoolean(tx, expr.right)
is Const<Boolean> -> expr.value
is TimePerceivable -> when (expr.cmp) {
Comparison.LTE -> tx.timeWindow!!.fromTime!! <= eval(tx, expr.instant)
Comparison.GTE -> tx.timeWindow!!.untilTime!! >= eval(tx, expr.instant)
Comparison.LTE -> tx.timeWindow!!.fromTime!! <= evalInstant(expr.instant)
Comparison.GTE -> tx.timeWindow!!.untilTime!! >= evalInstant(expr.instant)
else -> throw NotImplementedError("eval special")
}
is ActorPerceivable -> tx.commands.single().signers.contains(expr.actor.owningKey)
else -> throw NotImplementedError("eval - Boolean - " + expr.javaClass.name)
}
fun eval(tx: LedgerTransaction, expr: Perceivable<BigDecimal>): BigDecimal =
fun evalBigDecimal(tx: LedgerTransaction, expr: Perceivable<BigDecimal>): BigDecimal =
when (expr) {
is Const<BigDecimal> -> expr.value
is UnaryPlus -> {
val x = eval(tx, expr.arg)
val x = evalBigDecimal(tx, expr.arg)
if (x > BigDecimal.ZERO)
x
else
BigDecimal.ZERO
}
is PerceivableOperation -> {
val l = eval(tx, expr.left)
val r = eval(tx, expr.right)
val l = evalBigDecimal(tx, expr.left)
val r = evalBigDecimal(tx, expr.right)
when (expr.op) {
Operation.DIV -> l / r
Operation.MINUS -> l - r
Operation.PLUS -> l + r
Operation.TIMES -> l * r
else -> throw NotImplementedError("eval - amount - operation " + expr.op)
}
}
is Fixing -> {
@ -93,8 +92,8 @@ class UniversalContract : Contract {
0.0.bd
}
is Interest -> {
val a = eval(tx, expr.amount)
val i = eval(tx, expr.interest)
val a = evalBigDecimal(tx, expr.amount)
val i = evalBigDecimal(tx, expr.interest)
//TODO
@ -105,7 +104,7 @@ class UniversalContract : Contract {
fun validateImmediateTransfers(tx: LedgerTransaction, arrangement: Arrangement): Arrangement = when (arrangement) {
is Obligation -> {
val amount = eval(tx, arrangement.amount)
val amount = evalBigDecimal(tx, arrangement.amount)
requireThat { "transferred quantity is non-negative" using (amount >= BigDecimal.ZERO) }
Obligation(const(amount), arrangement.currency, arrangement.from, arrangement.to)
}
@ -220,7 +219,7 @@ class UniversalContract : Contract {
"action must have a time-window" using (tx.timeWindow != null)
// "action must be authorized" by (cmd.signers.any { action.actors.any { party -> party.owningKey == it } })
// todo perhaps merge these two requirements?
"condition must be met" using (eval(tx, action.condition))
"condition must be met" using evalBoolean(tx, action.condition)
}
// verify that any resulting transfers can be resolved
@ -297,7 +296,7 @@ class UniversalContract : Contract {
perceivable.dayCountConvention, replaceFixing(tx, perceivable.interest, fixings, unusedFixings),
perceivable.start, perceivable.end))
is Fixing -> {
val dt = eval(tx, perceivable.date)
val dt = evalInstant(perceivable.date)
if (dt != null && fixings.containsKey(FixOf(perceivable.source, dt.toLocalDate(), perceivable.tenor))) {
unusedFixings.remove(FixOf(perceivable.source, dt.toLocalDate(), perceivable.tenor))
uncheckedCast(Const(fixings[FixOf(perceivable.source, dt.toLocalDate(), perceivable.tenor)]!!))

View File

@ -24,13 +24,12 @@ class IRS {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
val notional = 50.M
val currency = EUR
val tradeDate: LocalDate = LocalDate.of(2016, 9, 1)
private val testTxTime1: Instant = Instant.parse("2017-09-02T12:00:00.00Z")
private val notional = 50.M
private val currency = EUR
private val tradeDate: LocalDate = LocalDate.of(2016, 9, 1)
/*
@ -43,7 +42,7 @@ class IRS {
*/
val contractInitial = arrange {
private val contractInitial = arrange {
rollOut("2016-09-01".ld, "2018-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank) may {
@ -62,7 +61,8 @@ class IRS {
}
}
}
val contractAfterFixingFirst = arrange {
private val contractAfterFixingFirst = arrange {
actions {
(acmeCorp or highStreetBank) may {
val floating = interest(notional, "act/365", 1.0.bd, "2016-09-01", "2016-12-01")
@ -93,15 +93,15 @@ class IRS {
rollOut("2016-12-01".ld, "2018-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank) may {
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
val nextFloating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end)
val nextFixed = interest(notional, "act/365", 0.5.bd, start, end)
"pay floating" anytime {
highStreetBank.owes(acmeCorp, floating - fixed, currency)
highStreetBank.owes(acmeCorp, nextFloating - nextFixed, currency)
next()
}
"pay fixed" anytime {
highStreetBank.owes(acmeCorp, fixed - floating, currency)
highStreetBank.owes(acmeCorp, nextFixed - nextFloating, currency)
next()
}
}
@ -112,7 +112,7 @@ class IRS {
}
}
val contractAfterExecutionFirst = arrange {
private val contractAfterExecutionFirst = arrange {
rollOut("2016-12-01".ld, "2018-09-01".ld, Frequency.Quarterly) {
actions {
(acmeCorp or highStreetBank) may {
@ -132,19 +132,20 @@ class IRS {
}
}
val paymentFirst = arrange { highStreetBank.owes(acmeCorp, 250.K, EUR) }
private val paymentFirst = arrange { highStreetBank.owes(acmeCorp, 250.K, EUR) }
val stateInitial = UniversalContract.State(listOf(DUMMY_NOTARY), contractInitial)
private val stateInitial = UniversalContract.State(listOf(DUMMY_NOTARY), contractInitial)
val stateAfterFixingFirst = UniversalContract.State(listOf(DUMMY_NOTARY), contractAfterFixingFirst)
val stateAfterExecutionFirst = UniversalContract.State(listOf(DUMMY_NOTARY), contractAfterExecutionFirst)
private val stateAfterFixingFirst = UniversalContract.State(listOf(DUMMY_NOTARY), contractAfterFixingFirst)
private val stateAfterExecutionFirst = UniversalContract.State(listOf(DUMMY_NOTARY), contractAfterExecutionFirst)
private val statePaymentFirst = UniversalContract.State(listOf(DUMMY_NOTARY), paymentFirst)
val statePaymentFirst = UniversalContract.State(listOf(DUMMY_NOTARY), paymentFirst)
@Test
fun issue() {
transaction {
output(UNIVERSAL_PROGRAM_ID, stateInitial)
timeWindow(TEST_TX_TIME_1)
timeWindow(testTxTime1)
tweak {
command(acmeCorp.owningKey, UniversalContract.Commands.Issue())
@ -160,7 +161,7 @@ class IRS {
transaction {
input(UNIVERSAL_PROGRAM_ID, stateInitial)
output(UNIVERSAL_PROGRAM_ID, stateAfterFixingFirst)
timeWindow(TEST_TX_TIME_1)
timeWindow(testTxTime1)
tweak {
command(highStreetBank.owningKey, UniversalContract.Commands.Action("some undefined name"))
@ -200,7 +201,7 @@ class IRS {
input(UNIVERSAL_PROGRAM_ID, stateAfterFixingFirst)
output(UNIVERSAL_PROGRAM_ID, stateAfterExecutionFirst)
output(UNIVERSAL_PROGRAM_ID, statePaymentFirst)
timeWindow(TEST_TX_TIME_1)
timeWindow(testTxTime1)
tweak {
command(highStreetBank.owningKey, UniversalContract.Commands.Action("some undefined name"))

View File

@ -27,8 +27,8 @@ class CashSelectionOracleImpl : AbstractCashSelection(maxRetries = 16, retrySlee
private val log = contextLogger()
}
override fun isCompatible(metaData: DatabaseMetaData): Boolean {
return metaData.driverName.startsWith(JDBC_DRIVER_NAME, ignoreCase = true)
override fun isCompatible(metadata: DatabaseMetaData): Boolean {
return metadata.driverName.startsWith(JDBC_DRIVER_NAME, ignoreCase = true)
}
override fun toString() = "${this::class.qualifiedName} for '$JDBC_DRIVER_NAME'"

View File

@ -16,7 +16,6 @@ import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.toBase58String
import java.sql.Connection
import java.sql.DatabaseMetaData
import java.sql.ResultSet
@ -32,8 +31,8 @@ class CashSelectionSQLServerImpl : AbstractCashSelection(maxRetries = 16, retryS
private val log = contextLogger()
}
override fun isCompatible(metaData: DatabaseMetaData): Boolean {
return metaData.driverName.startsWith(JDBC_DRIVER_NAME, ignoreCase = true)
override fun isCompatible(metadata: DatabaseMetaData): Boolean {
return metadata.driverName.startsWith(JDBC_DRIVER_NAME, ignoreCase = true)
}
override fun toString() = "${this::class.qualifiedName} for '$JDBC_DRIVER_NAME'"

View File

@ -8,7 +8,6 @@ import java.nio.file.Paths
import kotlin.system.exitProcess
fun main(args: Array<String>) {
if (args.isEmpty()) {
println("Usage: launcher <main-class-name> [args]")
exitProcess(0)
@ -54,15 +53,14 @@ fun main(args: Array<String>) {
@Suppress("unchecked")
private fun fixBaseDirArg(args: Array<String>, nodeBaseDirFromArgs: Path): Array<String> {
val baseDirIdx = args.indexOf("--base-directory")
if (baseDirIdx != -1){
args[baseDirIdx+1] = nodeBaseDirFromArgs.toString()
return args
return if (baseDirIdx != -1) {
// Replace the arg that follows, i.e. --base-directory X
// TODO This will not work for --base-directory=X
args[baseDirIdx + 1] = nodeBaseDirFromArgs.toString()
args
} else {
args + listOf("--base-directory", nodeBaseDirFromArgs.toString())
}
val argsWithBaseDir = args.copyOf(args.size + 2)
argsWithBaseDir[argsWithBaseDir.lastIndex - 1] = "--base-directory"
argsWithBaseDir[argsWithBaseDir.lastIndex] = nodeBaseDirFromArgs.toString()
return argsWithBaseDir as Array<String>
}
private fun setupClassLoader(nodeBaseDir: Path): ClassLoader {

View File

@ -35,6 +35,8 @@ import java.util.*
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
import kotlin.reflect.KType
import kotlin.reflect.full.createInstance
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
import kotlin.reflect.full.primaryConstructor
import kotlin.reflect.jvm.jvmErasure
@ -42,6 +44,17 @@ import kotlin.reflect.jvm.jvmErasure
@Target(AnnotationTarget.PROPERTY)
annotation class OldConfig(val value: String)
/**
* This annotation can be used to provide ConfigParser for the class,
* the [parseAs] method will use the provided parser instead of data class constructs to parse the object.
*/
@Target(AnnotationTarget.CLASS)
annotation class CustomConfigParser(val parser: KClass<out ConfigParser<*>>)
interface ConfigParser<T> {
fun parse(config: Config): T
}
const val CUSTOM_NODE_PROPERTIES_ROOT = "custom"
// TODO Move other config parsing to use parseAs and remove this
@ -50,7 +63,10 @@ operator fun <T : Any> Config.getValue(receiver: Any, metadata: KProperty<*>): T
}
fun <T : Any> Config.parseAs(clazz: KClass<T>, onUnknownKeys: ((Set<String>, logger: Logger) -> Unit) = UnknownConfigKeysPolicy.FAIL::handle, nestedPath: String? = null): T {
require(clazz.isData) { "Only Kotlin data classes can be parsed. Offending: ${clazz.qualifiedName}" }
// Use custom parser if provided, instead of treating the object as data class.
clazz.findAnnotation<CustomConfigParser>()?.let { return uncheckedCast(it.parser.createInstance().parse(this)) }
require(clazz.isData) { "Only Kotlin data classes or class annotated with CustomConfigParser can be parsed. Offending: ${clazz.qualifiedName}" }
val constructor = clazz.primaryConstructor!!
val parameters = constructor.parameters
val parameterNames = parameters.flatMap { param ->

View File

@ -237,6 +237,36 @@ class ConfigParsingTest {
}
}
@Test
fun `parse with provided parser`() {
val type1Config = mapOf("type" to "1", "value" to "type 1 value")
val type2Config = mapOf("type" to "2", "value" to "type 2 value")
val configuration = config("values" to listOf(type1Config, type2Config))
val objects = configuration.parseAs<TestObjects>()
assertThat(objects.values).containsExactly(TestObject.Type1("type 1 value"), TestObject.Type2("type 2 value"))
}
class TestParser : ConfigParser<TestObject> {
override fun parse(config: Config): TestObject {
val type = config.getInt("type")
return when (type) {
1 -> config.parseAs<TestObject.Type1>(onUnknownKeys = UnknownConfigKeysPolicy.IGNORE::handle)
2 -> config.parseAs<TestObject.Type2>(onUnknownKeys = UnknownConfigKeysPolicy.IGNORE::handle)
else -> throw IllegalArgumentException("Unsupported Object type : '$type'")
}
}
}
data class TestObjects(val values: List<TestObject>)
@CustomConfigParser(TestParser::class)
sealed class TestObject {
data class Type1(val value: String) : TestObject()
data class Type2(val value: String) : TestObject()
}
private inline fun <reified S : SingleData<V>, reified L : ListData<V>, V : Any> testPropertyType(
value1: V,
value2: V,
@ -320,6 +350,7 @@ class ConfigParsingTest {
require(positive > 0) { "$positive is not positive" }
}
}
data class OldData(
@OldConfig("oldValue")
val newValue: String)

View File

@ -63,6 +63,7 @@ class AuthDBTests : NodeBasedTest() {
private lateinit var client: CordaRPCClient
private lateinit var db: UsersDB
@Suppress("MemberVisibilityCanBePrivate")
@Parameterized.Parameter
lateinit var passwordEncryption: PasswordEncryption
@ -110,7 +111,7 @@ class AuthDBTests : NodeBasedTest() {
)
node = startNode(ALICE_NAME, rpcUsers = emptyList(), configOverrides = securityConfig)
client = CordaRPCClient(node.internals.configuration.rpcOptions.address!!)
client = CordaRPCClient(node.internals.configuration.rpcOptions.address)
}
@Test
@ -243,9 +244,8 @@ private data class RoleAndPermissions(val role: String, val permissions: List<St
/*
* Manage in-memory DB mocking a users database with the schema expected by Node's security manager
*/
private class UsersDB : AutoCloseable {
val jdbcUrl: String
private class UsersDB(name: String, users: List<UserAndRoles> = emptyList(), roleAndPermissions: List<RoleAndPermissions> = emptyList()) : AutoCloseable {
val jdbcUrl = "jdbc:h2:mem:$name;DB_CLOSE_DELAY=-1"
companion object {
const val DB_CREATE_SCHEMA = """
@ -295,11 +295,7 @@ private class UsersDB : AutoCloseable {
}
}
constructor(name: String,
users: List<UserAndRoles> = emptyList(),
roleAndPermissions: List<RoleAndPermissions> = emptyList()) {
jdbcUrl = "jdbc:h2:mem:$name;DB_CLOSE_DELAY=-1"
init {
dataSource = DataSourceFactory.createDataSource(Properties().apply {
put("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
put("dataSource.url", jdbcUrl)
@ -307,11 +303,9 @@ private class UsersDB : AutoCloseable {
session {
it.execute(DB_CREATE_SCHEMA)
}
require(users.map { it.username }.toSet().size == users.size) {
"Duplicate username in input"
}
users.forEach { insert(it) }
roleAndPermissions.forEach { insert(it) }
}

View File

@ -257,7 +257,7 @@ class MySQLNotaryServiceTests : IntegrationTest() {
}
private fun createNotaryNode(): InternalMockNetwork.MockNode {
val dataStoreProperties = makeTestDataSourceProperties(configSupplier = { _, _ -> ConfigFactory.empty() }, fallBackConfigSupplier = ::inMemoryH2DataSourceConfig).apply {
val dataStoreProperties = makeInternalTestDataSourceProperties(configSupplier = { ConfigFactory.empty() }).apply {
setProperty("autoCommit", "false")
}
return mockNet.createUnstartedNode(

View File

@ -32,7 +32,6 @@ import net.corda.testing.internal.DEV_ROOT_CA
import net.corda.testing.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
import net.corda.testing.node.NotarySpec
import net.corda.testing.node.internal.CompatibilityZoneParams
import net.corda.testing.node.internal.SharedCompatibilityZoneParams
import net.corda.testing.node.internal.internalDriver
import net.corda.testing.node.internal.network.NetworkMapServer
@ -64,7 +63,6 @@ class NodeRegistrationTest : IntegrationTest() {
private val notaryName = CordaX500Name("NotaryService", "Zurich", "CH")
private val aliceName = CordaX500Name("Alice", "London", "GB")
private val genevieveName = CordaX500Name("Genevieve", "London", "GB")
private val log = contextLogger()
}
@Rule
@ -82,7 +80,7 @@ class NodeRegistrationTest : IntegrationTest() {
pollInterval = 1.seconds,
hostAndPort = portAllocation.nextHostAndPort(),
myHostNameValue = "localhost",
additionalServices = registrationHandler)
additionalServices = *arrayOf(registrationHandler))
serverHostAndPort = server.start()
}

View File

@ -78,7 +78,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
@Test
fun `login to a non ssl port as a node user`() {
val attacker = clientTo(alice.internals.configuration.rpcOptions.address!!, sslConfiguration = null)
val attacker = clientTo(alice.internals.configuration.rpcOptions.address, sslConfiguration = null)
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
attacker.start(NODE_P2P_USER, NODE_P2P_USER, enableSSL = false)
}
@ -86,7 +86,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
@Test
fun `login to a non ssl port as a peer user`() {
val attacker = clientTo(alice.internals.configuration.rpcOptions.address!!, sslConfiguration = null)
val attacker = clientTo(alice.internals.configuration.rpcOptions.address, sslConfiguration = null)
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
attacker.start(PEER_USER, PEER_USER, enableSSL = false) // Login as a peer
}

View File

@ -18,7 +18,7 @@ import org.junit.Test
*/
class MQSecurityAsRPCTest : RPCMQSecurityTest() {
override fun createAttacker(): SimpleMQClient {
return clientTo(alice.internals.configuration.rpcOptions.address!!)
return clientTo(alice.internals.configuration.rpcOptions.address)
}
@Test

View File

@ -41,6 +41,7 @@ import net.corda.testing.node.internal.NodeBasedTest
import net.corda.testing.node.internal.startFlow
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
import org.apache.activemq.artemis.api.core.RoutingType
import org.apache.activemq.artemis.api.core.SimpleString
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.ClassRule
@ -125,9 +126,9 @@ abstract class MQSecurityTest : NodeBasedTest() {
}
fun loginToRPCAndGetClientQueue(): String {
loginToRPC(alice.internals.configuration.rpcOptions.address!!, rpcUser)
loginToRPC(alice.internals.configuration.rpcOptions.address, rpcUser)
val clientQueueQuery = SimpleString("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.${rpcUser.username}.*")
val client = clientTo(alice.internals.configuration.rpcOptions.address!!)
val client = clientTo(alice.internals.configuration.rpcOptions.address)
client.start(rpcUser.username, rpcUser.password, false)
return client.session.addressQuery(clientQueueQuery).queueNames.single().toString()
}
@ -140,7 +141,7 @@ abstract class MQSecurityTest : NodeBasedTest() {
fun assertTempQueueCreationAttackFails(queue: String) {
assertAttackFails(queue, "CREATE_NON_DURABLE_QUEUE") {
attacker.session.createTemporaryQueue(queue, queue)
attacker.session.createTemporaryQueue(queue, RoutingType.MULTICAST, queue)
}
// Double-check
assertThatExceptionOfType(ActiveMQNonExistentQueueException::class.java).isThrownBy {
@ -157,7 +158,7 @@ abstract class MQSecurityTest : NodeBasedTest() {
fun assertNonTempQueueCreationAttackFails(queue: String, durable: Boolean) {
val permission = if (durable) "CREATE_DURABLE_QUEUE" else "CREATE_NON_DURABLE_QUEUE"
assertAttackFails(queue, permission) {
attacker.session.createQueue(queue, queue, durable)
attacker.session.createQueue(queue, RoutingType.MULTICAST, queue, durable)
}
// Double-check
assertThatExceptionOfType(ActiveMQNonExistentQueueException::class.java).isThrownBy {

View File

@ -14,11 +14,10 @@ import com.typesafe.config.Config
import com.typesafe.config.ConfigException
import net.corda.core.context.AuthServiceId
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div
import net.corda.core.internal.TimedFlow
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.seconds
import net.corda.node.internal.artemis.CertificateChainCheckPolicy
import net.corda.node.services.config.rpc.NodeRpcOptions
import net.corda.nodeapi.BrokerRpcSslOptions
import net.corda.nodeapi.internal.config.NodeSSLConfiguration
@ -51,6 +50,7 @@ interface NodeConfiguration : NodeSSLConfiguration {
val devModeOptions: DevModeOptions?
val compatibilityZoneURL: URL?
val networkServices: NetworkServicesConfig?
@Suppress("DEPRECATION")
val certificateChainCheckPolicies: List<CertChainPolicyConfig>
val verifierType: VerifierType
val flowTimeout: FlowTimeoutConfiguration
@ -237,6 +237,7 @@ data class NodeConfigurationImpl(
override val messagingServerExternal: Boolean = (messagingServerAddress != null),
override val enterpriseConfiguration: EnterpriseConfiguration,
override val notary: NotaryConfig?,
@Suppress("DEPRECATION")
@Deprecated("Do not configure")
override val certificateChainCheckPolicies: List<CertChainPolicyConfig> = emptyList(),
override val devMode: Boolean = false,
@ -413,6 +414,7 @@ data class NodeConfigurationImpl(
}
// Check for usage of deprecated config
@Suppress("DEPRECATION")
if(certificateChainCheckPolicies.isNotEmpty()) {
logger.warn("""You are configuring certificateChainCheckPolicies. This is a setting that is not used, and will be removed in a future version.
|Please contact the R3 team on the public slack to discuss your use case.
@ -467,18 +469,7 @@ enum class CertChainPolicyType {
}
@Deprecated("Do not use")
data class CertChainPolicyConfig(val role: String, private val policy: CertChainPolicyType, private val trustedAliases: Set<String>) {
val certificateChainCheckPolicy: CertificateChainCheckPolicy
get() {
return when (policy) {
CertChainPolicyType.Any -> CertificateChainCheckPolicy.Any
CertChainPolicyType.RootMustMatch -> CertificateChainCheckPolicy.RootMustMatch
CertChainPolicyType.LeafMustMatch -> CertificateChainCheckPolicy.LeafMustMatch
CertChainPolicyType.MustContainOneOf -> CertificateChainCheckPolicy.MustContainOneOf(trustedAliases)
CertChainPolicyType.UsernameMustMatch -> CertificateChainCheckPolicy.UsernameMustMatchCommonName
}
}
}
data class CertChainPolicyConfig(val role: String, private val policy: CertChainPolicyType, private val trustedAliases: Set<String>)
// Supported types of authentication/authorization data providers
enum class AuthDataSourceType {
@ -515,8 +506,6 @@ data class SecurityConfiguration(val authService: SecurityConfiguration.AuthServ
}
}
fun copyWithAdditionalUser(user: User) = AuthService(dataSource.copyWithAdditionalUser(user), id, options)
// Optional components: cache
data class Options(val cache: Options.Cache?) {
@ -544,12 +533,6 @@ data class SecurityConfiguration(val authService: SecurityConfiguration.AuthServ
AuthDataSourceType.DB -> require(users == null && connection != null)
}
}
fun copyWithAdditionalUser(user: User): DataSource {
val extendedList = this.users?.toMutableList() ?: mutableListOf()
extendedList.add(user)
return DataSource(this.type, this.passwordEncryption, this.connection, listOf(*extendedList.toTypedArray()))
}
}
companion object {

View File

@ -34,7 +34,7 @@ import javax.annotation.concurrent.ThreadSafe
*/
// TODO There is duplicated logic between this and PersistentIdentityService
@ThreadSafe
class InMemoryIdentityService(identities: List<out PartyAndCertificate> = emptyList(),
class InMemoryIdentityService(identities: List<PartyAndCertificate> = emptyList(),
override val trustRoot: X509Certificate) : SingletonSerializeAsToken(), IdentityService {
companion object {
private val log = contextLogger()

View File

@ -63,7 +63,7 @@ class E2ETestKeyManagementService(val identityService: IdentityService,
}
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): PartyAndCertificate {
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey))
}
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))

View File

@ -40,8 +40,7 @@ import java.time.Duration
fun freshCertificate(identityService: IdentityService,
subjectPublicKey: PublicKey,
issuer: PartyAndCertificate,
issuerSigner: ContentSigner,
revocationEnabled: Boolean = false): PartyAndCertificate {
issuerSigner: ContentSigner): PartyAndCertificate {
val issuerRole = CertRole.extract(issuer.certificate)
require(issuerRole == CertRole.LEGAL_IDENTITY) { "Confidential identities can only be issued from well known identities, provided issuer ${issuer.name} has role $issuerRole" }
val issuerCert = issuer.certificate

View File

@ -98,8 +98,9 @@ class PersistentKeyManagementService(val identityService: IdentityService,
return keyPair.public
}
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): PartyAndCertificate =
freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey), revocationEnabled)
override fun freshKeyAndCert(identity: PartyAndCertificate, revocationEnabled: Boolean): PartyAndCertificate {
return freshCertificate(identityService, freshKey(), identity, getSigner(identity.owningKey))
}
private fun getSigner(publicKey: PublicKey): ContentSigner = getSigner(getSigningKeyPair(publicKey))

View File

@ -16,6 +16,7 @@ import net.corda.node.utilities.AffinityExecutor
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.NODE_DATABASE_PREFIX
import org.hibernate.Session
import org.hibernate.query.NativeQuery
import java.io.Serializable
import java.sql.SQLTransientConnectionException
import java.time.Duration
@ -132,7 +133,7 @@ class RunOnceService(private val database: CordaPersistence, private val machine
private fun insertMutualExclusion(session: Session) {
val query = session.createNativeQuery("INSERT INTO $TABLE VALUES ('X', :machineName, :pid, CURRENT_TIMESTAMP, :version)", MutualExclusion::class.java)
query.unwrap(org.hibernate.SQLQuery::class.java).addSynchronizedEntityClass(MutualExclusion::class.java)
query.unwrap(NativeQuery::class.java).addSynchronizedEntityClass(MutualExclusion::class.java)
query.setParameter("pid", pid)
query.setParameter("machineName", machineName)
query.setParameter("version", 0)

View File

@ -70,7 +70,7 @@ class MultiThreadedStateMachineManager(
val checkpointStorage: CheckpointStorage,
val executor: ExecutorService,
val database: CordaPersistence,
val secureRandom: SecureRandom,
private val secureRandom: SecureRandom,
private val unfinishedFibers: ReusableLatch = ReusableLatch(),
private val classloader: ClassLoader = MultiThreadedStateMachineManager::class.java.classLoader
) : StateMachineManager, StateMachineManagerInternal {
@ -158,7 +158,7 @@ class MultiThreadedStateMachineManager(
}
serviceHub.networkMapCache.nodeReady.then {
resumeRestoredFlows(fibers)
flowMessaging.start { receivedMessage, deduplicationHandler ->
flowMessaging.start { _, deduplicationHandler ->
lifeCycle.requireState(State.STARTED, StateMachineStoppedException("Flow cannot be started. State machine is stopped.")) {
deliverExternalEvent(deduplicationHandler.externalCause)
}
@ -306,10 +306,10 @@ class MultiThreadedStateMachineManager(
}
private fun checkQuasarJavaAgentPresence() {
check(SuspendableHelper.isJavaAgentActive(), {
check(SuspendableHelper.isJavaAgentActive()) {
"""Missing the '-javaagent' JVM argument. Make sure you run the tests with the Quasar java agent attached to your JVM.
#See https://docs.corda.net/troubleshooting.html - 'Fiber classes not instrumented' for more details.""".trimMargin("#")
})
}
}
private fun decrementLiveFibers() {
@ -324,8 +324,7 @@ class MultiThreadedStateMachineManager(
return checkpointStorage.getAllCheckpoints().map { (id, serializedCheckpoint) ->
// If a flow is added before start() then don't attempt to restore it
if (concurrentBox.content.flows.containsKey(id)) return@map null
val checkpoint = deserializeCheckpoint(serializedCheckpoint)
if (checkpoint == null) return@map null
val checkpoint = deserializeCheckpoint(serializedCheckpoint) ?: return@map null
createFlowFromCheckpoint(
id = id,
checkpoint = checkpoint,
@ -440,7 +439,7 @@ class MultiThreadedStateMachineManager(
val flowId = sessionToFlow[recipientId]
if (flowId == null) {
deduplicationHandler.afterDatabaseTransaction()
if (sessionMessage.payload is EndSessionMessage) {
if (sessionMessage.payload === EndSessionMessage) {
logger.debug {
"Got ${EndSessionMessage::class.java.simpleName} for " +
"unknown session $recipientId, discarding..."
@ -537,12 +536,6 @@ class MultiThreadedStateMachineManager(
isStartIdempotent: Boolean
): CordaFuture<FlowStateMachine<A>> {
val flowId = StateMachineRunId.createRandom()
val deduplicationSeed = when (flowStart) {
FlowStart.Explicit -> flowId.uuid.toString()
is FlowStart.Initiated ->
"${flowStart.initiatingMessage.initiatorSessionId.toLong}-" +
"${flowStart.initiatingMessage.initiationEntropy}"
}
// Before we construct the state machine state by freezing the FlowLogic we need to make sure that lazy properties
// have access to the fiber (and thereby the service hub)
@ -553,7 +546,7 @@ class MultiThreadedStateMachineManager(
val frozenFlowLogic = (flowLogic as FlowLogic<*>).serialize(context = checkpointSerializationContext!!)
val flowCorDappVersion = FlowStateMachineImpl.createSubFlowVersion(serviceHub.cordappProvider.getCordappForFlow(flowLogic), serviceHub.myInfo.platformVersion)
val initialCheckpoint = Checkpoint.create(invocationContext, flowStart, flowLogic.javaClass, frozenFlowLogic, ourIdentity, deduplicationSeed, flowCorDappVersion).getOrThrow()
val initialCheckpoint = Checkpoint.create(invocationContext, flowStart, flowLogic.javaClass, frozenFlowLogic, ourIdentity, flowCorDappVersion).getOrThrow()
val startedFuture = openFuture<Unit>()
val initialState = StateMachineState(
checkpoint = initialCheckpoint,
@ -721,7 +714,7 @@ class MultiThreadedStateMachineManager(
private fun addAndStartFlow(id: StateMachineRunId, flow: Flow) {
val checkpoint = flow.fiber.snapshot().checkpoint
for (sessionId in getFlowSessionIds(checkpoint)) {
sessionToFlow.put(sessionId, id)
sessionToFlow[sessionId] = id
}
concurrentBox.concurrent {
val oldFlow = flows.put(id, flow)

View File

@ -66,10 +66,10 @@ import kotlin.streams.toList
@ThreadSafe
class SingleThreadedStateMachineManager(
val serviceHub: ServiceHubInternal,
val checkpointStorage: CheckpointStorage,
private val checkpointStorage: CheckpointStorage,
val executor: ExecutorService,
val database: CordaPersistence,
val secureRandom: SecureRandom,
private val secureRandom: SecureRandom,
private val unfinishedFibers: ReusableLatch = ReusableLatch(),
private val classloader: ClassLoader = SingleThreadedStateMachineManager::class.java.classLoader
) : StateMachineManager, StateMachineManagerInternal {
@ -145,7 +145,7 @@ class SingleThreadedStateMachineManager(
}
serviceHub.networkMapCache.nodeReady.then {
resumeRestoredFlows(fibers)
flowMessaging.start { receivedMessage, deduplicationHandler ->
flowMessaging.start { _, deduplicationHandler ->
executor.execute {
deliverExternalEvent(deduplicationHandler.externalCause)
}
@ -296,10 +296,10 @@ class SingleThreadedStateMachineManager(
}
private fun checkQuasarJavaAgentPresence() {
check(SuspendableHelper.isJavaAgentActive(), {
check(SuspendableHelper.isJavaAgentActive()) {
"""Missing the '-javaagent' JVM argument. Make sure you run the tests with the Quasar java agent attached to your JVM.
#See https://docs.corda.net/troubleshooting.html - 'Fiber classes not instrumented' for more details.""".trimMargin("#")
})
}
}
private fun decrementLiveFibers() {
@ -314,8 +314,7 @@ class SingleThreadedStateMachineManager(
return checkpointStorage.getAllCheckpoints().map { (id, serializedCheckpoint) ->
// If a flow is added before start() then don't attempt to restore it
mutex.locked { if (flows.containsKey(id)) return@map null }
val checkpoint = deserializeCheckpoint(serializedCheckpoint)
if (checkpoint == null) return@map null
val checkpoint = deserializeCheckpoint(serializedCheckpoint) ?: return@map null
logger.debug { "Restored $checkpoint" }
createFlowFromCheckpoint(
id = id,
@ -534,12 +533,6 @@ class SingleThreadedStateMachineManager(
isStartIdempotent: Boolean
): CordaFuture<FlowStateMachine<A>> {
val flowId = StateMachineRunId.createRandom()
val deduplicationSeed = when (flowStart) {
FlowStart.Explicit -> flowId.uuid.toString()
is FlowStart.Initiated ->
"${flowStart.initiatingMessage.initiatorSessionId.toLong}-" +
"${flowStart.initiatingMessage.initiationEntropy}"
}
// Before we construct the state machine state by freezing the FlowLogic we need to make sure that lazy properties
// have access to the fiber (and thereby the service hub)
@ -551,7 +544,7 @@ class SingleThreadedStateMachineManager(
val flowCorDappVersion = createSubFlowVersion(serviceHub.cordappProvider.getCordappForFlow(flowLogic), serviceHub.myInfo.platformVersion)
val initialCheckpoint = Checkpoint.create(invocationContext, flowStart, flowLogic.javaClass, frozenFlowLogic, ourIdentity, deduplicationSeed, flowCorDappVersion).getOrThrow()
val initialCheckpoint = Checkpoint.create(invocationContext, flowStart, flowLogic.javaClass, frozenFlowLogic, ourIdentity, flowCorDappVersion).getOrThrow()
val startedFuture = openFuture<Unit>()
val initialState = StateMachineState(
checkpoint = initialCheckpoint,

View File

@ -2,6 +2,7 @@ package net.corda.node.services.statemachine
import net.corda.core.flows.StateMachineRunId
import net.corda.core.internal.ThreadBox
import net.corda.core.internal.TimedFlow
import net.corda.core.internal.bufferUntilSubscribed
import net.corda.core.messaging.DataFeed
import net.corda.core.utilities.contextLogger
@ -100,12 +101,6 @@ class StaffedFlowHospital {
private data class ConsultationReport(val error: Throwable, val diagnosis: Diagnosis, val by: List<Staff>)
/**
* The flow running in [flowFiber] has cleaned, possibly as a result of a flow hospital resume.
*/
// It's okay for flows to be cleaned... we fix them now!
fun flowCleaned(flowFiber: FlowFiber) = Unit
/**
* The flow has been removed from the state machine.
*/

View File

@ -79,7 +79,6 @@ data class Checkpoint(
flowLogicClass: Class<FlowLogic<*>>,
frozenFlowLogic: SerializedBytes<FlowLogic<*>>,
ourIdentity: Party,
deduplicationSeed: String,
subFlowVersion: SubFlowVersion
): Try<Checkpoint> {
return SubFlow.create(flowLogicClass, subFlowVersion).map { topLevelSubFlow ->

View File

@ -55,9 +55,7 @@ class HospitalisingInterceptor(
when (nextState.checkpoint.errorState) {
is ErrorState.Clean -> {
if (hospitalisedFlows.remove(fiber.id) != null) {
flowHospital.flowCleaned(fiber)
}
hospitalisedFlows.remove(fiber.id)
}
is ErrorState.Errored -> {
val exceptionsToHandle = nextState.checkpoint.errorState.errors.map { it.exception }

View File

@ -86,7 +86,7 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
Transactional.Committed(value)
} else {
// Some database transactions, including us, writing, with readers seeing whatever is in the database and writers seeing the (in memory) value.
Transactional.InFlight(this, key, { loadValue(key) }).apply { alsoWrite(value) }
Transactional.InFlight(this, key, _readerValueLoader = { loadValue(key) }).apply { alsoWrite(value) }
}
}
@ -156,13 +156,13 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
}
// Helpers to know if transaction(s) are currently writing the given key.
protected fun weAreWriting(key: K): Boolean = pendingKeys.get(key)?.contains(contextTransaction) ?: false
protected fun anyoneWriting(key: K): Boolean = pendingKeys.get(key)?.isNotEmpty() ?: false
protected fun weAreWriting(key: K): Boolean = pendingKeys[key]?.contains(contextTransaction) ?: false
protected fun anyoneWriting(key: K): Boolean = pendingKeys[key]?.isNotEmpty() ?: false
// Indicate this database transaction is a writer of this key.
private fun addPendingKey(key: K, databaseTransaction: DatabaseTransaction): Boolean {
var added = true
pendingKeys.compute(key) { k, oldSet ->
pendingKeys.compute(key) { _, oldSet ->
if (oldSet == null) {
val newSet = HashSet<DatabaseTransaction>(0)
newSet += databaseTransaction
@ -177,7 +177,7 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
// Remove this database transaction as a writer of this key, because the transaction committed or rolled back.
private fun removePendingKey(key: K, databaseTransaction: DatabaseTransaction) {
pendingKeys.compute(key) { k, oldSet ->
pendingKeys.compute(key) { _, oldSet ->
if (oldSet == null) {
oldSet
} else {
@ -209,7 +209,7 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
}
// No one can see it.
class Missing<T>() : Transactional<T>() {
class Missing<T> : Transactional<T>() {
override val value: T
get() = throw NoSuchElementException("Not present")
override val isPresent: Boolean
@ -238,7 +238,7 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
fun alsoWrite(_value: T) {
// Make the lazy loader the writers see actually just return the value that has been set.
writerValueLoader.set({ _value })
writerValueLoader.set { _value }
// We make all these vals so that the lambdas do not need a reference to this, and so the onCommit only has a weak ref to the value.
// We want this so that the cache could evict the value (due to memory constraints etc) without the onCommit callback
// retaining what could be a large memory footprint object.
@ -252,10 +252,9 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
// and then stop saying the transaction is writing the key.
tx.onCommit {
if (strongComitted.compareAndSet(false, true)) {
val dereferencedKey = strongKey
val dereferencedValue = weakValue.get()
if (dereferencedValue != null) {
strongMap.cache.put(dereferencedKey, Committed(dereferencedValue))
strongMap.cache.put(strongKey, Committed(dereferencedValue))
}
}
strongMap.removePendingKey(strongKey, tx)
@ -272,7 +271,7 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
private fun loadAsWriter(): T {
val _value = writerValueLoader.get()()
if (writerValueLoader.get() == _writerValueLoader) {
writerValueLoader.set({ _value })
writerValueLoader.set { _value }
}
return _value
}
@ -282,7 +281,7 @@ abstract class AppendOnlyPersistentMapBase<K, V, E, out EK>(
private fun loadAsReader(): T? {
val _value = readerValueLoader.get()()
if (readerValueLoader.get() == _readerValueLoader) {
readerValueLoader.set({ _value })
readerValueLoader.set { _value }
}
return _value
}
@ -320,7 +319,7 @@ open class AppendOnlyPersistentMap<K, V, E, out EK>(
toPersistentEntity,
persistentEntityClass) {
//TODO determine cacheBound based on entity class later or with node config allowing tuning, or using some heuristic based on heap size
override val cache = NonInvalidatingCache<K, Transactional<V>>(
override val cache = NonInvalidatingCache(
bound = cacheBound,
loadFunction = { key: K ->
// This gets called if a value is read and the cache has no Transactional for this key yet.
@ -331,10 +330,10 @@ open class AppendOnlyPersistentMap<K, V, E, out EK>(
// If someone is writing (but not us)
// For those not writing, the value cannot be seen.
// For those writing, they need to re-load the value from the database (which their database transaction CAN see).
Transactional.InFlight<K, V>(this, key, { null }, { loadValue(key)!! })
Transactional.InFlight(this, key, { null }, { loadValue(key)!! })
} else {
// If no one is writing, then the value does not exist.
Transactional.Missing<V>()
Transactional.Missing()
}
} else {
// A value was found
@ -342,10 +341,10 @@ open class AppendOnlyPersistentMap<K, V, E, out EK>(
// If we are writing, it might not be globally visible, and was evicted from the cache.
// For those not writing, they need to check the database again.
// For those writing, they can see the value found.
Transactional.InFlight<K, V>(this, key, { loadValue(key) }, { value })
Transactional.InFlight(this, key, { loadValue(key) }, { value })
} else {
// If no one is writing, then make it globally visible.
Transactional.Committed<V>(value)
Transactional.Committed(value)
}
}
})
@ -364,26 +363,22 @@ class WeightBasedAppendOnlyPersistentMap<K, V, E, out EK>(
fromPersistentEntity,
toPersistentEntity,
persistentEntityClass) {
override val cache = NonInvalidatingWeightBasedCache<K, Transactional<V>>(
override val cache = NonInvalidatingWeightBasedCache(
maxWeight = maxWeight,
weigher = object : Weigher<K, Transactional<V>> {
override fun weigh(key: K, value: Transactional<V>): Int {
return weighingFunc(key, value)
}
},
weigher = Weigher { key, value -> weighingFunc(key, value) },
loadFunction = { key: K ->
val value: V? = loadValue(key)
if (value == null) {
if (anyoneWriting(key)) {
Transactional.InFlight<K, V>(this, key, { null }, { loadValue(key)!! })
Transactional.InFlight(this, key, { null }, { loadValue(key)!! })
} else {
Transactional.Missing<V>()
Transactional.Missing()
}
} else {
if (weAreWriting(key)) {
Transactional.InFlight<K, V>(this, key, { loadValue(key) }, { value })
Transactional.InFlight(this, key, { loadValue(key) }, { value })
} else {
Transactional.Committed<V>(value)
Transactional.Committed(value)
}
}
})

View File

@ -46,9 +46,6 @@ import org.junit.Rule;
import org.junit.Test;
import rx.Observable;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.cert.CertificateException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -80,7 +77,7 @@ public class VaultQueryJavaTests {
private CordaPersistence database;
@Before
public void setUp() throws CertificateException, InvalidAlgorithmParameterException {
public void setUp() {
List<String> cordappPackages = asList(
"net.corda.testing.internal.vault",
"net.corda.finance.contracts.asset",
@ -101,14 +98,10 @@ public class VaultQueryJavaTests {
}
@After
public void cleanUp() throws IOException {
public void cleanUp() {
database.close();
}
/**
* Sample Vault Query API tests
*/
/**
* Static queryBy() tests
*/
@ -119,6 +112,7 @@ public class VaultQueryJavaTests {
FieldInfo currency = getField("currency", SampleCashSchemaV2.PersistentCashState.class);
CriteriaExpression.AggregateFunctionExpression<Object, Boolean> expression = sum(quantity, singletonList(currency), Sort.Direction.ASC);
@SuppressWarnings("unchecked")
VaultCustomQueryCriteria<SampleCashSchemaV2.PersistentCashState> criteria = new VaultCustomQueryCriteria(expression, Vault.StateStatus.UNCONSUMED, null);
database.transaction(tx -> vaultService.queryBy(FungibleAsset.class, criteria));
@ -131,13 +125,14 @@ public class VaultQueryJavaTests {
FieldInfo stateRef = getField("stateRef", SampleCashSchemaV2.PersistentCashState.class);
CriteriaExpression.AggregateFunctionExpression<Object, Boolean> expression = sum(quantity, asList(currency, stateRef), Sort.Direction.ASC);
@SuppressWarnings("unchecked")
VaultCustomQueryCriteria<SampleCashSchemaV2.PersistentCashState> criteria = new VaultCustomQueryCriteria(expression, Vault.StateStatus.UNCONSUMED, null);
database.transaction(tx -> vaultService.queryBy(FungibleAsset.class, criteria));
}
@Test
public void unconsumedLinearStates() throws VaultQueryException {
public void unconsumedLinearStates() {
database.transaction(tx -> {
vaultFiller.fillWithSomeTestLinearStates(3);
return tx;
@ -209,7 +204,7 @@ public class VaultQueryJavaTests {
}
@Test
public void consumedDealStatesPagedSorted() throws VaultQueryException {
public void consumedDealStatesPagedSorted() {
List<String> dealIds = asList("123", "456", "789");
@SuppressWarnings("unchecked")
Triple<StateAndRef<LinearState>, UniqueIdentifier, Vault<DealState>> ids =
@ -320,7 +315,6 @@ public class VaultQueryJavaTests {
DataFeed<Vault.Page<ContractState>, Vault.Update<ContractState>> results = vaultService.trackBy(ContractState.class, criteria);
Vault.Page<ContractState> snapshot = results.getSnapshot();
Observable<Vault.Update<ContractState>> updates = results.getUpdates();
// DOCEND VaultJavaQueryExample4
assertThat(snapshot.getStates()).hasSize(3);
@ -374,7 +368,6 @@ public class VaultQueryJavaTests {
@SuppressWarnings("unchecked")
public void aggregateFunctionsWithoutGroupClause() {
database.transaction(tx -> {
Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD"));
Amount<Currency> dollars200 = new Amount<>(200, Currency.getInstance("USD"));
Amount<Currency> dollars300 = new Amount<>(300, Currency.getInstance("USD"));
@ -420,7 +413,6 @@ public class VaultQueryJavaTests {
@SuppressWarnings("unchecked")
public void aggregateFunctionsWithSingleGroupClause() {
database.transaction(tx -> {
Amount<Currency> dollars100 = new Amount<>(100, Currency.getInstance("USD"));
Amount<Currency> dollars200 = new Amount<>(200, Currency.getInstance("USD"));
Amount<Currency> dollars300 = new Amount<>(300, Currency.getInstance("USD"));

View File

@ -34,7 +34,6 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.finance.DOLLARS
import net.corda.finance.GBP
import net.corda.finance.USD
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
@ -167,6 +166,7 @@ class CordaRPCOpsImplTest {
@Test
fun `issue and move`() {
@Suppress("DEPRECATION")
withPermissions(invokeRpc(CordaRPCOps::stateMachinesFeed),
invokeRpc(CordaRPCOps::internalVerifiedTransactionsFeed),
invokeRpc("vaultTrackBy"),
@ -178,11 +178,7 @@ class CordaRPCOpsImplTest {
vaultTrackCash = rpc.vaultTrackBy<Cash.State>().updates
}
val result = rpc.startFlow(::CashIssueFlow,
100.DOLLARS,
OpaqueBytes(ByteArray(1, { 1 })),
notary
)
val result = rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), notary)
mockNet.runNetwork()
@ -257,7 +253,7 @@ class CordaRPCOpsImplTest {
fun `cash command by user not permissioned for cash`() {
withoutAnyPermissions {
assertThatExceptionOfType(PermissionException::class.java).isThrownBy {
rpc.startFlow(::CashIssueFlow, Amount(100, USD), OpaqueBytes(ByteArray(1, { 1 })), notary)
rpc.startFlow(::CashIssueFlow, 100.DOLLARS, OpaqueBytes.of(1), notary)
}
}
}

View File

@ -70,7 +70,7 @@ class NodeTest {
fun `generateAndSaveNodeInfo works`() {
val configuration = createConfig(ALICE_NAME)
val info = VersionInfo(789, "3.0", "SNAPSHOT", "R3")
configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use { database ->
configureDatabase(configuration.dataSourceProperties, configuration.database, { null }, { null }).use {
val node = Node(configuration, info, initialiseSerialization = false)
assertEquals(node.generateNodeInfo(), node.generateNodeInfo()) // Node info doesn't change (including the serial)
}

View File

@ -19,7 +19,6 @@ import org.apache.activemq.artemis.api.core.SimpleString
import org.junit.Test
import rx.Notification
import rx.Observable
import rx.Subscription
import rx.subjects.UnicastSubject
import java.time.Instant
import java.util.*
@ -38,7 +37,7 @@ class RoundTripObservableSerializerTests {
.maximumSize(100)
.build()
subMap.put(id, ObservableSubscription(mock<Subscription>()))
subMap.put(id, ObservableSubscription(mock()))
return subMap
}
@ -48,7 +47,7 @@ class RoundTripObservableSerializerTests {
})
private fun createRpcObservableMap(): Cache<Trace.InvocationId, UnicastSubject<Notification<*>>> {
val onObservableRemove = RemovalListener<Trace.InvocationId, UnicastSubject<Notification<*>>> { key, value, cause ->
val onObservableRemove = RemovalListener<Trace.InvocationId, UnicastSubject<Notification<*>>> { key, _, _ ->
val observableId = key!!
observablesToReap.locked { observables.add(observableId) }
@ -85,7 +84,7 @@ class RoundTripObservableSerializerTests {
// What we're actually going to serialize then deserialize
val obs = Observable.create<Int>({ 12 })
val obs = Observable.create<Int> { Math.random() }
val serverSerializationContext = RpcServerObservableSerializer.createContext(
serializationContext, serverObservableContext)
@ -95,6 +94,6 @@ class RoundTripObservableSerializerTests {
val blob = SerializationOutput(serverSerializer).serialize(obs, serverSerializationContext)
val obs2 = DeserializationInput(clientSerializer).deserialize(blob, clientSerializationContext)
DeserializationInput(clientSerializer).deserialize(blob, clientSerializationContext)
}
}
}

View File

@ -8,13 +8,12 @@ import net.corda.node.internal.serialization.testutils.TestObservableContext
import net.corda.node.internal.serialization.testutils.serializationContext
import net.corda.node.serialization.amqp.RpcServerObservableSerializer
import net.corda.node.services.messaging.ObservableSubscription
import net.corda.serialization.internal.AllWhitelist
import net.corda.serialization.internal.amqp.SerializationOutput
import net.corda.serialization.internal.amqp.SerializerFactory
import net.corda.serialization.internal.AllWhitelist
import org.apache.activemq.artemis.api.core.SimpleString
import org.junit.Test
import rx.Observable
import rx.Subscription
import java.time.Instant
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
@ -28,7 +27,7 @@ class RpcServerObservableSerializerTests {
.maximumSize(100)
.build()
subMap.put(Trace.InvocationId("test1", Instant.now()), ObservableSubscription(mock<Subscription>()))
subMap.put(Trace.InvocationId("test1", Instant.now()), ObservableSubscription(mock()))
return subMap
}
@ -72,7 +71,7 @@ class RpcServerObservableSerializerTests {
register(RpcServerObservableSerializer())
}
val obs = Observable.create<Int>({ 12 })
val obs = Observable.create<Int> { Math.random() }
val newContext = RpcServerObservableSerializer.createContext(serializationContext, observable)
try {

View File

@ -10,22 +10,8 @@
package net.corda.node.services.events
import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.argForWhich
import com.nhaarman.mockito_kotlin.doAnswer
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.eq
import com.nhaarman.mockito_kotlin.same
import com.nhaarman.mockito_kotlin.timeout
import com.nhaarman.mockito_kotlin.verify
import com.nhaarman.mockito_kotlin.verifyNoMoreInteractions
import com.nhaarman.mockito_kotlin.whenever
import junit.framework.Assert.fail
import net.corda.core.contracts.SchedulableState
import net.corda.core.contracts.ScheduledActivity
import net.corda.core.contracts.ScheduledStateRef
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState
import com.nhaarman.mockito_kotlin.*
import net.corda.core.contracts.*
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowLogicRef
@ -46,11 +32,7 @@ import net.corda.testing.internal.rigorousMock
import net.corda.testing.internal.spectator
import net.corda.testing.node.MockServices
import net.corda.testing.node.TestClock
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.*
import org.junit.rules.TestWatcher
import org.junit.runner.Description
import org.slf4j.Logger
@ -61,6 +43,7 @@ import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.TimeUnit
import kotlin.test.assertEquals
import kotlin.test.fail
open class NodeSchedulerServiceTestBase {
protected class Event(time: Instant) {
@ -97,7 +80,7 @@ open class NodeSchedulerServiceTestBase {
doLookup(transactionStates).whenever(it).loadState(any())
}
protected val traces = Collections.synchronizedList(mutableListOf<ScheduledStateRef>())
private val traces = Collections.synchronizedList(mutableListOf<ScheduledStateRef>())
@Before
fun resetTraces() {
@ -108,7 +91,7 @@ open class NodeSchedulerServiceTestBase {
doReturn(false).whenever(it).isTraceEnabled
doAnswer {
traces += it.getArgument<ScheduledStateRef>(1)
}.whenever(it).trace(eq(NodeSchedulerService.schedulingAsNextFormat), any<Object>())
}.whenever(it).trace(eq(NodeSchedulerService.schedulingAsNextFormat), any<Any>())
}
protected fun assertWaitingFor(ssr: ScheduledStateRef) {
@ -283,7 +266,7 @@ class NodeSchedulerServiceTest : NodeSchedulerServiceTestBase() {
class NodeSchedulerPersistenceTest : NodeSchedulerServiceTestBase() {
private val databaseConfig: DatabaseConfig = DatabaseConfig()
fun createScheduler(db: CordaPersistence): NodeSchedulerService {
private fun createScheduler(db: CordaPersistence): NodeSchedulerService {
return NodeSchedulerService(
testClock,
db,
@ -295,7 +278,7 @@ class NodeSchedulerPersistenceTest : NodeSchedulerServiceTestBase() {
log = log).apply { start() }
}
fun transactionStateMock(logicRef: FlowLogicRef, time: Instant): TransactionState<*> {
private fun transactionStateMock(logicRef: FlowLogicRef, time: Instant): TransactionState<*> {
return rigorousMock<TransactionState<SchedulableState>>().also {
doReturn(rigorousMock<SchedulableState>().also {
doReturn(ScheduledActivity(logicRef, time)).whenever(it).nextScheduledActivity(any(), any())

View File

@ -81,7 +81,6 @@ class ArtemisMessagingTest {
doReturn("cordacadevpass").whenever(it).keyStorePassword
doReturn(NetworkHostAndPort("0.0.0.0", serverPort)).whenever(it).p2pAddress
doReturn(null).whenever(it).jmxMonitoringHttpPort
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000))).whenever(it).enterpriseConfiguration
doReturn(FlowTimeoutConfiguration(5.seconds, 3, backoffBase = 1.0)).whenever(it).flowTimeout
}

View File

@ -200,7 +200,7 @@ class DBCheckpointStorageTests {
override fun call() {}
}
val frozenLogic = logic.serialize(context = SerializationDefaults.CHECKPOINT_CONTEXT)
val checkpoint = Checkpoint.create(InvocationContext.shell(), FlowStart.Explicit, logic.javaClass, frozenLogic, ALICE, "", SubFlowVersion.CoreFlow(version)).getOrThrow()
val checkpoint = Checkpoint.create(InvocationContext.shell(), FlowStart.Explicit, logic.javaClass, frozenLogic, ALICE, SubFlowVersion.CoreFlow(version)).getOrThrow()
return id to checkpoint.serialize(context = SerializationDefaults.CHECKPOINT_CONTEXT)
}

View File

@ -17,18 +17,14 @@ import net.corda.core.crypto.SignatureMetadata
import net.corda.core.crypto.TransactionSignature
import net.corda.core.toFuture
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.WireTransaction
import net.corda.node.internal.configureDatabase
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.TestIdentity
import net.corda.testing.core.dummyCommand
import net.corda.testing.core.*
import net.corda.testing.internal.LogHelper
import net.corda.testing.internal.createWireTransaction
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
@ -176,7 +172,7 @@ class DBTransactionStorageTests {
}
private fun newTransaction(): SignedTransaction {
val wtx = WireTransaction(
val wtx = createWireTransaction(
inputs = listOf(StateRef(SecureHash.randomSHA256(), 0)),
attachments = emptyList(),
outputs = emptyList(),
@ -184,6 +180,9 @@ class DBTransactionStorageTests {
notary = DUMMY_NOTARY,
timeWindow = null
)
return SignedTransaction(wtx, listOf(TransactionSignature(ByteArray(1), ALICE_PUBKEY, SignatureMetadata(1, Crypto.findSignatureScheme(ALICE_PUBKEY).schemeNumberID))))
return SignedTransaction(
wtx,
listOf(TransactionSignature(ByteArray(1), ALICE_PUBKEY, SignatureMetadata(1, Crypto.findSignatureScheme(ALICE_PUBKEY).schemeNumberID)))
)
}
}

View File

@ -14,7 +14,6 @@ import com.nhaarman.mockito_kotlin.*
import net.corda.core.contracts.Amount
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.generateKeyPair
import net.corda.core.identity.AbstractParty
@ -39,13 +38,13 @@ import net.corda.finance.schemas.SampleCashSchemaV3
import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.utils.sumCash
import net.corda.node.internal.configureDatabase
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.schema.ContractStateAndRef
import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.vault.VaultSchemaV1
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.vault.NodeVaultService
import net.corda.node.services.vault.VaultSchemaV1
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.nodeapi.internal.persistence.HibernateConfiguration
@ -85,18 +84,18 @@ class HibernateConfigurationTest {
val testSerialization = SerializationEnvironmentRule()
lateinit var services: MockServices
private lateinit var vaultFiller: VaultFiller
lateinit var bankServices: MockServices
lateinit var issuerServices: MockServices
lateinit var notaryServices: MockServices
private lateinit var bankServices: MockServices
private lateinit var issuerServices: MockServices
private lateinit var notaryServices: MockServices
lateinit var database: CordaPersistence
val vault: VaultService get() = services.vaultService
// Hibernate configuration objects
lateinit var hibernateConfig: HibernateConfiguration
lateinit var hibernatePersister: HibernateObserver
lateinit var sessionFactory: SessionFactory
lateinit var entityManager: EntityManager
lateinit var criteriaBuilder: CriteriaBuilder
private lateinit var hibernatePersister: HibernateObserver
private lateinit var sessionFactory: SessionFactory
private lateinit var entityManager: EntityManager
private lateinit var criteriaBuilder: CriteriaBuilder
// Identities used
private lateinit var identity: Party
@ -104,7 +103,7 @@ class HibernateConfigurationTest {
private lateinit var notary: Party
// test States
lateinit var cashStates: List<StateAndRef<Cash.State>>
private lateinit var cashStates: List<StateAndRef<Cash.State>>
@Before
fun setUp() {
@ -701,7 +700,7 @@ class HibernateConfigurationTest {
val queryResults = entityManager.createQuery(criteriaQuery).resultList
queryResults.forEach {
val cashState = (services.loadState(toStateRef(it.stateRef!!)) as TransactionState<Cash.State>).data
val cashState = services.loadState(toStateRef(it.stateRef!!)).data as Cash.State
println("${it.stateRef} with owner: ${cashState.owner.owningKey.toBase58String()}")
}
@ -785,7 +784,7 @@ class HibernateConfigurationTest {
// execute query
val queryResults = entityManager.createQuery(criteriaQuery).resultList
queryResults.forEach {
val cashState = (services.loadState(toStateRef(it.stateRef!!)) as TransactionState<Cash.State>).data
val cashState = services.loadState(toStateRef(it.stateRef!!)).data as Cash.State
println("${it.stateRef} with owner ${cashState.owner.owningKey.toBase58String()} and participants ${cashState.participants.map { it.owningKey.toBase58String() }}")
}
@ -924,6 +923,6 @@ class HibernateConfigurationTest {
}
private fun toStateRef(pStateRef: PersistentStateRef): StateRef {
return StateRef(SecureHash.parse(pStateRef.txId!!), pStateRef.index!!)
return StateRef(SecureHash.parse(pStateRef.txId), pStateRef.index)
}
}
}

View File

@ -15,11 +15,7 @@ import com.google.common.jimfs.Configuration
import com.google.common.jimfs.Jimfs
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.sha256
import net.corda.core.internal.read
import net.corda.core.internal.readAll
import net.corda.core.internal.readFully
import net.corda.core.internal.write
import net.corda.core.internal.writeLines
import net.corda.core.internal.*
import net.corda.core.node.services.vault.AttachmentQueryCriteria
import net.corda.core.node.services.vault.AttachmentSort
import net.corda.core.node.services.vault.Builder
@ -69,7 +65,7 @@ class NodeAttachmentStorageTest {
fun `insert and retrieve`() {
val (testJar, expectedHash) = makeTestJar()
val id = testJar.read { storage.importAttachment(it) }
val id = testJar.read { storage.importAttachment(it, "test", null) }
assertEquals(expectedHash, id)
assertNull(storage.openAttachment(SecureHash.randomSHA256()))
@ -94,7 +90,7 @@ class NodeAttachmentStorageTest {
val (testJar, expectedHash) = makeTestJar()
val (jarB, hashB) = makeTestJar(listOf(Pair("file", "content")))
val id = testJar.read { storage.importAttachment(it) }
val id = testJar.read { storage.importAttachment(it, "test", null) }
assertEquals(expectedHash, id)
@ -109,7 +105,7 @@ class NodeAttachmentStorageTest {
stream.close()
val idB = jarB.read { storage.importAttachment(it) }
val idB = jarB.read { storage.importAttachment(it, "test", null) }
assertEquals(hashB, idB)
storage.openAttachment(id)!!.openAsJAR().use {
@ -129,6 +125,7 @@ class NodeAttachmentStorageTest {
val (jarB, hashB) = makeTestJar(listOf(Pair("file", "content")))
val (jarC, hashC) = makeTestJar(listOf(Pair("magic_file", "magic_content_puff")))
@Suppress("DEPRECATION")
jarA.read { storage.importAttachment(it) }
jarB.read { storage.importAttachment(it, "uploaderB", "fileB.zip") }
jarC.read { storage.importAttachment(it, "uploaderC", "fileC.zip") }
@ -196,11 +193,11 @@ class NodeAttachmentStorageTest {
fun `duplicates not allowed`() {
val (testJar, _) = makeTestJar()
testJar.read {
storage.importAttachment(it)
storage.importAttachment(it, "test", null)
}
assertFailsWith<FileAlreadyExistsException> {
testJar.read {
storage.importAttachment(it)
storage.importAttachment(it, "test", null)
}
}
}
@ -209,7 +206,7 @@ class NodeAttachmentStorageTest {
fun `corrupt entry throws exception`() {
val (testJar, _) = makeTestJar()
val id = database.transaction {
val id = testJar.read { storage.importAttachment(it) }
val id = testJar.read { storage.importAttachment(it, "test", null) }
// Corrupt the file in the store.
val bytes = testJar.readAll()
@ -237,7 +234,7 @@ class NodeAttachmentStorageTest {
path.writeLines(listOf("Hey", "there!"))
path.read {
assertFailsWith<IllegalArgumentException>("either empty or not a JAR") {
storage.importAttachment(it)
storage.importAttachment(it, "test", null)
}
}
}

View File

@ -246,7 +246,6 @@ class RunOnceServiceTest {
assertEquals('X', result.id)
assertEquals("machine1", result.machineName)
assertEquals("123", result.pid)
assertTrue(result.timestamp is LocalDateTime)
return result
}
@ -256,7 +255,6 @@ class RunOnceServiceTest {
assertEquals('X', result.id)
assertEquals("machine2", result.machineName)
assertEquals("789", result.pid)
assertTrue(result.timestamp is LocalDateTime)
return result
}
}

View File

@ -25,6 +25,7 @@ import net.corda.testing.node.MockServices
import org.apache.commons.io.FileUtils
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import java.lang.reflect.Method
import java.math.BigInteger
import java.net.URL
import javax.persistence.*
@ -32,7 +33,6 @@ import java.net.URLClassLoader
import java.nio.file.Files
import java.nio.file.Path
class SchemaMigrationTest {
@Test
@ -82,7 +82,7 @@ class SchemaMigrationTest {
// check that the file was picked up
val nrOfChangesOnDiscoveredFile = db.dataSource.connection.use {
it.createStatement().executeQuery("select count(*) from DATABASECHANGELOG where filename ='migration/${fileName}'").use { rs ->
it.createStatement().executeQuery("select count(*) from DATABASECHANGELOG where filename ='migration/$fileName'").use { rs ->
rs.next()
rs.getInt(1)
}
@ -102,9 +102,11 @@ class SchemaMigrationTest {
}
//hacky way to add a folder to the classpath
fun addToClassPath(file: Path) = URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java).apply {
isAccessible = true
invoke(ClassLoader.getSystemClassLoader(), file.toFile().toURL())
private fun addToClassPath(file: Path): Method {
return URLClassLoader::class.java.getDeclaredMethod("addURL", URL::class.java).apply {
isAccessible = true
invoke(ClassLoader.getSystemClassLoader(), file.toUri().toURL())
}
}
object DummyTestSchema
@ -116,9 +118,9 @@ class SchemaMigrationTest {
@ElementCollection
@Column(name = "participants")
@CollectionTable(name = "dummy_test_states_parts", joinColumns = arrayOf(
@CollectionTable(name = "dummy_test_states_parts", joinColumns = [
JoinColumn(name = "output_index", referencedColumnName = "output_index"),
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")))
JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id")])
override var participants: MutableSet<AbstractParty>? = null,
@Transient

View File

@ -15,6 +15,7 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.flows.*
import net.corda.core.identity.Party
import net.corda.core.internal.InputStreamAndHash
import net.corda.core.node.services.AttachmentId
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.testing.common.internal.testNetworkParameters
@ -31,6 +32,7 @@ import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
import java.io.InputStream
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@ -67,10 +69,10 @@ class MaxTransactionSizeTests {
val bigFile3 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 2)
val bigFile4 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 3)
val flow = aliceNode.transaction {
val hash1 = aliceNode.services.attachments.importAttachment(bigFile1.inputStream)
val hash2 = aliceNode.services.attachments.importAttachment(bigFile2.inputStream)
val hash3 = aliceNode.services.attachments.importAttachment(bigFile3.inputStream)
val hash4 = aliceNode.services.attachments.importAttachment(bigFile4.inputStream)
val hash1 = aliceNode.importAttachment(bigFile1.inputStream)
val hash2 = aliceNode.importAttachment(bigFile2.inputStream)
val hash3 = aliceNode.importAttachment(bigFile3.inputStream)
val hash4 = aliceNode.importAttachment(bigFile4.inputStream)
assertEquals(hash1, bigFile1.sha256)
SendLargeTransactionFlow(notary, bob, hash1, hash2, hash3, hash4)
}
@ -90,10 +92,10 @@ class MaxTransactionSizeTests {
val bigFile3 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 2)
val bigFile4 = InputStreamAndHash.createInMemoryTestZip(1024 * 1024, 3)
val flow = aliceNode.transaction {
val hash1 = aliceNode.services.attachments.importAttachment(bigFile1.inputStream)
val hash2 = aliceNode.services.attachments.importAttachment(bigFile2.inputStream)
val hash3 = aliceNode.services.attachments.importAttachment(bigFile3.inputStream)
val hash4 = aliceNode.services.attachments.importAttachment(bigFile4.inputStream)
val hash1 = aliceNode.importAttachment(bigFile1.inputStream)
val hash2 = aliceNode.importAttachment(bigFile2.inputStream)
val hash3 = aliceNode.importAttachment(bigFile3.inputStream)
val hash4 = aliceNode.importAttachment(bigFile4.inputStream)
assertEquals(hash1, bigFile1.sha256)
SendLargeTransactionFlow(notary, bob, hash1, hash2, hash3, hash4, verify = false)
}
@ -104,6 +106,10 @@ class MaxTransactionSizeTests {
}
}
private fun StartedMockNode.importAttachment(inputStream: InputStream): AttachmentId {
return services.attachments.importAttachment(inputStream, "test", null)
}
@StartableByRPC
@InitiatingFlow
class SendLargeTransactionFlow(private val notary: Party,

View File

@ -51,7 +51,6 @@ import org.junit.Test
import org.junit.rules.ExpectedException
import org.junit.rules.ExternalResource
import java.time.Duration
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneOffset
import java.time.temporal.ChronoUnit
@ -113,7 +112,7 @@ open class VaultQueryTestRule : ExternalResource(), VaultQueryParties {
override val bob = TestIdentity(BOB_NAME, 80)
override val cashNotary = TestIdentity(CordaX500Name("Cash Notary Service", "Zurich", "CH"), 21)
override val charlie = TestIdentity(CHARLIE_NAME, 90)
override val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10)
final override val dummyCashIssuer = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10)
override val DUMMY_CASH_ISSUER = dummyCashIssuer.ref(1)
override val dummyNotary = TestIdentity(DUMMY_NOTARY_NAME, 20)
override val DUMMY_OBLIGATION_ISSUER = TestIdentity(CordaX500Name("Snake Oil Issuer", "London", "GB"), 10).party
@ -143,7 +142,7 @@ open class VaultQueryTestRule : ExternalResource(), VaultQueryParties {
cordappPackages,
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity),
megaCorp,
moreKeys = DUMMY_NOTARY_KEY)
moreKeys = *arrayOf(DUMMY_NOTARY_KEY))
database = databaseAndServices.first
services = databaseAndServices.second
vaultFiller = VaultFiller(services, dummyNotary)
@ -161,7 +160,7 @@ open class VaultQueryTestRule : ExternalResource(), VaultQueryParties {
}
}
class VaultQueryRollbackRule(val vaultQueryParties: VaultQueryParties) : ExternalResource() {
class VaultQueryRollbackRule(private val vaultQueryParties: VaultQueryParties) : ExternalResource() {
lateinit var transaction: DatabaseTransaction

View File

@ -75,7 +75,7 @@ class VaultWithCashTest {
private val servicesKey = generateKeyPair()
lateinit var services: MockServices
private lateinit var vaultFiller: VaultFiller
lateinit var issuerServices: MockServices
private lateinit var issuerServices: MockServices
val vaultService: VaultService get() = services.vaultService
lateinit var database: CordaPersistence
private lateinit var notaryServices: MockServices
@ -88,7 +88,7 @@ class VaultWithCashTest {
cordappPackages,
makeTestIdentityService(MEGA_CORP_IDENTITY, MINI_CORP_IDENTITY, dummyCashIssuer.identity, dummyNotary.identity),
TestIdentity(MEGA_CORP.name, servicesKey),
moreKeys = dummyNotary.keyPair)
moreKeys = *arrayOf(dummyNotary.keyPair))
database = databaseAndServices.first
services = databaseAndServices.second
vaultFiller = VaultFiller(services, dummyNotary)
@ -141,7 +141,7 @@ class VaultWithCashTest {
database.transaction {
// A tx that spends our money.
val spendTXBuilder = TransactionBuilder(DUMMY_NOTARY)
Cash.generateSpend(services, spendTXBuilder, 80.DOLLARS, BOB)
Cash.generateSpend(services, spendTXBuilder, 80.DOLLARS, services.myInfo.legalIdentitiesAndCerts.single(), BOB)
val spendPTX = services.signInitialTransaction(spendTXBuilder, freshKey)
notaryServices.addSignature(spendPTX)
}
@ -189,7 +189,7 @@ class VaultWithCashTest {
val first = backgroundExecutor.fork {
database.transaction {
val txn1Builder = TransactionBuilder(DUMMY_NOTARY)
Cash.generateSpend(services, txn1Builder, 60.DOLLARS, BOB)
Cash.generateSpend(services, txn1Builder, 60.DOLLARS, services.myInfo.legalIdentitiesAndCerts.single(), BOB)
val ptxn1 = notaryServices.signInitialTransaction(txn1Builder)
val txn1 = services.addSignature(ptxn1, freshKey)
println("txn1: ${txn1.id} spent ${((txn1.tx.outputs[0].data) as Cash.State).amount}")
@ -220,7 +220,7 @@ class VaultWithCashTest {
val second = backgroundExecutor.fork {
database.transaction {
val txn2Builder = TransactionBuilder(DUMMY_NOTARY)
Cash.generateSpend(services, txn2Builder, 80.DOLLARS, BOB)
Cash.generateSpend(services, txn2Builder, 80.DOLLARS, services.myInfo.legalIdentitiesAndCerts.single(), BOB)
val ptxn2 = notaryServices.signInitialTransaction(txn2Builder)
val txn2 = services.addSignature(ptxn2, freshKey)
println("txn2: ${txn2.id} spent ${((txn2.tx.outputs[0].data) as Cash.State).amount}")
@ -344,7 +344,7 @@ class VaultWithCashTest {
database.transaction {
// A tx that spends our money.
val spendTXBuilder = TransactionBuilder(DUMMY_NOTARY)
Cash.generateSpend(services, spendTXBuilder, 80.DOLLARS, BOB)
Cash.generateSpend(services, spendTXBuilder, 80.DOLLARS, services.myInfo.legalIdentitiesAndCerts.single(), BOB)
val spendPTX = notaryServices.signInitialTransaction(spendTXBuilder)
val spendTX = services.addSignature(spendPTX, freshKey)
services.recordTransactions(spendTX)

View File

@ -23,7 +23,6 @@ import rx.Observable
import rx.subjects.PublishSubject
import java.io.Closeable
import java.util.*
import kotlin.test.fail
class ObservablesTests {
private fun isInDatabaseTransaction() = contextTransactionOrNull != null
@ -68,7 +67,7 @@ class ObservablesTests {
assertThat(secondEvent.get()).isEqualTo(0 to false)
}
class TestException : Exception("Synthetic exception for tests") {}
class TestException : Exception("Synthetic exception for tests")
@Test
fun `bufferUntilDatabaseCommit swallows if transaction rolled back`() {
@ -93,7 +92,6 @@ class ObservablesTests {
assertThat(secondEvent.isDone).isFalse()
throw TestException()
}
fail("Should not have successfully completed transaction")
} catch (e: TestException) {
}
assertThat(secondEvent.isDone).isFalse()
@ -125,7 +123,6 @@ class ObservablesTests {
assertThat(secondEvent.isDone).isFalse()
throw TestException()
}
fail("Should not have successfully completed transaction")
} catch (e: TestException) {
}
assertThat(secondEvent.isDone).isTrue()

View File

@ -40,7 +40,6 @@ class LinearStateBatchNotariseContract : Contract {
}
override fun verify(tx: LedgerTransaction) {
val command = tx.commands.requireSingleCommand<Commands>()
val timeWindow: TimeWindow? = tx.timeWindow
tx.commands.requireSingleCommand<Commands>()
}
}

View File

@ -230,27 +230,6 @@ abstract class OnLedgerAsset<T : Any, C : CommandData, S : FungibleAsset<T>> : C
return Pair(gathered, gatheredAmount)
}
/**
* Generate an transaction exiting fungible assets from the ledger.
*
* @param tx transaction builder to add states and commands to.
* @param amountIssued the amount to be exited, represented as a quantity of issued currency.
* @param assetStates the asset states to take funds from. No checks are done about ownership of these states, it is
* the responsibility of the caller to check that they do not attempt to exit funds held by others.
* @return the public keys which must sign the transaction for it to be valid.
*/
@Throws(InsufficientBalanceException::class)
@JvmStatic
@Deprecated("Replaced with generateExit() which takes in a party to pay change to")
fun <S : FungibleAsset<T>, T: Any> generateExit(tx: TransactionBuilder, amountIssued: Amount<Issued<T>>,
assetStates: List<StateAndRef<S>>,
deriveState: (TransactionState<S>, Amount<Issued<T>>, AbstractParty) -> TransactionState<S>,
generateMoveCommand: () -> CommandData,
generateExitCommand: (Amount<Issued<T>>) -> CommandData): Set<PublicKey> {
val owner = assetStates.map { it.state.data.owner }.toSet().firstOrNull() ?: throw InsufficientBalanceException(amountIssued)
return generateExit(tx, amountIssued, assetStates, owner, deriveState, generateMoveCommand, generateExitCommand)
}
/**
* Generate an transaction exiting fungible assets from the ledger.
*
@ -323,31 +302,6 @@ abstract class OnLedgerAsset<T : Any, C : CommandData, S : FungibleAsset<T>> : C
abstract fun extractCommands(commands: Collection<CommandWithParties<CommandData>>): Collection<CommandWithParties<C>>
/**
* Generate an transaction exiting assets from the ledger.
*
* @param tx transaction builder to add states and commands to.
* @param amountIssued the amount to be exited, represented as a quantity of issued currency.
* @param assetStates the asset states to take funds from. No checks are done about ownership of these states, it is
* the responsibility of the caller to check that they do not exit funds held by others.
* @param payChangeTo party to pay any change to; this is normally a confidential identity of the calling
* party.
* @return the public keys which must sign the transaction for it to be valid.
*/
@Throws(InsufficientBalanceException::class)
@Deprecated("Replaced with generateExit() which takes in a party to pay change to")
fun generateExit(tx: TransactionBuilder, amountIssued: Amount<Issued<T>>,
assetStates: List<StateAndRef<S>>): Set<PublicKey> {
return generateExit(
tx,
amountIssued,
assetStates,
deriveState = { state, amount, owner -> deriveState(state, amount, owner) },
generateMoveCommand = { -> generateMoveCommand() },
generateExitCommand = { amount -> generateExitCommand(amount) }
)
}
/**
* Generate an transaction exiting assets from the ledger.
*
@ -367,8 +321,8 @@ abstract class OnLedgerAsset<T : Any, C : CommandData, S : FungibleAsset<T>> : C
assetStates,
payChangeTo,
deriveState = { state, amount, owner -> deriveState(state, amount, owner) },
generateMoveCommand = { -> generateMoveCommand() },
generateExitCommand = { amount -> generateExitCommand(amount) }
generateMoveCommand = { generateMoveCommand() },
generateExitCommand = { generateExitCommand(it) }
)
}

View File

@ -14,22 +14,18 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.Amount
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
import net.corda.core.contracts.TransactionState
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party
import net.corda.core.node.ServiceHub
import net.corda.core.node.services.StatesNotAvailableException
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.deserialize
import net.corda.core.utilities.*
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import net.corda.core.internal.uncheckedCast
import java.sql.*
import java.util.*
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
/**
* Pluggable interface to allow for different cash selection provider implementations
@ -41,17 +37,17 @@ import kotlin.concurrent.withLock
abstract class AbstractCashSelection(private val maxRetries: Int = 8, private val retrySleep: Int = 100,
private val retryCap: Int = 2000) {
companion object {
val instance = AtomicReference<AbstractCashSelection>()
private val instance = AtomicReference<AbstractCashSelection>()
fun getInstance(metadata: () -> java.sql.DatabaseMetaData): AbstractCashSelection {
return instance.get() ?: {
val _metadata = metadata()
val metadataResult = metadata()
val cashSelectionAlgos = ServiceLoader.load(AbstractCashSelection::class.java).toList()
val cashSelectionAlgo = cashSelectionAlgos.firstOrNull { it.isCompatible(_metadata) }
val cashSelectionAlgo = cashSelectionAlgos.firstOrNull { it.isCompatible(metadataResult) }
cashSelectionAlgo?.let {
instance.set(cashSelectionAlgo)
cashSelectionAlgo
} ?: throw ClassNotFoundException("\nUnable to load compatible cash selection algorithm implementation for JDBC driver ($_metadata)." +
} ?: throw ClassNotFoundException("\nUnable to load compatible cash selection algorithm implementation for JDBC driver ($metadataResult)." +
"\nPlease specify an implementation in META-INF/services/${AbstractCashSelection::class.java}")
}.invoke()
}
@ -84,7 +80,7 @@ abstract class AbstractCashSelection(private val maxRetries: Int = 8, private va
abstract fun executeQuery(connection: Connection, amount: Amount<Currency>, lockId: UUID, notary: Party?,
onlyFromIssuerParties: Set<AbstractParty>, withIssuerRefs: Set<OpaqueBytes>, withResultSet: (ResultSet) -> Boolean): Boolean
override abstract fun toString(): String
abstract override fun toString(): String
/**
* Query to gather Cash states that are available and retry if they are temporarily unavailable.
@ -149,7 +145,7 @@ abstract class AbstractCashSelection(private val maxRetries: Int = 8, private va
if (stateRefs.isNotEmpty()) {
// TODO: future implementation to retrieve contract states from a Vault BLOB store
stateAndRefs.addAll(services.loadStates(stateRefs) as Collection<StateAndRef<Cash.State>>)
stateAndRefs.addAll(uncheckedCast(services.loadStates(stateRefs)))
}
val success = stateAndRefs.isNotEmpty() && totalPennies >= amount.quantity

View File

@ -13,6 +13,9 @@ package com.r3.corda.enterprise.perftestcordapp.flows
import co.paralleluniverse.fibers.Suspendable
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.cash.selection.AbstractCashSelection
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
import com.r3.corda.enterprise.perftestcordapp.issuedBy
import net.corda.core.contracts.Amount
import net.corda.core.contracts.InsufficientBalanceException
@ -60,10 +63,13 @@ class CashExitFlow(private val amount: Amount<Currency>,
.getInstance { serviceHub.jdbcSession().metaData }
.unconsumedCashStatesForSpending(serviceHub, amount, setOf(issuer.party), builder.notary, builder.lockId, setOf(issuer.reference))
val signers = try {
val changeOwner = exitStates.map { it.state.data.owner }.toSet().firstOrNull() ?: throw InsufficientBalanceException(amount)
Cash().generateExit(
builder,
amount.issuedBy(issuer),
exitStates)
exitStates,
changeOwner
)
} catch (e: InsufficientBalanceException) {
throw CashException("Exiting more cash than exists", e)
}

View File

@ -14,6 +14,10 @@ import co.paralleluniverse.fibers.Suspendable
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_ID
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
import net.corda.confidential.SwapIdentitiesFlow
import net.corda.core.contracts.*
import net.corda.core.flows.FlowException
@ -23,6 +27,7 @@ import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party
import net.corda.core.internal.uncheckedCast
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.ProgressTracker
@ -54,7 +59,7 @@ class CashIssueAndDoublePayment(val amount: Amount<Currency>,
= txState.copy(data = txState.data.copy(amount = amt, owner = owner))
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
val cashStateAndRef = serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single() as StateAndRef<Cash.State>
val cashStateAndRef: StateAndRef<Cash.State> = uncheckedCast(serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single())
progressTracker.currentStep = GENERATING_ID
val txIdentities = if (anonymous) {
@ -86,7 +91,7 @@ class CashIssueAndDoublePayment(val amount: Amount<Currency>,
progressTracker.currentStep = FINALISING_TX
val notarised1 = finaliseTx(tx1, setOf(recipient), "Unable to notarise spend first time")
try {
val notarised2 = finaliseTx(tx2, setOf(recipient), "Unable to notarise spend second time")
finaliseTx(tx2, setOf(recipient), "Unable to notarise spend second time")
} catch (expected: CashException) {
val cause = expected.cause
if (cause is NotaryException) {

View File

@ -14,12 +14,17 @@ import co.paralleluniverse.fibers.Suspendable
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_ID
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
import net.corda.confidential.SwapIdentitiesFlow
import net.corda.core.contracts.*
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party
import net.corda.core.internal.uncheckedCast
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.ProgressTracker
@ -51,7 +56,7 @@ class CashIssueAndDuplicatePayment(val amount: Amount<Currency>,
= txState.copy(data = txState.data.copy(amount = amt, owner = owner))
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
val cashStateAndRef = serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single() as StateAndRef<Cash.State>
val cashStateAndRef: StateAndRef<Cash.State> = uncheckedCast(serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single())
progressTracker.currentStep = GENERATING_ID
val txIdentities = if (anonymous) {
@ -74,7 +79,7 @@ class CashIssueAndDuplicatePayment(val amount: Amount<Currency>,
val tx = serviceHub.signInitialTransaction(spendTx, keysForSigning)
progressTracker.currentStep = FINALISING_TX
val notarised1 = finaliseTx(tx, setOf(recipient), "Unable to notarise spend first time")
finaliseTx(tx, setOf(recipient), "Unable to notarise spend first time")
val notarised2 = finaliseTx(tx, setOf(recipient), "Unable to notarise spend second time")
return Result(notarised2.id, recipient)

View File

@ -14,12 +14,17 @@ import co.paralleluniverse.fibers.Suspendable
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.OnLedgerAsset
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.PartyAndAmount
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_ID
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
import net.corda.confidential.SwapIdentitiesFlow
import net.corda.core.contracts.*
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party
import net.corda.core.internal.uncheckedCast
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.ProgressTracker
@ -51,7 +56,7 @@ class CashIssueAndPaymentNoSelection(val amount: Amount<Currency>,
progressTracker.currentStep = GENERATING_TX
val issueResult = subFlow(CashIssueFlow(amount, issueRef, notary))
val cashStateAndRef = serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single() as StateAndRef<Cash.State>
val cashStateAndRef: StateAndRef<Cash.State> = uncheckedCast(serviceHub.loadStates(setOf(StateRef(issueResult.id, 0))).single())
progressTracker.currentStep = GENERATING_ID
val txIdentities = if (anonymous) {

View File

@ -12,6 +12,9 @@ package com.r3.corda.enterprise.perftestcordapp.flows
import co.paralleluniverse.fibers.Suspendable
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
import com.r3.corda.enterprise.perftestcordapp.issuedBy
import net.corda.core.contracts.Amount
import net.corda.core.flows.StartableByRPC

View File

@ -12,6 +12,10 @@ package com.r3.corda.enterprise.perftestcordapp.flows
import co.paralleluniverse.fibers.Suspendable
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.FINALISING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_ID
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.GENERATING_TX
import com.r3.corda.enterprise.perftestcordapp.flows.AbstractCashFlow.Companion.SIGNING_TX
import net.corda.confidential.SwapIdentitiesFlow
import net.corda.core.contracts.Amount
import net.corda.core.contracts.InsufficientBalanceException

Some files were not shown because too many files have changed in this diff Show More