From fb624a2b06bceff0b0ac6996ddec8feb8a7794bc Mon Sep 17 00:00:00 2001 From: Adel El-Beik <48713346+adelel1@users.noreply.github.com> Date: Wed, 26 Jan 2022 11:33:23 +0000 Subject: [PATCH 01/11] CORDA-4189: Now compare against Corda Community Edition as well. (#7046) * CORDA-4189: Now compare against Corda Community Edition as well. * CORDA-4189: Removed unused imports. --- node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt b/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt index 2fb9e35196..64c275193e 100644 --- a/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt @@ -13,6 +13,7 @@ import kotlin.test.assertTrue class NodeRPCTests { private val CORDA_VERSION_REGEX = "\\d+(\\.\\d+)?(\\.\\d+)?(-\\w+)?".toRegex() private val CORDA_VENDOR = "Corda Open Source" + private val CORDA_VENDOR_CE = "Corda Community Edition" private val CORDAPPS = listOf(FINANCE_CONTRACTS_CORDAPP, FINANCE_WORKFLOWS_CORDAPP) private val CORDAPP_TYPES = setOf("Contract CorDapp", "Workflow CorDapp") private val CLASSIFIER = if (SystemUtils.IS_JAVA_11) "-jdk11" else "" @@ -30,6 +31,7 @@ class NodeRPCTests { assertTrue(nodeDiagnosticInfo.version.matches(CORDA_VERSION_REGEX)) assertEquals(PLATFORM_VERSION, nodeDiagnosticInfo.platformVersion) assertEquals(CORDA_VENDOR, nodeDiagnosticInfo.vendor) + assertTrue(nodeDiagnosticInfo.vendor == CORDA_VENDOR || nodeDiagnosticInfo.vendor == CORDA_VENDOR_CE) nodeDiagnosticInfo.cordapps.forEach { println("${it.shortName} ${it.type}") } assertEquals(CORDAPPS.size, nodeDiagnosticInfo.cordapps.size) assertEquals(CORDAPP_TYPES, nodeDiagnosticInfo.cordapps.map { it.type }.toSet()) From b93ce6ed598522962d313d04cf2d6017483cd77a Mon Sep 17 00:00:00 2001 From: Adel El-Beik <48713346+adelel1@users.noreply.github.com> Date: Wed, 26 Jan 2022 11:34:10 +0000 Subject: [PATCH 02/11] ENT-6550: Updated quasar version. (#7045) --- constants.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constants.properties b/constants.properties index a236dd791b..0fda4ee782 100644 --- a/constants.properties +++ b/constants.properties @@ -14,7 +14,7 @@ java8MinUpdateVersion=171 platformVersion=10 guavaVersion=28.0-jre # Quasar version to use with Java 8: -quasarVersion=0.7.13_r3 +quasarVersion=0.7.14_r3 # Quasar version to use with Java 11: quasarVersion11=0.8.1_r3 jdkClassifier11=jdk11 From 9444c9b637a1e083d36c98f5f81c283b5fd976fb Mon Sep 17 00:00:00 2001 From: Adel El-Beik <48713346+adelel1@users.noreply.github.com> Date: Wed, 26 Jan 2022 11:37:22 +0000 Subject: [PATCH 03/11] ENT-6567: Bump platform version to 11 (#7043) * ENT-6567: Bump platform version to 11 * ENT-6567: Bump platform version to 11 --- constants.properties | 2 +- core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/constants.properties b/constants.properties index 0fda4ee782..62ec448848 100644 --- a/constants.properties +++ b/constants.properties @@ -11,7 +11,7 @@ java8MinUpdateVersion=171 # When incrementing platformVersion make sure to update # # net.corda.core.internal.CordaUtilsKt.PLATFORM_VERSION as well. # # ***************************************************************# -platformVersion=10 +platformVersion=11 guavaVersion=28.0-jre # Quasar version to use with Java 8: quasarVersion=0.7.14_r3 diff --git a/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt b/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt index e0f41d2fdd..3e09be0ff4 100644 --- a/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/CordaUtils.kt @@ -28,7 +28,9 @@ import java.util.jar.JarInputStream // *Internal* Corda-specific utilities. -const val PLATFORM_VERSION = 10 + +// When incrementing platformVersion make sure to update PLATFORM_VERSION in constants.properties as well. +const val PLATFORM_VERSION = 11 fun ServicesForResolution.ensureMinimumPlatformVersion(requiredMinPlatformVersion: Int, feature: String) { checkMinimumPlatformVersion(networkParameters.minimumPlatformVersion, requiredMinPlatformVersion, feature) From ce211000cd3be7664e311ee44a27e0f2d971f361 Mon Sep 17 00:00:00 2001 From: Ronan Browne Date: Wed, 26 Jan 2022 13:32:18 +0000 Subject: [PATCH 04/11] ENT-6426: update docker tagging (#7047) * ENT-6426: update docker tahhing inline with our policies old corda/corda-zulu-java1.8-4.8.5:latest new corda/corda:4.8.5-zulu-1.8 based on pattern {repo}:{version}-{base-Image} * ENT-6426: update docker tahhing inline with our policies old corda/corda-zulu-java1.8-4.8.5:latest new corda/corda:4.8.5-zulu-openjdk8 based on pattern {repo}:{version}-{base-Image} Remove some redundant code * ENT-6426 update corda repo tagging * ENT-6426 update corda repo tagging * ENt-6426 update corda tagging in line with feedback --- .ci/dev/regression/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/dev/regression/Jenkinsfile b/.ci/dev/regression/Jenkinsfile index b53e23d557..aa22fce3f3 100644 --- a/.ci/dev/regression/Jenkinsfile +++ b/.ci/dev/regression/Jenkinsfile @@ -319,7 +319,7 @@ pipeline { './gradlew', COMMON_GRADLE_PARAMS, 'docker:pushDockerImage', - '-Pdocker.image.repository=corda/community-node', + '-Pdocker.image.repository=corda/corda', '--image OFFICIAL' ].join(' ') } From 7752fc8c9d9f90ff5d5ee820e4ba46afe5c83887 Mon Sep 17 00:00:00 2001 From: Adel El-Beik <48713346+adelel1@users.noreply.github.com> Date: Thu, 27 Jan 2022 13:49:08 +0000 Subject: [PATCH 05/11] CORDA-4189: Removed existing vendor test (#7048) --- node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt b/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt index 64c275193e..646772745f 100644 --- a/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt +++ b/node/src/integration-test/kotlin/net/corda/node/NodeRPCTests.kt @@ -30,7 +30,6 @@ class NodeRPCTests { val nodeDiagnosticInfo = startNode().get().rpc.nodeDiagnosticInfo() assertTrue(nodeDiagnosticInfo.version.matches(CORDA_VERSION_REGEX)) assertEquals(PLATFORM_VERSION, nodeDiagnosticInfo.platformVersion) - assertEquals(CORDA_VENDOR, nodeDiagnosticInfo.vendor) assertTrue(nodeDiagnosticInfo.vendor == CORDA_VENDOR || nodeDiagnosticInfo.vendor == CORDA_VENDOR_CE) nodeDiagnosticInfo.cordapps.forEach { println("${it.shortName} ${it.type}") } assertEquals(CORDAPPS.size, nodeDiagnosticInfo.cordapps.size) From 758a69f9048b6550aba384415b85427c493bacaf Mon Sep 17 00:00:00 2001 From: Chris Rankin Date: Mon, 31 Jan 2022 09:40:01 +0000 Subject: [PATCH 06/11] Validate LedgerTransaction deserialised from AttachmentsClassLoader. (#7049) (#7052) --- .../transactions/TransactionTests.kt | 8 +- .../corda/core/internal/ConstraintsUtils.kt | 9 +- .../TransactionVerifierServiceInternal.kt | 82 +++++++++++++++---- .../core/transactions/LedgerTransaction.kt | 31 +++---- .../internal/internalAccessTestHelpers.kt | 14 +++- .../net/corda/node/djvm/AttachmentBuilder.kt | 28 ++++++- .../contracts/mutator/MutatorContract.kt | 8 +- .../net/corda/node/CashIssueAndPaymentTest.kt | 6 +- .../ContractCannotMutateTransactionTest.kt | 4 +- .../node/ContractWithCordappFixupTest.kt | 6 +- .../node/ContractWithCustomSerializerTest.kt | 2 +- .../corda/node/ContractWithGenericTypeTest.kt | 6 +- ...ContractWithMissingCustomSerializerTest.kt | 2 +- .../ContractWithSerializationWhitelistTest.kt | 2 +- .../DeterministicCashIssueAndPaymentTest.kt | 6 +- ...sticContractCannotMutateTransactionTest.kt | 4 +- .../DeterministicContractCryptoTest.kt | 6 +- ...inisticContractWithCustomSerializerTest.kt | 10 +-- ...eterministicContractWithGenericTypeTest.kt | 6 +- ...cContractWithSerializationWhitelistTest.kt | 10 +-- ...isticEvilContractCannotModifyStatesTest.kt | 4 +- .../NonDeterministicContractVerifyTest.kt | 6 +- .../node/services/SandboxAttachmentsTest.kt | 6 +- .../node/internal/djvm/AttachmentFactory.kt | 31 +++++-- .../internal/djvm/DeterministicVerifier.kt | 19 +++-- 25 files changed, 212 insertions(+), 104 deletions(-) diff --git a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionTests.kt b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionTests.kt index 47d4171c1d..62254d6b4e 100644 --- a/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionTests.kt +++ b/core-tests/src/test/kotlin/net/corda/coretests/transactions/TransactionTests.kt @@ -21,6 +21,7 @@ import net.corda.testing.internal.createWireTransaction import net.corda.testing.internal.fakeAttachment import net.corda.coretesting.internal.rigorousMock import net.corda.testing.internal.TestingNamedCacheFactory +import org.assertj.core.api.Assertions.fail import org.junit.Before import org.junit.Rule import org.junit.Test @@ -36,6 +37,7 @@ import kotlin.test.assertNotEquals @RunWith(Parameterized::class) class TransactionTests(private val digestService : DigestService) { private companion object { + const val ISOLATED_JAR = "isolated-4.0.jar" val DUMMY_KEY_1 = generateKeyPair() val DUMMY_KEY_2 = generateKeyPair() val DUMMY_CASH_ISSUER_KEY = entropyToKeyPair(BigInteger.valueOf(10)) @@ -200,15 +202,15 @@ class TransactionTests(private val digestService : DigestService) { val outputs = listOf(outState) val commands = emptyList>() - val attachments = listOf(object : AbstractAttachment({ - AttachmentsClassLoaderTests::class.java.getResource("isolated-4.0.jar").openStream().readBytes() + val attachments = listOf(ContractAttachment(object : AbstractAttachment({ + (AttachmentsClassLoaderTests::class.java.getResource(ISOLATED_JAR) ?: fail("Missing $ISOLATED_JAR")).openStream().readBytes() }, TESTDSL_UPLOADER) { @Suppress("OverridingDeprecatedMember") override val signers: List = emptyList() override val signerKeys: List = emptyList() override val size: Int = 1234 override val id: SecureHash = SecureHash.zeroHash - }) + }, DummyContract.PROGRAM_ID)) val id = digestService.randomHash() val timeWindow: TimeWindow? = null val privacySalt = PrivacySalt(digestService.digestLength) diff --git a/core/src/main/kotlin/net/corda/core/internal/ConstraintsUtils.kt b/core/src/main/kotlin/net/corda/core/internal/ConstraintsUtils.kt index c05ae94680..2cdb80fad1 100644 --- a/core/src/main/kotlin/net/corda/core/internal/ConstraintsUtils.kt +++ b/core/src/main/kotlin/net/corda/core/internal/ConstraintsUtils.kt @@ -16,6 +16,7 @@ typealias Version = Int * Attention: this value affects consensus, so it requires a minimum platform version bump in order to be changed. */ const val MAX_NUMBER_OF_KEYS_IN_SIGNATURE_CONSTRAINT = 20 +private const val DJVM_SANDBOX_PREFIX = "sandbox." private val log = loggerFor() @@ -29,10 +30,14 @@ val Attachment.contractVersion: Version get() = if (this is ContractAttachment) val ContractState.requiredContractClassName: String? get() { val annotation = javaClass.getAnnotation(BelongsToContract::class.java) if (annotation != null) { - return annotation.value.java.typeName + return annotation.value.java.typeName.removePrefix(DJVM_SANDBOX_PREFIX) } val enclosingClass = javaClass.enclosingClass ?: return null - return if (Contract::class.java.isAssignableFrom(enclosingClass)) enclosingClass.typeName else null + return if (Contract::class.java.isAssignableFrom(enclosingClass)) { + enclosingClass.typeName.removePrefix(DJVM_SANDBOX_PREFIX) + } else { + null + } } /** diff --git a/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt b/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt index 2a8c13036e..58d647af6f 100644 --- a/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt +++ b/core/src/main/kotlin/net/corda/core/internal/TransactionVerifierServiceInternal.kt @@ -13,6 +13,7 @@ import net.corda.core.contracts.SignatureAttachmentConstraint import net.corda.core.contracts.StateAndRef import net.corda.core.contracts.StateRef import net.corda.core.contracts.TransactionState +import net.corda.core.contracts.TransactionVerificationException import net.corda.core.contracts.TransactionVerificationException.ConflictingAttachmentsRejection import net.corda.core.contracts.TransactionVerificationException.ConstraintPropagationRejection import net.corda.core.contracts.TransactionVerificationException.ContractCreationError @@ -33,7 +34,7 @@ import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.SecureHash import net.corda.core.internal.rules.StateContractValidationEnforcementRule import net.corda.core.transactions.LedgerTransaction -import net.corda.core.utilities.contextLogger +import net.corda.core.utilities.loggerFor import java.util.function.Function import java.util.function.Supplier @@ -47,16 +48,54 @@ interface TransactionVerifierServiceInternal { */ fun LedgerTransaction.prepareVerify(attachments: List) = internalPrepareVerify(attachments) +interface Verifier { + + /** + * Placeholder function for the verification logic. + */ + fun verify() +} + +// This class allows us unit-test transaction verification more easily. +abstract class AbstractVerifier( + protected val ltx: LedgerTransaction, + protected val transactionClassLoader: ClassLoader +) : Verifier { + protected abstract val transaction: Supplier + + protected companion object { + @JvmField + val logger = loggerFor() + } + + /** + * Check that the transaction is internally consistent, and then check that it is + * contract-valid by running verify() for each input and output state contract. + * If any contract fails to verify, the whole transaction is considered to be invalid. + * + * Note: Reference states are not verified. + */ + final override fun verify() { + try { + TransactionVerifier(transactionClassLoader).apply(transaction) + } catch (e: TransactionVerificationException) { + logger.error("Error validating transaction ${ltx.id}.", e.cause) + throw e + } + } +} + /** * Because we create a separate [LedgerTransaction] onto which we need to perform verification, it becomes important we don't verify the * wrong object instance. This class helps avoid that. */ -abstract class Verifier(val ltx: LedgerTransaction, protected val transactionClassLoader: ClassLoader) { +@KeepForDJVM +private class Validator(private val ltx: LedgerTransaction, private val transactionClassLoader: ClassLoader) { private val inputStates: List> = ltx.inputs.map(StateAndRef::state) private val allStates: List> = inputStates + ltx.references.map(StateAndRef::state) + ltx.outputs - companion object { - val logger = contextLogger() + private companion object { + private val logger = loggerFor() } /** @@ -66,7 +105,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla * * @throws net.corda.core.contracts.TransactionVerificationException */ - fun verify() { + fun validate() { // checkNoNotaryChange and checkEncumbrancesValid are called here, and not in the c'tor, as they need access to the "outputs" // list, the contents of which need to be deserialized under the correct classloader. checkNoNotaryChange() @@ -93,8 +132,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla // 4. Check that the [TransactionState] objects are correctly formed. validateStatesAgainstContract() - // 5. Final step is to run the contract code. After the first 4 steps we are now sure that we are running the correct code. - verifyContracts() + // 5. Final step will be to run the contract code. } private fun checkTransactionWithTimeWindowIsNotarised() { @@ -106,6 +144,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla * It makes sure there is one and only one. * This is an important piece of the security of transactions. */ + @Suppress("ThrowsCount") private fun getUniqueContractAttachmentsByContract(): Map { val contractClasses = allStates.mapTo(LinkedHashSet(), TransactionState<*>::contract) @@ -210,6 +249,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla // b -> c and c -> b // c -> a b -> a // and form a full cycle, meaning that the bi-directionality property is satisfied. + @Suppress("ThrowsCount") private fun checkBidirectionalOutputEncumbrances(statesAndEncumbrance: List>) { // [Set] of "from" (encumbered states). val encumberedSet = mutableSetOf() @@ -306,6 +346,7 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla * - Constraints should be one of the valid supported ones. * - Constraints should propagate correctly if not marked otherwise (in that case it is the responsibility of the contract to ensure that the output states are created properly). */ + @Suppress("NestedBlockDepth") private fun verifyConstraintsValidity(contractAttachmentsByContract: Map) { // First check that the constraints are valid. @@ -392,19 +433,15 @@ abstract class Verifier(val ltx: LedgerTransaction, protected val transactionCla throw ContractConstraintRejection(ltx.id, contract) } } - - /** - * Placeholder function for the contract verification logic. - */ - abstract fun verifyContracts() } /** - * Verify all of the contracts on the given [LedgerTransaction]. + * Verify the given [LedgerTransaction]. This includes validating + * its contents, as well as executing all of its smart contracts. */ @Suppress("TooGenericExceptionCaught") @KeepForDJVM -class ContractVerifier(private val transactionClassLoader: ClassLoader) : Function, Unit> { +class TransactionVerifier(private val transactionClassLoader: ClassLoader) : Function, Unit> { // This constructor is used inside the DJVM's sandbox. @Suppress("unused") constructor() : this(ClassLoader.getSystemClassLoader()) @@ -440,16 +477,33 @@ class ContractVerifier(private val transactionClassLoader: ClassLoader) : Functi } } + private fun validateTransaction(ltx: LedgerTransaction) { + Validator(ltx, transactionClassLoader).validate() + } + override fun apply(transactionFactory: Supplier) { var firstLtx: LedgerTransaction? = null transactionFactory.get().let { ltx -> firstLtx = ltx + + /** + * Check that this transaction is correctly formed. + * We only need to run these checks once. + */ + validateTransaction(ltx) + + /** + * Generate the list of unique contracts + * within this transaction. + */ generateContracts(ltx) }.forEach { contract -> val ltx = firstLtx ?: transactionFactory.get() firstLtx = null try { + // Final step is to run the contract code. Having validated the + // transaction, we are now sure that we are running the correct code. contract.verify(ltx) } catch (e: Exception) { throw ContractRejection(ltx.id, contract, e) diff --git a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt index c7b00f60bd..25dfa7f293 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt @@ -18,7 +18,7 @@ import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.flows.FlowLogic import net.corda.core.identity.Party -import net.corda.core.internal.ContractVerifier +import net.corda.core.internal.AbstractVerifier import net.corda.core.internal.SerializedStateAndRef import net.corda.core.internal.Verifier import net.corda.core.internal.castIfPossible @@ -824,7 +824,7 @@ private constructor( private class BasicVerifier( ltx: LedgerTransaction, private val serializationContext: SerializationContext -) : Verifier(ltx, serializationContext.deserializationClassLoader) { +) : AbstractVerifier(ltx, serializationContext.deserializationClassLoader) { init { // This is a sanity check: We should only instantiate this @@ -836,9 +836,15 @@ private class BasicVerifier( // Fetch these commands' signing parties from the database. // Corda forbids database access during contract verification, // and so we must load the commands here eagerly instead. + // THIS ALSO DESERIALISES THE COMMANDS USING THE WRONG CONTEXT + // BECAUSE THAT CONTEXT WAS CHOSEN WHEN THE LAZY MAP WAS CREATED, + // AND CHANGING THE DEFAULT CONTEXT HERE DOES NOT AFFECT IT. ltx.commands.eagerDeserialise() } + override val transaction: Supplier + get() = Supplier(::createTransaction) + private fun createTransaction(): LedgerTransaction { // Deserialize all relevant classes using the serializationContext. return SerializationFactory.defaultFactory.withCurrentContext(serializationContext) { @@ -870,21 +876,6 @@ private class BasicVerifier( } } } - - /** - * Check the transaction is contract-valid by running verify() for each input and output state contract. - * If any contract fails to verify, the whole transaction is considered to be invalid. - * - * Note: Reference states are not verified. - */ - override fun verifyContracts() { - try { - ContractVerifier(transactionClassLoader).apply(Supplier(::createTransaction)) - } catch (e: TransactionVerificationException) { - logger.error("Error validating transaction ${ltx.id}.", e.cause) - throw e - } - } } /** @@ -892,10 +883,10 @@ private class BasicVerifier( * * THIS CLASS IS NOT PUBLIC API, AND IS DELIBERATELY PRIVATE! */ +@Suppress("unused_parameter") @CordaInternal -private class NoOpVerifier(ltx: LedgerTransaction, serializationContext: SerializationContext) - : Verifier(ltx, serializationContext.deserializationClassLoader) { +private class NoOpVerifier(ltx: LedgerTransaction, serializationContext: SerializationContext) : Verifier { // Invoking LedgerTransaction.verify() from Contract.verify(LedgerTransaction) // will execute this function. But why would anyone do that?! - override fun verifyContracts() {} + override fun verify() {} } diff --git a/core/src/test/kotlin/net/corda/core/internal/internalAccessTestHelpers.kt b/core/src/test/kotlin/net/corda/core/internal/internalAccessTestHelpers.kt index 1a6f880f1d..16a6e6bef8 100644 --- a/core/src/test/kotlin/net/corda/core/internal/internalAccessTestHelpers.kt +++ b/core/src/test/kotlin/net/corda/core/internal/internalAccessTestHelpers.kt @@ -5,10 +5,12 @@ import net.corda.core.crypto.DigestService import net.corda.core.crypto.SecureHash import net.corda.core.identity.Party import net.corda.core.node.NetworkParameters +import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.internal.AttachmentsClassLoaderCache import net.corda.core.transactions.ComponentGroup import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.WireTransaction +import java.util.function.Supplier /** * A set of functions in core:test that allows testing of core internal classes in the core-tests project. @@ -38,7 +40,17 @@ fun createLedgerTransaction( isAttachmentTrusted: (Attachment) -> Boolean, attachmentsClassLoaderCache: AttachmentsClassLoaderCache, digestService: DigestService = DigestService.default -): LedgerTransaction = LedgerTransaction.create(inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, references, componentGroups, serializedInputs, serializedReferences, isAttachmentTrusted, attachmentsClassLoaderCache, digestService) +): LedgerTransaction = LedgerTransaction.create( + inputs, outputs, commands, attachments, id, notary, timeWindow, privacySalt, networkParameters, references, componentGroups, serializedInputs, serializedReferences, isAttachmentTrusted, attachmentsClassLoaderCache, digestService +).specialise(::PassthroughVerifier) fun createContractCreationError(txId: SecureHash, contractClass: String, cause: Throwable) = TransactionVerificationException.ContractCreationError(txId, contractClass, cause) fun createContractRejection(txId: SecureHash, contract: Contract, cause: Throwable) = TransactionVerificationException.ContractRejection(txId, contract, cause) + +/** + * Verify the [LedgerTransaction] we already have. + */ +private class PassthroughVerifier(ltx: LedgerTransaction, context: SerializationContext) : AbstractVerifier(ltx, context.deserializationClassLoader) { + override val transaction: Supplier + get() = Supplier { ltx } +} diff --git a/node/djvm/src/main/kotlin/net/corda/node/djvm/AttachmentBuilder.kt b/node/djvm/src/main/kotlin/net/corda/node/djvm/AttachmentBuilder.kt index f3a205ba38..561b5bcd76 100644 --- a/node/djvm/src/main/kotlin/net/corda/node/djvm/AttachmentBuilder.kt +++ b/node/djvm/src/main/kotlin/net/corda/node/djvm/AttachmentBuilder.kt @@ -3,6 +3,7 @@ package net.corda.node.djvm import net.corda.core.contracts.Attachment import net.corda.core.contracts.BrokenAttachmentException +import net.corda.core.contracts.ContractAttachment import net.corda.core.crypto.SecureHash import net.corda.core.identity.Party import java.io.InputStream @@ -16,6 +17,12 @@ private const val ID_IDX = 2 private const val ATTACHMENT_IDX = 3 private const val STREAMER_IDX = 4 +private const val CONTRACT_IDX = 5 +private const val ADDITIONAL_CONTRACT_IDX = 6 +private const val UPLOADER_IDX = 7 +private const val CONTRACT_SIGNER_KEYS_IDX = 8 +private const val VERSION_IDX = 9 + class AttachmentBuilder : Function?, List?> { private val attachments = mutableListOf() @@ -28,17 +35,30 @@ class AttachmentBuilder : Function?, List?> { } override fun apply(inputs: Array?): List? { + @Suppress("unchecked_cast") return if (inputs == null) { unmodifiable(attachments) } else { - @Suppress("unchecked_cast") - attachments.add(SandboxAttachment( + var attachment: Attachment = SandboxAttachment( signerKeys = inputs[SIGNER_KEYS_IDX] as List, size = inputs[SIZE_IDX] as Int, id = inputs[ID_IDX] as SecureHash, attachment = inputs[ATTACHMENT_IDX], streamer = inputs[STREAMER_IDX] as Function - )) + ) + + if (inputs.size > VERSION_IDX) { + attachment = ContractAttachment.create( + attachment = attachment, + contract = inputs[CONTRACT_IDX] as String, + additionalContracts = (inputs[ADDITIONAL_CONTRACT_IDX] as Array).toSet(), + uploader = inputs[UPLOADER_IDX] as? String, + signerKeys = inputs[CONTRACT_SIGNER_KEYS_IDX] as List, + version = inputs[VERSION_IDX] as Int + ) + } + + attachments.add(attachment) null } } @@ -47,7 +67,7 @@ class AttachmentBuilder : Function?, List?> { /** * This represents an [Attachment] from within the sandbox. */ -class SandboxAttachment( +private class SandboxAttachment( override val signerKeys: List, override val size: Int, override val id: SecureHash, diff --git a/node/src/integration-test/kotlin/net/corda/contracts/mutator/MutatorContract.kt b/node/src/integration-test/kotlin/net/corda/contracts/mutator/MutatorContract.kt index cffcf18b3d..239525c576 100644 --- a/node/src/integration-test/kotlin/net/corda/contracts/mutator/MutatorContract.kt +++ b/node/src/integration-test/kotlin/net/corda/contracts/mutator/MutatorContract.kt @@ -95,9 +95,11 @@ class MutatorContract : Contract { } } - private class ExtraSpecialise(ltx: LedgerTransaction, ctx: SerializationContext) - : Verifier(ltx, ctx.deserializationClassLoader) { - override fun verifyContracts() {} + private class ExtraSpecialise(private val ltx: LedgerTransaction, private val ctx: SerializationContext) : Verifier { + override fun verify() { + ltx.inputStates.forEach(::println) + println(ctx.deserializationClassLoader) + } } class MutateState(val owner: AbstractParty) : ContractState { diff --git a/node/src/integration-test/kotlin/net/corda/node/CashIssueAndPaymentTest.kt b/node/src/integration-test/kotlin/net/corda/node/CashIssueAndPaymentTest.kt index 399e1d9c2c..2da38e1509 100644 --- a/node/src/integration-test/kotlin/net/corda/node/CashIssueAndPaymentTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/CashIssueAndPaymentTest.kt @@ -30,12 +30,12 @@ class CashIssueAndPaymentTest { private val configOverrides = mapOf(NodeConfiguration::reloadCheckpointAfterSuspend.name to true) private val CASH_AMOUNT = 500.DOLLARS - fun parametersFor(): DriverParameters { + fun parametersFor(runInProcess: Boolean = false): DriverParameters { return DriverParameters( systemProperties = mapOf("co.paralleluniverse.fibers.verifyInstrumentation" to "false"), portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = false, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), notaryCustomOverrides = configOverrides, cordappsForAllNodes = listOf( findCordapp("net.corda.finance.contracts"), diff --git a/node/src/integration-test/kotlin/net/corda/node/ContractCannotMutateTransactionTest.kt b/node/src/integration-test/kotlin/net/corda/node/ContractCannotMutateTransactionTest.kt index eecfe203ec..62a92dc14f 100644 --- a/node/src/integration-test/kotlin/net/corda/node/ContractCannotMutateTransactionTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/ContractCannotMutateTransactionTest.kt @@ -23,7 +23,7 @@ class ContractCannotMutateTransactionTest { private val mutatorFlowCorDapp = cordappWithPackages("net.corda.flows.mutator").signed() private val mutatorContractCorDapp = cordappWithPackages("net.corda.contracts.mutator").signed() - fun driverParameters(runInProcess: Boolean): DriverParameters { + fun driverParameters(runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), startNodesInProcess = runInProcess, @@ -35,7 +35,7 @@ class ContractCannotMutateTransactionTest { @Test(timeout = 300_000) fun testContractCannotModifyTransaction() { - driver(driverParameters(runInProcess = false)) { + driver(driverParameters()) { val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val txID = CordaRPCClient(hostAndPort = alice.rpcAddress) .start(user.username, user.password) diff --git a/node/src/integration-test/kotlin/net/corda/node/ContractWithCordappFixupTest.kt b/node/src/integration-test/kotlin/net/corda/node/ContractWithCordappFixupTest.kt index 50e5b1b1bd..77f267aed7 100644 --- a/node/src/integration-test/kotlin/net/corda/node/ContractWithCordappFixupTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/ContractWithCordappFixupTest.kt @@ -35,11 +35,11 @@ class ContractWithCordappFixupTest { val dependentContractCorDapp = cordappWithPackages("net.corda.contracts.fixup.dependent").signed() val standaloneContractCorDapp = cordappWithPackages("net.corda.contracts.fixup.standalone").signed() - fun driverParameters(cordapps: List): DriverParameters { + fun driverParameters(cordapps: List, runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = cordapps, systemProperties = mapOf("net.corda.transactionbuilder.missingclass.disabled" to true.toString()) ) diff --git a/node/src/integration-test/kotlin/net/corda/node/ContractWithCustomSerializerTest.kt b/node/src/integration-test/kotlin/net/corda/node/ContractWithCustomSerializerTest.kt index ffb2d297b1..442214e13e 100644 --- a/node/src/integration-test/kotlin/net/corda/node/ContractWithCustomSerializerTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/ContractWithCustomSerializerTest.kt @@ -46,7 +46,7 @@ class ContractWithCustomSerializerTest(private val runInProcess: Boolean) { driver(DriverParameters( portAllocation = incrementalPortAllocation(), startNodesInProcess = runInProcess, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = listOf( cordappWithPackages("net.corda.flows.serialization.custom").signed(), cordappWithPackages("net.corda.contracts.serialization.custom").signed() diff --git a/node/src/integration-test/kotlin/net/corda/node/ContractWithGenericTypeTest.kt b/node/src/integration-test/kotlin/net/corda/node/ContractWithGenericTypeTest.kt index d23c137dda..4dfb1f17e6 100644 --- a/node/src/integration-test/kotlin/net/corda/node/ContractWithGenericTypeTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/ContractWithGenericTypeTest.kt @@ -31,11 +31,11 @@ class ContractWithGenericTypeTest { @JvmField val user = User("u", "p", setOf(Permissions.all())) - fun parameters(): DriverParameters { + fun parameters(runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = listOf( cordappWithPackages("net.corda.flows.serialization.generics").signed(), cordappWithPackages("net.corda.contracts.serialization.generics").signed() diff --git a/node/src/integration-test/kotlin/net/corda/node/ContractWithMissingCustomSerializerTest.kt b/node/src/integration-test/kotlin/net/corda/node/ContractWithMissingCustomSerializerTest.kt index 2110ff3cfe..78ee896844 100644 --- a/node/src/integration-test/kotlin/net/corda/node/ContractWithMissingCustomSerializerTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/ContractWithMissingCustomSerializerTest.kt @@ -45,7 +45,7 @@ class ContractWithMissingCustomSerializerTest(private val runInProcess: Boolean) return DriverParameters( portAllocation = incrementalPortAllocation(), startNodesInProcess = runInProcess, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = cordapps ) } diff --git a/node/src/integration-test/kotlin/net/corda/node/ContractWithSerializationWhitelistTest.kt b/node/src/integration-test/kotlin/net/corda/node/ContractWithSerializationWhitelistTest.kt index 2a9ae80195..9c6d809d77 100644 --- a/node/src/integration-test/kotlin/net/corda/node/ContractWithSerializationWhitelistTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/ContractWithSerializationWhitelistTest.kt @@ -43,7 +43,7 @@ class ContractWithSerializationWhitelistTest(private val runInProcess: Boolean) return DriverParameters( portAllocation = incrementalPortAllocation(), startNodesInProcess = runInProcess, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = listOf(contractCordapp, workflowCordapp) ) } diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicCashIssueAndPaymentTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicCashIssueAndPaymentTest.kt index 4997cac5e3..9b3bdf77ef 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicCashIssueAndPaymentTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicCashIssueAndPaymentTest.kt @@ -32,11 +32,11 @@ class DeterministicCashIssueAndPaymentTest { @JvmField val djvmSources = DeterministicSourcesRule() - fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters { + fun parametersFor(djvmSources: DeterministicSourcesRule, runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), notaryCustomOverrides = configOverrides, cordappsForAllNodes = listOf( findCordapp("net.corda.finance.contracts"), diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractCannotMutateTransactionTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractCannotMutateTransactionTest.kt index 68b8c3531c..41c80ea7d9 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractCannotMutateTransactionTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractCannotMutateTransactionTest.kt @@ -28,7 +28,7 @@ class DeterministicContractCannotMutateTransactionTest { @JvmField val djvmSources = DeterministicSourcesRule() - fun driverParameters(runInProcess: Boolean): DriverParameters { + fun driverParameters(runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), startNodesInProcess = runInProcess, @@ -42,7 +42,7 @@ class DeterministicContractCannotMutateTransactionTest { @Test(timeout = 300_000) fun testContractCannotModifyTransaction() { - driver(driverParameters(runInProcess = false)) { + driver(driverParameters()) { val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val txID = CordaRPCClient(hostAndPort = alice.rpcAddress) .start(user.username, user.password) diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractCryptoTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractCryptoTest.kt index 275693f4d7..5d28ae41b8 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractCryptoTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractCryptoTest.kt @@ -32,11 +32,11 @@ class DeterministicContractCryptoTest { @JvmField val djvmSources = DeterministicSourcesRule() - fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters { + fun parametersFor(djvmSources: DeterministicSourcesRule, runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = listOf( cordappWithPackages("net.corda.flows.djvm.crypto"), CustomCordapp( diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithCustomSerializerTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithCustomSerializerTest.kt index 3630fbcf3c..447cd2d6a6 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithCustomSerializerTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithCustomSerializerTest.kt @@ -41,11 +41,11 @@ class DeterministicContractWithCustomSerializerTest { @JvmField val contractCordapp = cordappWithPackages("net.corda.contracts.serialization.custom").signed() - fun parametersFor(djvmSources: DeterministicSourcesRule, vararg cordapps: TestCordapp): DriverParameters { + fun parametersFor(djvmSources: DeterministicSourcesRule, cordapps: List, runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = cordapps.toList(), djvmBootstrapSource = djvmSources.bootstrap, djvmCordaSource = djvmSources.corda @@ -61,7 +61,7 @@ class DeterministicContractWithCustomSerializerTest { @Test(timeout=300_000) fun `test DJVM can verify using custom serializer`() { - driver(parametersFor(djvmSources, flowCordapp, contractCordapp)) { + driver(parametersFor(djvmSources, listOf(flowCordapp, contractCordapp))) { val alice = startNode(providedName = ALICE_NAME).getOrThrow() val txId = assertDoesNotThrow { alice.rpc.startFlow(::CustomSerializerFlow, Currantsy(GOOD_CURRANTS)) @@ -73,7 +73,7 @@ class DeterministicContractWithCustomSerializerTest { @Test(timeout=300_000) fun `test DJVM can fail verify using custom serializer`() { - driver(parametersFor(djvmSources, flowCordapp, contractCordapp)) { + driver(parametersFor(djvmSources, listOf(flowCordapp, contractCordapp))) { val alice = startNode(providedName = ALICE_NAME).getOrThrow() val currantsy = Currantsy(BAD_CURRANTS) val ex = assertThrows { diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithGenericTypeTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithGenericTypeTest.kt index c3c440eaf6..d2cae60136 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithGenericTypeTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithGenericTypeTest.kt @@ -36,11 +36,11 @@ class DeterministicContractWithGenericTypeTest { @JvmField val djvmSources = DeterministicSourcesRule() - fun parameters(): DriverParameters { + fun parameters(runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = listOf( cordappWithPackages("net.corda.flows.serialization.generics").signed(), cordappWithPackages("net.corda.contracts.serialization.generics").signed() diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithSerializationWhitelistTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithSerializationWhitelistTest.kt index 97ecbf014a..9b0e057453 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithSerializationWhitelistTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicContractWithSerializationWhitelistTest.kt @@ -41,11 +41,11 @@ class DeterministicContractWithSerializationWhitelistTest { @JvmField val contractCordapp = cordappWithPackages("net.corda.contracts.djvm.whitelist").signed() - fun parametersFor(djvmSources: DeterministicSourcesRule, vararg cordapps: TestCordapp): DriverParameters { + fun parametersFor(djvmSources: DeterministicSourcesRule, cordapps: List, runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = cordapps.toList(), djvmBootstrapSource = djvmSources.bootstrap, djvmCordaSource = djvmSources.corda @@ -61,7 +61,7 @@ class DeterministicContractWithSerializationWhitelistTest { @Test(timeout=300_000) fun `test DJVM can verify using whitelist`() { - driver(parametersFor(djvmSources, flowCordapp, contractCordapp)) { + driver(parametersFor(djvmSources, listOf(flowCordapp, contractCordapp))) { val alice = startNode(providedName = ALICE_NAME).getOrThrow() val txId = assertDoesNotThrow { alice.rpc.startFlow(::DeterministicWhitelistFlow, WhitelistData(GOOD_VALUE)) @@ -73,7 +73,7 @@ class DeterministicContractWithSerializationWhitelistTest { @Test(timeout=300_000) fun `test DJVM can fail verify using whitelist`() { - driver(parametersFor(djvmSources, flowCordapp, contractCordapp)) { + driver(parametersFor(djvmSources, listOf(flowCordapp, contractCordapp))) { val alice = startNode(providedName = ALICE_NAME).getOrThrow() val badData = WhitelistData(BAD_VALUE) val ex = assertThrows { diff --git a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicEvilContractCannotModifyStatesTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicEvilContractCannotModifyStatesTest.kt index f2d455dce4..5188f0b4fd 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/DeterministicEvilContractCannotModifyStatesTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/DeterministicEvilContractCannotModifyStatesTest.kt @@ -34,7 +34,7 @@ class DeterministicEvilContractCannotModifyStatesTest { @JvmField val djvmSources = DeterministicSourcesRule() - fun driverParameters(runInProcess: Boolean): DriverParameters { + fun driverParameters(runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), startNodesInProcess = runInProcess, @@ -53,7 +53,7 @@ class DeterministicEvilContractCannotModifyStatesTest { @Test(timeout = 300_000) fun testContractThatTriesToModifyStates() { val evilData = MutableDataObject(5000) - driver(driverParameters(runInProcess = false)) { + driver(driverParameters()) { val alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)).getOrThrow() val ex = assertFailsWith { CordaRPCClient(hostAndPort = alice.rpcAddress) diff --git a/node/src/integration-test/kotlin/net/corda/node/services/NonDeterministicContractVerifyTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/NonDeterministicContractVerifyTest.kt index 264502e448..a200d5db41 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/NonDeterministicContractVerifyTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/NonDeterministicContractVerifyTest.kt @@ -35,11 +35,11 @@ class NonDeterministicContractVerifyTest { @JvmField val djvmSources = DeterministicSourcesRule() - fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters { + fun parametersFor(djvmSources: DeterministicSourcesRule, runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = listOf( cordappWithPackages("net.corda.flows.djvm.broken"), CustomCordapp( diff --git a/node/src/integration-test/kotlin/net/corda/node/services/SandboxAttachmentsTest.kt b/node/src/integration-test/kotlin/net/corda/node/services/SandboxAttachmentsTest.kt index c825357581..e868566f58 100644 --- a/node/src/integration-test/kotlin/net/corda/node/services/SandboxAttachmentsTest.kt +++ b/node/src/integration-test/kotlin/net/corda/node/services/SandboxAttachmentsTest.kt @@ -31,11 +31,11 @@ class SandboxAttachmentsTest { @JvmField val djvmSources = DeterministicSourcesRule() - fun parametersFor(djvmSources: DeterministicSourcesRule): DriverParameters { + fun parametersFor(djvmSources: DeterministicSourcesRule, runInProcess: Boolean = false): DriverParameters { return DriverParameters( portAllocation = incrementalPortAllocation(), - startNodesInProcess = false, - notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, validating = true)), + startNodesInProcess = runInProcess, + notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, startInProcess = runInProcess, validating = true)), cordappsForAllNodes = listOf( cordappWithPackages("net.corda.flows.djvm.attachment"), CustomCordapp( diff --git a/node/src/main/kotlin/net/corda/node/internal/djvm/AttachmentFactory.kt b/node/src/main/kotlin/net/corda/node/internal/djvm/AttachmentFactory.kt index 9a616aa813..d272a7428e 100644 --- a/node/src/main/kotlin/net/corda/node/internal/djvm/AttachmentFactory.kt +++ b/node/src/main/kotlin/net/corda/node/internal/djvm/AttachmentFactory.kt @@ -1,6 +1,7 @@ package net.corda.node.internal.djvm import net.corda.core.contracts.Attachment +import net.corda.core.contracts.ContractAttachment import net.corda.core.serialization.serialize import net.corda.djvm.rewiring.SandboxClassLoader import net.corda.node.djvm.AttachmentBuilder @@ -19,14 +20,30 @@ class AttachmentFactory( fun toSandbox(attachments: List): Any? { val builder = taskFactory.apply(AttachmentBuilder::class.java) for (attachment in attachments) { - builder.apply(arrayOf( - serializer.deserialize(attachment.signerKeys.serialize()), - sandboxBasicInput.apply(attachment.size), - serializer.deserialize(attachment.id.serialize()), - attachment, - sandboxOpenAttachment - )) + builder.apply(generateArgsFor(attachment)) } return builder.apply(null) } + + private fun generateArgsFor(attachment: Attachment): Array { + val signerKeys = serializer.deserialize(attachment.signerKeys.serialize()) + val id = serializer.deserialize(attachment.id.serialize()) + val size = sandboxBasicInput.apply(attachment.size) + return if (attachment is ContractAttachment) { + val underlyingAttachment = attachment.attachment + arrayOf( + serializer.deserialize(underlyingAttachment.signerKeys.serialize()), + size, id, + underlyingAttachment, + sandboxOpenAttachment, + sandboxBasicInput.apply(attachment.contract), + sandboxBasicInput.apply(attachment.additionalContracts.toTypedArray()), + sandboxBasicInput.apply(attachment.uploader), + signerKeys, + sandboxBasicInput.apply(attachment.version) + ) + } else { + arrayOf(signerKeys, size, id, attachment, sandboxOpenAttachment) + } + } } diff --git a/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt b/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt index f1880fbf54..3263868aa8 100644 --- a/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt +++ b/node/src/main/kotlin/net/corda/node/internal/djvm/DeterministicVerifier.kt @@ -7,13 +7,14 @@ import net.corda.core.contracts.ComponentGroupEnum.SIGNERS_GROUP import net.corda.core.contracts.TransactionState import net.corda.core.contracts.TransactionVerificationException import net.corda.core.crypto.SecureHash -import net.corda.core.internal.ContractVerifier +import net.corda.core.internal.TransactionVerifier import net.corda.core.internal.Verifier import net.corda.core.internal.getNamesOfClassesImplementing import net.corda.core.serialization.SerializationCustomSerializer import net.corda.core.serialization.SerializationWhitelist import net.corda.core.serialization.serialize import net.corda.core.transactions.LedgerTransaction +import net.corda.core.utilities.contextLogger import net.corda.djvm.SandboxConfiguration import net.corda.djvm.execution.ExecutionSummary import net.corda.djvm.execution.IsolatedTask @@ -26,10 +27,14 @@ import java.util.function.Function import kotlin.collections.LinkedHashSet class DeterministicVerifier( - ltx: LedgerTransaction, - transactionClassLoader: ClassLoader, + private val ltx: LedgerTransaction, + private val transactionClassLoader: ClassLoader, private val sandboxConfiguration: SandboxConfiguration -) : Verifier(ltx, transactionClassLoader) { +) : Verifier { + private companion object { + private val logger = contextLogger() + } + /** * Read the whitelisted classes without using the [java.util.ServiceLoader] mechanism * because the whitelists themselves are untrusted. @@ -47,7 +52,7 @@ class DeterministicVerifier( } } - override fun verifyContracts() { + override fun verify() { val customSerializerNames = getNamesOfClassesImplementing(transactionClassLoader, SerializationCustomSerializer::class.java) val serializationWhitelistNames = getSerializationWhitelistNames(transactionClassLoader) val result = IsolatedTask(ltx.id.toString(), sandboxConfiguration).run(Function { classLoader -> @@ -113,7 +118,7 @@ class DeterministicVerifier( )) } - val verifier = taskFactory.apply(ContractVerifier::class.java) + val verifier = taskFactory.apply(TransactionVerifier::class.java) // Now execute the contract verifier task within the sandbox... verifier.apply(sandboxTx) @@ -128,7 +133,7 @@ class DeterministicVerifier( val sandboxEx = SandboxException( Message.getMessageFromException(this), result.identifier, - ClassSource.fromClassName(ContractVerifier::class.java.name), + ClassSource.fromClassName(TransactionVerifier::class.java.name), ExecutionSummary(result.costs), this ) From 30786fb6810215b4c317766961b79fba22fc4394 Mon Sep 17 00:00:00 2001 From: Ramzi El-Yafi Date: Mon, 31 Jan 2022 10:23:14 +0000 Subject: [PATCH 07/11] CORDA-4195 Fix attachment demo notarisation (#7050) --- samples/attachment-demo/build.gradle | 1 + .../kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt | 6 +++++- .../main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/samples/attachment-demo/build.gradle b/samples/attachment-demo/build.gradle index c3aeafa1b9..0e6000cbe2 100644 --- a/samples/attachment-demo/build.gradle +++ b/samples/attachment-demo/build.gradle @@ -77,6 +77,7 @@ def webTask = tasks.getByPath(':testing:testserver:testcapsule::assemble') task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask, webTask]) { ext.rpcUsers = [['username': "demo", 'password': "demo", 'permissions': ["StartFlow.net.corda.attachmentdemo.AttachmentDemoFlow", "InvokeRpc.partiesFromName", + "InvokeRpc.notaryPartyFromX500Name", "InvokeRpc.attachmentExists", "InvokeRpc.openAttachment", "InvokeRpc.uploadAttachment", diff --git a/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt b/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt index 290452c9de..b60e813471 100644 --- a/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt +++ b/samples/attachment-demo/src/integration-test/kotlin/net/corda/attachmentdemo/AttachmentDemoTest.kt @@ -5,10 +5,13 @@ import net.corda.core.utilities.getOrThrow import net.corda.node.services.Permissions.Companion.all import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.core.DUMMY_BANK_B_NAME +import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.driver import net.corda.testing.driver.internal.incrementalPortAllocation +import net.corda.testing.node.NotarySpec import net.corda.testing.node.User +import net.corda.testing.node.internal.DummyClusterSpec import net.corda.testing.node.internal.findCordapp import org.junit.Test import java.util.concurrent.CompletableFuture.supplyAsync @@ -21,7 +24,8 @@ class AttachmentDemoTest { driver(DriverParameters( portAllocation = incrementalPortAllocation(), startNodesInProcess = true, - cordappsForAllNodes = listOf(findCordapp("net.corda.attachmentdemo.contracts"), findCordapp("net.corda.attachmentdemo.workflows"))) + cordappsForAllNodes = listOf(findCordapp("net.corda.attachmentdemo.contracts"), findCordapp("net.corda.attachmentdemo.workflows")), + notarySpecs = listOf(NotarySpec(name = DUMMY_NOTARY_NAME, cluster = DummyClusterSpec(clusterSize = 1)))) ) { val demoUser = listOf(User("demo", "demo", setOf(all()))) val (nodeA, nodeB) = listOf( diff --git a/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt b/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt index ebe4d8e1e8..2851a3c654 100644 --- a/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt +++ b/samples/attachment-demo/src/main/kotlin/net/corda/attachmentdemo/AttachmentDemo.kt @@ -5,6 +5,7 @@ import net.corda.attachmentdemo.contracts.AttachmentContract import net.corda.attachmentdemo.workflows.AttachmentDemoFlow import net.corda.client.rpc.CordaRPCClient import net.corda.core.crypto.SecureHash +import net.corda.core.identity.CordaX500Name import net.corda.core.internal.Emoji import net.corda.core.internal.InputStreamAndHash import net.corda.core.messaging.CordaRPCOps @@ -65,7 +66,7 @@ fun sender(rpc: CordaRPCOps, numOfClearBytes: Int = 1024) { // default size 1K. private fun sender(rpc: CordaRPCOps, inputStream: InputStream, hash: SecureHash.SHA256) { // Get the identity key of the other side (the recipient). - val notaryParty = rpc.partiesFromName("Notary", false).firstOrNull() ?: throw IllegalArgumentException("Couldn't find notary party") + val notaryParty = rpc.notaryPartyFromX500Name(CordaX500Name.parse("O=Notary Service,L=Zurich,C=CH")) ?: throw IllegalArgumentException("Couldn't find notary party") val bankBParty = rpc.partiesFromName("Bank B", false).firstOrNull() ?: throw IllegalArgumentException("Couldn't find Bank B party") // Make sure we have the file in storage if (!rpc.attachmentExists(hash)) { From 76366398fe024d2b424a4968fac4bf42592bf4ec Mon Sep 17 00:00:00 2001 From: Adel El-Beik <48713346+adelel1@users.noreply.github.com> Date: Tue, 8 Feb 2022 10:32:12 +0000 Subject: [PATCH 08/11] =?UTF-8?q?ENT-6584:=20Move=20sending=20of=20events?= =?UTF-8?q?=20to=20finally=20block.=20This=20makes=20sure=20it=E2=80=A6=20?= =?UTF-8?q?(#4383)=20(#7057)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ENT-6584: Move sending of events to finally block. This makes sure it gets executed in event of an exception. --- .../internal/persistence/DatabaseTransaction.kt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/DatabaseTransaction.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/DatabaseTransaction.kt index 9b8ed573d2..0d69706eb1 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/DatabaseTransaction.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/persistence/DatabaseTransaction.kt @@ -112,12 +112,11 @@ class DatabaseTransaction( } finally { clearException() contextTransactionOrNull = outerTransaction - } - - if (outerTransaction == null) { - synchronized(this) { - closed = true - boundary.onNext(CordaPersistence.Boundary(id, committed)) + if (outerTransaction == null) { + synchronized(this) { + closed = true + boundary.onNext(CordaPersistence.Boundary(id, committed)) + } } } } From 0b8c46e1b2c5cf9938e69456b1a9b7b4b5a19fc1 Mon Sep 17 00:00:00 2001 From: Ronan Browne Date: Tue, 8 Feb 2022 16:22:02 +0000 Subject: [PATCH 09/11] ENT-6495: bump java base version (#7056) * ENT-6609: update base version in line with supported java versions * NOTICK: update java version --- docker/src/docker/Dockerfile | 4 ++-- docker/src/docker/Dockerfile-debug | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/src/docker/Dockerfile b/docker/src/docker/Dockerfile index d3d287a750..41be49ad20 100644 --- a/docker/src/docker/Dockerfile +++ b/docker/src/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM azul/zulu-openjdk:8u192 +FROM azul/zulu-openjdk:8u312 ## Add packages, clean cache, create dirs, create corda user and change ownership RUN apt-get update && \ @@ -63,4 +63,4 @@ COPY --chown=corda:corda starting-node.conf /opt/corda/starting-node.conf USER "corda" EXPOSE ${MY_P2P_PORT} ${MY_RPC_PORT} ${MY_RPC_ADMIN_PORT} WORKDIR /opt/corda -CMD ["run-corda"] \ No newline at end of file +CMD ["run-corda"] diff --git a/docker/src/docker/Dockerfile-debug b/docker/src/docker/Dockerfile-debug index 5b0c7bbb1f..b961b4570d 100644 --- a/docker/src/docker/Dockerfile-debug +++ b/docker/src/docker/Dockerfile-debug @@ -1,4 +1,4 @@ -FROM azul/zulu-openjdk:8u192 +FROM azul/zulu-openjdk:8u312 ## Add packages, clean cache, create dirs, create corda user and change ownership RUN apt-get update && \ From 7afb585ae2e232b7289d9c1b8f8e9477dd331543 Mon Sep 17 00:00:00 2001 From: Dan Newton Date: Fri, 11 Feb 2022 14:05:05 +0000 Subject: [PATCH 10/11] ENT-6676 Don't log SSH port if shell not installed (#7059) --- .../net/corda/node/internal/AbstractNode.kt | 8 ++++++-- .../net/corda/node/internal/NodeStartup.kt | 12 ++++++++++-- .../node/internal/shell/InteractiveShell.kt | 16 ++++++++++++---- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt index 623e434a27..7deb9ae1d4 100644 --- a/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt +++ b/node/src/main/kotlin/net/corda/node/internal/AbstractNode.kt @@ -687,10 +687,14 @@ abstract class AbstractNode(val configuration: NodeConfiguration, open fun startShell() { if (configuration.shouldInitCrashShell()) { + val isShellStarted = InteractiveShell.startShellIfInstalled(configuration, cordappLoader) configuration.sshd?.port?.let { - log.info("Binding Shell SSHD server on port $it.") + if (isShellStarted) { + log.info("Binding Shell SSHD server on port $it.") + } else { + log.info("SSH port defined but corda-shell is not installed in node's drivers directory") + } } - InteractiveShell.startShellIfInstalled(configuration, cordappLoader) } } diff --git a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt index 97d4e5a1d1..0e90920616 100644 --- a/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt +++ b/node/src/main/kotlin/net/corda/node/internal/NodeStartup.kt @@ -263,11 +263,19 @@ open class NodeStartup : NodeStartupLogging { Node.printBasicNodeInfo("Node for \"$name\" started up and registered in $elapsed sec") // Don't start the shell if there's no console attached. - if (node.configuration.shouldStartLocalShell()) { + val isShellStarted = if (node.configuration.shouldStartLocalShell()) { InteractiveShell.runLocalShellIfInstalled(node::stop) + } else { + false } if (node.configuration.shouldStartSSHDaemon()) { - Node.printBasicNodeInfo("SSH server listening on port", node.configuration.sshd!!.port.toString()) + if (isShellStarted) { + Node.printBasicNodeInfo("SSH server listening on port", node.configuration.sshd!!.port.toString()) + } else { + Node.printBasicNodeInfo( + "SSH server not started. SSH port is defined but the corda-shell is not installed in node's drivers directory" + ) + } } }, { th -> diff --git a/node/src/main/kotlin/net/corda/node/internal/shell/InteractiveShell.kt b/node/src/main/kotlin/net/corda/node/internal/shell/InteractiveShell.kt index 0a98a8e4ab..7952789813 100644 --- a/node/src/main/kotlin/net/corda/node/internal/shell/InteractiveShell.kt +++ b/node/src/main/kotlin/net/corda/node/internal/shell/InteractiveShell.kt @@ -17,28 +17,36 @@ object InteractiveShell { private const val RUN_LOCAL_SHELL_METHOD = "runLocalShell" private const val SET_USER_INFO_METHOD = "setUserInfo" - fun startShellIfInstalled(configuration: NodeConfiguration, cordappLoader: CordappLoader) { - if (isShellInstalled()) { + fun startShellIfInstalled(configuration: NodeConfiguration, cordappLoader: CordappLoader): Boolean { + return if (isShellInstalled()) { try { val shellConfiguration = configuration.toShellConfigMap() setUnsafeUsers(configuration) startShell(shellConfiguration, cordappLoader) + true } catch (e: Exception) { log.error("Shell failed to start", e) + false } + } else { + false } } /** * Only call this after [startShellIfInstalled] has been called or the required classes will not be loaded into the current classloader. */ - fun runLocalShellIfInstalled(onExit: () -> Unit = {}) { - if (isShellInstalled()) { + fun runLocalShellIfInstalled(onExit: () -> Unit = {}): Boolean { + return if (isShellInstalled()) { try { runLocalShell(onExit) + true } catch (e: Exception) { log.error("Shell failed to start", e) + false } + } else { + false } } From 2338f90e6406065bb90438541b4f003c3b477db8 Mon Sep 17 00:00:00 2001 From: Lajos Veres Date: Mon, 14 Feb 2022 10:09:36 +0000 Subject: [PATCH 11/11] LEDG-67 updating contrib links (#7036) --- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++---- CONTRIBUTING.md | 2 +- README.md | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 9922e009fe..48f0f7fcab 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -3,9 +3,9 @@ # PR Checklist: -- [ ] Have you run the unit, integration and smoke tests as described [here](https://docs.corda.net/head/testing.html)? -- [ ] If you added public APIs, did you write the JavaDocs? -- [ ] If the changes are of interest to application developers, have you added them to the [changelog](https://docs.corda.net/head/changelog.html) (`/docs/source/changelog.rst`), and potentially the [release notes](https://docs.corda.net/head/release-notes.html) (`/docs/source/release-notes.rst`)? -- [ ] If you are contributing for the first time, please read the [contributor agreement](https://docs.corda.net/head/contributing.html) now and add a comment to this pull request stating that your PR is in accordance with the [Developer's Certificate of Origin](https://docs.corda.net/head/contributing.html#merging-the-changes-back-into-corda). +- [ ] Have you run the unit, integration and smoke tests as described [here](https://docs.r3.com/en/platform/corda/4.8/open-source/testing.html)? +- [ ] If you added public APIs, did you write the JavaDocs/kdocs? +- [ ] If the changes are of interest to application developers, have you added them to the changelog, and potentially the [release notes](https://docs.corda.net/head/release-notes.html) (`https://docs.r3.com/en/platform/corda/4.8/open-source/release-notes.html`)? +- [ ] If you are contributing for the first time, please read the [contributor agreement](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html) now and add a comment to this pull request stating that your PR is in accordance with the [Developer's Certificate of Origin](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html#merging-the-changes-back-into-corda). Thanks for your code, it's appreciated! :) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 98a67e669c..da3fe3c032 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,4 +2,4 @@ Corda is an open-source project and contributions are welcome! -To find out how to contribute, please see our [contributing docs](https://docs.corda.net/head/contributing-index.html). +To find out how to contribute, please see our [contributing docs](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html). diff --git a/README.md b/README.md index 78915358e4..a84c2d5957 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Corda is an open source blockchain project, designed for business from the start Corda is an open-source project and contributions are welcome! -To find out how to contribute, please see our [contributing docs](https://docs.corda.net/head/contributing-index.html). +To find out how to contribute, please see our [contributing docs](https://docs.r3.com/en/platform/corda/4.8/open-source/contributing.html). ## License