diff --git a/.ci/api-current.txt b/.ci/api-current.txt index e0280f9d4f..393eb52413 100644 --- a/.ci/api-current.txt +++ b/.ci/api-current.txt @@ -4950,7 +4950,8 @@ public static final class net.corda.core.transactions.LedgerTransaction$InOutGro @CordaSerializable public final class net.corda.core.transactions.MissingContractAttachments extends net.corda.core.flows.FlowException public (java.util.List>) - public (java.util.List>, Integer) + public (java.util.List>, String) + public (java.util.List>, String, Integer) @NotNull public final java.util.List> getStates() ## diff --git a/core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt b/core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt index 407d00ecbc..cdb3aed810 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/MissingContractAttachments.kt @@ -16,7 +16,7 @@ import net.corda.core.serialization.CordaSerializable @KeepForDJVM class MissingContractAttachments @JvmOverloads -constructor(val states: List>, minimumRequiredContractClassVersion: Version? = null) : FlowException( +constructor(val states: List>, contractsClassName: String? = null, minimumRequiredContractClassVersion: Version? = null) : FlowException( "Cannot find contract attachments for " + - "${states.map { it.contract }.distinct()}${minimumRequiredContractClassVersion?.let { ", minimum required contract class version $minimumRequiredContractClassVersion"}}. " + + "${contractsClassName ?: states.map { it.contract }.distinct()}${minimumRequiredContractClassVersion?.let { ", minimum required contract class version $minimumRequiredContractClassVersion"}}. " + "See https://docs.corda.net/api-contract-constraints.html#debugging") diff --git a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt index e1d303e794..4dfdb95815 100644 --- a/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt +++ b/core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt @@ -468,7 +468,7 @@ open class TransactionBuilder( val minimumRequiredContractClassVersion = stateRefs?.map { services.loadContractAttachment(it).contractVersion }?.max() ?: DEFAULT_CORDAPP_VERSION return services.attachments.getLatestContractAttachments(contractClassName, minimumRequiredContractClassVersion).firstOrNull() - ?: throw MissingContractAttachments(states, minimumRequiredContractClassVersion) + ?: throw MissingContractAttachments(states, contractClassName, minimumRequiredContractClassVersion) } private fun useWhitelistedByZoneAttachmentConstraint(contractClassName: ContractClassName, networkParameters: NetworkParameters) = contractClassName in networkParameters.whitelistedContractImplementations.keys diff --git a/docs/source/api-contract-constraints.rst b/docs/source/api-contract-constraints.rst index 1d80cd6cd6..50fb351caa 100644 --- a/docs/source/api-contract-constraints.rst +++ b/docs/source/api-contract-constraints.rst @@ -1,3 +1,5 @@ +.. highlight:: kotlin + API: Contract Constraints ========================= @@ -337,7 +339,38 @@ common sources of ``MissingContractAttachments`` exceptions: Not setting CorDapp packages in tests ************************************* -You are running a test and have not specified the CorDapp packages to scan. See the instructions above. +You are running a test and have not specified the CorDapp packages to scan. +When using ``MockNetwork`` ensure you have provided a package containing the contract class in ``MockNetworkParameters``. See :doc:`api-testing`. + +Similarly package names need to be provided when testing using ``DriverDSl``. ``DriverParameters`` has a property ``cordappsForAllNodes`` (Kotlin) +or method ``withCordappsForAllNodes`` in Java. Pass the collection of ``TestCordapp`` created by utility method ``TestCordapp.findCordapp(String)``. + +Example of creation of two Cordapps with Finance App Flows and Finance App Contracts in Kotlin: + + .. sourcecode:: kotlin + + Driver.driver(DriverParameters(cordappsForAllNodes = listOf(TestCordapp.findCordapp("net.corda.finance.schemas"), + TestCordapp.findCordapp("net.corda.finance.flows"))) { + // Your test code goes here + }) + +The same example in Java: + + .. sourcecode:: java + + Driver.driver(new DriverParameters() + .withCordappsForAllNodes(Arrays.asList(TestCordapp.findCordapp("net.corda.finance.schemas"), + TestCordapp.findCordapp("net.corda.finance.flows"))), dsl -> { + // Your test code goes here + }); + + +Staring a node missing CorDapp(s) +********************************* + +When running the Corda node ensure all CordDapp JARs are placed in ``cordapps`` directory of each node. +By default Gradle Cordform task ``deployNodes`` copies all JARs if CorDapps to deploy are specified. +See :doc:`generating-a-node` for detailed instructions. Wrong fully-qualified contract name *********************************** diff --git a/docs/source/api-testing.rst b/docs/source/api-testing.rst index ae261a0e08..9a6004bdb4 100644 --- a/docs/source/api-testing.rst +++ b/docs/source/api-testing.rst @@ -33,7 +33,8 @@ A ``MockNetwork`` is created as follows: :end-before: DOCEND 1 The ``MockNetwork`` requires at a minimum a list of CorDapps to be installed on each ``StartedMockNode``. The CorDapps are looked up on the -classpath by package name, using ``TestCordapp.findCordapp``. +classpath by package name, using ``TestCordapp.findCordapp``. ``TestCordapp.findCordapp`` scans the current classpath to find the CorDapp that contains the given package. +This includes all the associated CorDapp metadata present in its MANIFEST. ``MockNetworkParameters`` provides other properties for the network which can be tweaked. They default to sensible values if not specified.