diff --git a/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeDriverTest.kt b/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeDriverTest.kt index 430b7dbac8..26a2039406 100644 --- a/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeDriverTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeDriverTest.kt @@ -29,6 +29,7 @@ import net.corda.core.identity.Party import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.copyBytes import net.corda.core.messaging.startFlow +import net.corda.core.node.ServiceHub import net.corda.core.serialization.CustomSerializationScheme import net.corda.core.serialization.SerializationSchemeContext import net.corda.core.serialization.internal.CustomSerializationSchemeUtils.Companion.getSchemeIdIfCustomSerializationMagic @@ -55,12 +56,28 @@ import org.objenesis.strategy.InstantiatorStrategy import org.objenesis.strategy.StdInstantiatorStrategy import java.io.ByteArrayOutputStream import java.lang.reflect.Modifier +import java.security.PublicKey import java.util.* import kotlin.test.assertEquals import kotlin.test.assertTrue class CustomSerializationSchemeDriverTest { + companion object { + private fun createWireTx(serviceHub: ServiceHub, notary: Party, key: PublicKey, schemeId: Int): WireTransaction { + val outputState = TransactionState( + data = DummyContract.DummyState(), + contract = DummyContract::class.java.name, + notary = notary, + constraint = AlwaysAcceptAttachmentConstraint + ) + val builder = TransactionBuilder() + .addOutputState(outputState) + .addCommand(DummyCommandData, key) + return builder.toWireTransaction(serviceHub, schemeId) + } + } + @Test(timeout = 300_000) fun `flow can send wire transaction serialized with custom kryo serializer`() { driver(DriverParameters(notarySpecs = emptyList(), startNodesInProcess = true, cordappsForAllNodes = listOf(enclosedCordapp()))) { @@ -120,16 +137,7 @@ class CustomSerializationSchemeDriverTest { class WriteTxToLedgerFlow(val counterparty: Party, val notary: Party) : FlowLogic() { @Suspendable override fun call(): SecureHash { - val outputState = TransactionState( - data = DummyContract.DummyState(), - contract = DummyContract::class.java.name, - notary = notary, - constraint = AlwaysAcceptAttachmentConstraint - ) - val builder = TransactionBuilder() - .addOutputState(outputState) - .addCommand(DummyCommandData, counterparty.owningKey) - val wireTx = builder.toWireTransaction(serviceHub, KryoScheme.SCHEME_ID) + val wireTx = createWireTx(serviceHub, notary, counterparty.owningKey, KryoScheme.SCHEME_ID) val partSignedTx = signWireTx(wireTx) val session = initiateFlow(counterparty) val fullySignedTx = subFlow(CollectSignaturesFlow(partSignedTx, setOf(session))) @@ -174,17 +182,7 @@ class CustomSerializationSchemeDriverTest { class CheckComponentGroupsFlow(val notary: Party) : FlowLogic() { @Suspendable override fun call(): Boolean { - val outputState = TransactionState( - data = DummyContract.DummyState(), - contract = DummyContract::class.java.name, - notary = notary, - constraint = AlwaysAcceptAttachmentConstraint - ) - val builder = TransactionBuilder() - .addOutputState(outputState) - .addCommand(DummyCommandData, notary.owningKey) - - val wtx = builder.toWireTransaction(serviceHub, KryoScheme.SCHEME_ID) + val wtx = createWireTx(serviceHub, notary, notary.owningKey, KryoScheme.SCHEME_ID) var success = true for (group in wtx.componentGroups) { //Component groups are lazily serialized as we iterate through. @@ -230,23 +228,21 @@ class CustomSerializationSchemeDriverTest { class SendFlow(val counterparty: Party) : FlowLogic() { @Suspendable override fun call(): Boolean { - val outputState = TransactionState( - data = DummyContract.DummyState(), - contract = DummyContract::class.java.name, - notary = counterparty, - constraint = AlwaysAcceptAttachmentConstraint - ) - val builder = TransactionBuilder() - .addOutputState(outputState) - .addCommand(DummyCommandData, counterparty.owningKey) - - val wtx = builder.toWireTransaction(serviceHub, KryoScheme.SCHEME_ID) + val wtx = createWireTx(serviceHub, counterparty, counterparty.owningKey, KryoScheme.SCHEME_ID) val session = initiateFlow(counterparty) session.send(wtx) return session.receive().unwrap {it} } } + @StartableByRPC + class CreateWireTxFlow(val counterparty: Party) : FlowLogic() { + @Suspendable + override fun call(): WireTransaction { + return createWireTx(serviceHub, counterparty, counterparty.owningKey, KryoScheme.SCHEME_ID) + } + } + @InitiatedBy(SendFlow::class) class ReceiveFlow(private val session: FlowSession): FlowLogic() { @Suspendable diff --git a/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeMockNetworkTest.kt b/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeMockNetworkTest.kt new file mode 100644 index 0000000000..6da9350ec7 --- /dev/null +++ b/node/src/integration-test/kotlin/net/corda/node/CustomSerializationSchemeMockNetworkTest.kt @@ -0,0 +1,62 @@ +package net.corda.node + +import net.corda.core.crypto.SecureHash +import net.corda.core.serialization.SerializedBytes +import net.corda.core.serialization.deserialize +import net.corda.node.CustomSerializationSchemeDriverTest.CreateWireTxFlow +import net.corda.node.CustomSerializationSchemeDriverTest.WriteTxToLedgerFlow +import net.corda.testing.core.ALICE_NAME +import net.corda.testing.core.BOB_NAME +import net.corda.testing.node.internal.CustomCordapp +import net.corda.testing.node.internal.InternalMockNetwork +import net.corda.testing.node.internal.InternalMockNodeParameters +import net.corda.testing.node.internal.enclosedCordapp +import net.corda.testing.node.internal.startFlow +import org.junit.After +import org.junit.Before +import org.junit.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +class CustomSerializationSchemeMockNetworkTest { + + private lateinit var mockNetwork : InternalMockNetwork + + val customSchemeCordapp: CustomCordapp = CustomSerializationSchemeDriverTest().enclosedCordapp() + + @Before + fun setup() { + mockNetwork = InternalMockNetwork(cordappsForAllNodes = listOf(customSchemeCordapp)) + } + + @After + fun shutdown() { + mockNetwork.stopNodes() + } + + @Test(timeout = 300_000) + fun `transactions network parameter hash is correct`() { + val alice = mockNetwork.createNode(InternalMockNodeParameters(legalName = ALICE_NAME)) + val bob = mockNetwork.createNode(InternalMockNodeParameters(legalName = BOB_NAME)) + val flow = alice.services.startFlow (CreateWireTxFlow(bob.info.legalIdentities.single())) + mockNetwork.runNetwork() + val wireTx = flow.resultFuture.get() + /** The NetworkParmeters is the last component in the list of component groups. If we ever change this this + * in [net.corda.core.internal.createComponentGroups] this test will need to be updated.*/ + val serializedHash = SerializedBytes(wireTx.componentGroups.last().components.single().bytes) + assertEquals(alice.internals.networkParametersStorage.defaultHash, serializedHash.deserialize()) + } + + @Test(timeout = 300_000) + fun `transaction can be written to the ledger`() { + val alice = mockNetwork.createNode(InternalMockNodeParameters(legalName = ALICE_NAME)) + val bob = mockNetwork.createNode(InternalMockNodeParameters(legalName = BOB_NAME)) + val flow = alice.services.startFlow (WriteTxToLedgerFlow(bob.info.legalIdentities.single(), + mockNetwork.notaryNodes.single().info.legalIdentities.single())) + mockNetwork.runNetwork() + val txId = flow.resultFuture.get() + val getTxFlow = bob.services.startFlow(CustomSerializationSchemeDriverTest.GetTxFromDBFlow(txId)) + mockNetwork.runNetwork() + assertNotNull(getTxFlow.resultFuture.get()) + } +} diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/MockNetworkParametersService.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/MockNetworkParametersService.kt index 6938c9d256..390b0b6369 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/MockNetworkParametersService.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/MockNetworkParametersService.kt @@ -20,17 +20,28 @@ import java.time.Instant class MockNetworkParametersStorage(private var currentParameters: NetworkParameters = testNetworkParameters(modifiedTime = Instant.MIN)) : NetworkParametersStorage { private val hashToParametersMap: HashMap = HashMap() private val hashToSignedParametersMap: HashMap = HashMap() + override var currentHash = currentParameters.computeHash() + override val defaultHash: SecureHash get() = currentHash init { storeCurrentParameters() } + private fun NetworkParameters.computeHash(): SecureHash { + return withTestSerializationEnvIfNotSet { + this.serialize().hash + } + } + fun setCurrentParametersUnverified(networkParameters: NetworkParameters) { currentParameters = networkParameters + currentHash = currentParameters.computeHash() storeCurrentParameters() } override fun setCurrentParameters(currentSignedParameters: SignedDataWithCert, trustRoots: Set) { - setCurrentParametersUnverified(currentSignedParameters.verifiedNetworkParametersCert(trustRoots)) + currentParameters = currentSignedParameters.verifiedNetworkParametersCert(trustRoots) + currentHash = currentSignedParameters.raw.hash + storeCurrentParameters() } override fun lookupSigned(hash: SecureHash): SignedDataWithCert? { @@ -39,13 +50,6 @@ class MockNetworkParametersStorage(private var currentParameters: NetworkParamet override fun hasParameters(hash: SecureHash): Boolean = hash in hashToParametersMap - override val currentHash: SecureHash - get() { - return withTestSerializationEnvIfNotSet { - currentParameters.serialize().hash - } - } - override val defaultHash: SecureHash get() = currentHash override fun lookup(hash: SecureHash): NetworkParameters? = hashToParametersMap[hash] override fun getEpochFromHash(hash: SecureHash): Int? = lookup(hash)?.epoch override fun saveParameters(signedNetworkParameters: SignedDataWithCert) {