mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +00:00
CORDA-2149 CorDapp Contract and Workflow version identifiers (#4363)
* Implementation of Contract and Workflow attribute identifiers. * Fixes following rebase from master. * Fix broken JUnit test. * Fix broken JUnit test. * Fix broken JUnit test. * Added missing constants. * Further clean-up. * Updated documentation. * Added changelog entry. * Updated all samples (using new Gradle Plugin 4.0.37 functionality) * Temporarily resolve gradle plugins from latest published snapshot. * Temporarily resolve gradle plugins from latest published snapshot. * Updates following feedback from PR review. * Move constants into CordappInfo companion object. * Contract and Workflow attribute `version` to `versionId` (as version is a reserved gradle variable) * Clarified warning message on incorrect version identifier. * Align version identifier processing logic with gradle cordapp plugin. * Updated comment. * Minor fixes following rebase from master. * Fixed broken unit test. * Improved exception reporting. * Update to use 4.0.37 of Gradle Plugins. * Added support for combined Contract and Workflow CorDapp info. * Updated following discussions with Shams + cleanup. * Updated following Shams PR review. * Minor API improvements. * Added missing cordapp info causing deployNodes to fail.
This commit is contained in:
parent
767e37a34e
commit
9cdda3bd77
@ -1,4 +1,4 @@
|
|||||||
gradlePluginsVersion=4.0.36
|
gradlePluginsVersion=4.0.37
|
||||||
kotlinVersion=1.2.71
|
kotlinVersion=1.2.71
|
||||||
# ***************************************************************#
|
# ***************************************************************#
|
||||||
# When incrementing platformVersion make sure to update #
|
# When incrementing platformVersion make sure to update #
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package net.corda.core.contracts
|
package net.corda.core.contracts
|
||||||
|
|
||||||
import net.corda.core.KeepForDJVM
|
import net.corda.core.KeepForDJVM
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,3 +4,8 @@ package net.corda.core.cordapp
|
|||||||
* Thrown if an exception occurs in accessing or parsing cordapp configuration
|
* Thrown if an exception occurs in accessing or parsing cordapp configuration
|
||||||
*/
|
*/
|
||||||
class CordappConfigException(msg: String, e: Throwable) : Exception(msg, e)
|
class CordappConfigException(msg: String, e: Throwable) : Exception(msg, e)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown if an exception occurs whilst parsing version identifiers within cordapp configuration
|
||||||
|
*/
|
||||||
|
class CordappInvalidVersionException(msg: String) : Exception(msg)
|
@ -4,6 +4,10 @@ import net.corda.core.DeleteForDJVM
|
|||||||
import net.corda.core.DoNotImplement
|
import net.corda.core.DoNotImplement
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.UNKNOWN_VALUE
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.parseVersion
|
||||||
import net.corda.core.schemas.MappedSchema
|
import net.corda.core.schemas.MappedSchema
|
||||||
import net.corda.core.serialization.SerializationCustomSerializer
|
import net.corda.core.serialization.SerializationCustomSerializer
|
||||||
import net.corda.core.serialization.SerializationWhitelist
|
import net.corda.core.serialization.SerializationWhitelist
|
||||||
@ -47,5 +51,66 @@ interface Cordapp {
|
|||||||
val allFlows: List<Class<out FlowLogic<*>>>
|
val allFlows: List<Class<out FlowLogic<*>>>
|
||||||
val jarPath: URL
|
val jarPath: URL
|
||||||
val cordappClasses: List<String>
|
val cordappClasses: List<String>
|
||||||
|
val info: Info
|
||||||
val jarHash: SecureHash.SHA256
|
val jarHash: SecureHash.SHA256
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CorDapp's information, including vendor and version.
|
||||||
|
*
|
||||||
|
* @property shortName Cordapp's shortName
|
||||||
|
* @property vendor Cordapp's vendor
|
||||||
|
* @property version Cordapp's version
|
||||||
|
*/
|
||||||
|
@DoNotImplement
|
||||||
|
interface Info {
|
||||||
|
val shortName: String
|
||||||
|
val vendor: String
|
||||||
|
val version: String
|
||||||
|
val licence: String
|
||||||
|
val minimumPlatformVersion: Int
|
||||||
|
val targetPlatformVersion: Int
|
||||||
|
|
||||||
|
fun hasUnknownFields(): Boolean
|
||||||
|
|
||||||
|
/** CorDapps that do not separate Contracts and Flows into separate jars (pre Corda 4) */
|
||||||
|
data class Default(override val shortName: String, override val vendor: String, override val version: String, override val minimumPlatformVersion: Int, override val targetPlatformVersion: Int, override val licence: String = UNKNOWN_VALUE)
|
||||||
|
: Info {
|
||||||
|
override fun hasUnknownFields(): Boolean = arrayOf(shortName, vendor, version).any { it == UNKNOWN_VALUE }
|
||||||
|
override fun toString() = "CorDapp $shortName version $version by $vendor with licence $licence"
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A Contract CorDapp contains contract definitions (state, commands) and verification logic */
|
||||||
|
data class Contract(override val shortName: String, override val vendor: String, val versionId: Int, override val licence: String, override val minimumPlatformVersion: Int, override val targetPlatformVersion: Int)
|
||||||
|
: Info {
|
||||||
|
override val version: String
|
||||||
|
get() = versionId.toString()
|
||||||
|
override fun toString() = "Contract CorDapp: $shortName version $version by vendor $vendor with licence $licence"
|
||||||
|
override fun hasUnknownFields(): Boolean = arrayOf(shortName, vendor, licence).any { it == UNKNOWN_VALUE }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A Workflow CorDapp contains flows and services used to implement business transactions using contracts and states persisted to the immutable ledger */
|
||||||
|
data class Workflow(override val shortName: String, override val vendor: String, val versionId: Int, override val licence: String, override val minimumPlatformVersion: Int, override val targetPlatformVersion: Int)
|
||||||
|
: Info {
|
||||||
|
override val version: String
|
||||||
|
get() = versionId.toString()
|
||||||
|
override fun toString() = "Workflow CorDapp: $shortName version $version by vendor $vendor with licence $licence"
|
||||||
|
override fun hasUnknownFields(): Boolean = arrayOf(shortName, vendor, licence).any { it == UNKNOWN_VALUE }
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A CorDapp that includes both Contract and Workflow classes (not recommended) */
|
||||||
|
// TODO: future work in Gradle cordapp plugins to enforce separation of Contract and Workflow classes into separate jars
|
||||||
|
data class ContractAndWorkflow(val contract: Contract, val workflow: Workflow, override val minimumPlatformVersion: Int, override val targetPlatformVersion: Int)
|
||||||
|
: Info {
|
||||||
|
override val shortName: String
|
||||||
|
get() = "Contract: ${contract.shortName}, Workflow: ${workflow.shortName}"
|
||||||
|
override val vendor: String
|
||||||
|
get() = "Contract: ${contract.vendor}, Workflow: ${workflow.vendor}"
|
||||||
|
override val licence: String
|
||||||
|
get() = "Contract: ${contract.licence}, Workflow: ${workflow.licence}"
|
||||||
|
override val version: String
|
||||||
|
get() = "Contract: ${contract.versionId}, Workflow: ${workflow.versionId}"
|
||||||
|
override fun toString() = "Combined CorDapp: $contract, $workflow"
|
||||||
|
override fun hasUnknownFields(): Boolean = contract.hasUnknownFields() || workflow.hasUnknownFields()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
package net.corda.core.cordapp
|
|
||||||
|
|
||||||
const val CORDAPP_CONTRACT_VERSION = "Implementation-Version" //TODO will be changed to "Corda-Contract-Version"
|
|
||||||
|
|
||||||
const val DEFAULT_CORDAPP_VERSION: Int = 1
|
|
@ -2,6 +2,7 @@ package net.corda.core.internal.cordapp
|
|||||||
|
|
||||||
import net.corda.core.DeleteForDJVM
|
import net.corda.core.DeleteForDJVM
|
||||||
import net.corda.core.cordapp.Cordapp
|
import net.corda.core.cordapp.Cordapp
|
||||||
|
import net.corda.core.cordapp.CordappInvalidVersionException
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.internal.notary.NotaryService
|
import net.corda.core.internal.notary.NotaryService
|
||||||
@ -25,7 +26,7 @@ data class CordappImpl(
|
|||||||
override val customSchemas: Set<MappedSchema>,
|
override val customSchemas: Set<MappedSchema>,
|
||||||
override val allFlows: List<Class<out FlowLogic<*>>>,
|
override val allFlows: List<Class<out FlowLogic<*>>>,
|
||||||
override val jarPath: URL,
|
override val jarPath: URL,
|
||||||
val info: Info,
|
override val info: Cordapp.Info,
|
||||||
override val jarHash: SecureHash.SHA256,
|
override val jarHash: SecureHash.SHA256,
|
||||||
val notaryService: Class<out NotaryService>?,
|
val notaryService: Class<out NotaryService>?,
|
||||||
/** Indicates whether the CorDapp is loaded from external sources, or generated on node startup (virtual). */
|
/** Indicates whether the CorDapp is loaded from external sources, or generated on node startup (virtual). */
|
||||||
@ -34,8 +35,42 @@ data class CordappImpl(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun jarName(url: URL): String = url.toPath().fileName.toString().removeSuffix(".jar")
|
fun jarName(url: URL): String = url.toPath().fileName.toString().removeSuffix(".jar")
|
||||||
}
|
|
||||||
|
|
||||||
|
/** CorDapp manifest entries */
|
||||||
|
const val CORDAPP_CONTRACT_NAME = "Cordapp-Contract-Name"
|
||||||
|
const val CORDAPP_CONTRACT_VERSION = "Cordapp-Contract-Version"
|
||||||
|
const val CORDAPP_CONTRACT_VENDOR = "Cordapp-Contract-Vendor"
|
||||||
|
const val CORDAPP_CONTRACT_LICENCE = "Cordapp-Contract-Licence"
|
||||||
|
|
||||||
|
const val CORDAPP_WORKFLOW_NAME = "Cordapp-Workflow-Name"
|
||||||
|
const val CORDAPP_WORKFLOW_VERSION = "Cordapp-Workflow-Version"
|
||||||
|
const val CORDAPP_WORKFLOW_VENDOR = "Cordapp-Workflow-Vendor"
|
||||||
|
const val CORDAPP_WORKFLOW_LICENCE = "Cordapp-Workflow-Licence"
|
||||||
|
|
||||||
|
const val TARGET_PLATFORM_VERSION = "Target-Platform-Version"
|
||||||
|
const val MIN_PLATFORM_VERSION = "Min-Platform-Version"
|
||||||
|
|
||||||
|
const val UNKNOWN_VALUE = "Unknown"
|
||||||
|
const val DEFAULT_CORDAPP_VERSION = 1
|
||||||
|
|
||||||
|
/** used for CorDapps that do not explicitly define attributes */
|
||||||
|
val UNKNOWN = Cordapp.Info.Default(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE,1, 1)
|
||||||
|
|
||||||
|
/** Helper method for version identifier parsing */
|
||||||
|
fun parseVersion(versionStr: String?, attributeName: String): Int {
|
||||||
|
if (versionStr == null)
|
||||||
|
throw CordappInvalidVersionException("Target versionId attribute $attributeName not specified. Please specify a whole number starting from 1.")
|
||||||
|
return try {
|
||||||
|
val version = versionStr.toInt()
|
||||||
|
if (version < 1) {
|
||||||
|
throw CordappInvalidVersionException("Target versionId ($versionStr) for attribute $attributeName must not be smaller than 1.")
|
||||||
|
}
|
||||||
|
return version
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
throw CordappInvalidVersionException("Version identifier ($versionStr) for attribute $attributeName must be a whole number starting from 1.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* An exhaustive list of all classes relevant to the node within this CorDapp
|
* An exhaustive list of all classes relevant to the node within this CorDapp
|
||||||
*
|
*
|
||||||
@ -45,14 +80,4 @@ data class CordappImpl(
|
|||||||
val classList = rpcFlows + initiatedFlows + services + serializationWhitelists.map { javaClass } + notaryService
|
val classList = rpcFlows + initiatedFlows + services + serializationWhitelists.map { javaClass } + notaryService
|
||||||
classList.mapNotNull { it?.name } + contractClassNames
|
classList.mapNotNull { it?.name } + contractClassNames
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Why a seperate Info class and not just have the fields directly in CordappImpl?
|
|
||||||
data class Info(val shortName: String, val vendor: String, val version: String, val minimumPlatformVersion: Int, val targetPlatformVersion: Int) {
|
|
||||||
companion object {
|
|
||||||
const val UNKNOWN_VALUE = "Unknown"
|
|
||||||
val UNKNOWN = Info(UNKNOWN_VALUE, UNKNOWN_VALUE, UNKNOWN_VALUE, 1, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hasUnknownFields(): Boolean = arrayOf(shortName, vendor, version).any { it == UNKNOWN_VALUE }
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.core.internal.cordapp
|
package net.corda.core.internal.cordapp
|
||||||
|
|
||||||
|
import net.corda.core.cordapp.Cordapp
|
||||||
import net.corda.core.internal.PLATFORM_VERSION
|
import net.corda.core.internal.PLATFORM_VERSION
|
||||||
import net.corda.core.internal.VisibleForTesting
|
import net.corda.core.internal.VisibleForTesting
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
@ -10,10 +11,10 @@ import java.util.concurrent.ConcurrentHashMap
|
|||||||
*/
|
*/
|
||||||
object CordappInfoResolver {
|
object CordappInfoResolver {
|
||||||
private val logger = loggerFor<CordappInfoResolver>()
|
private val logger = loggerFor<CordappInfoResolver>()
|
||||||
private val cordappClasses: ConcurrentHashMap<String, Set<CordappImpl.Info>> = ConcurrentHashMap()
|
private val cordappClasses: ConcurrentHashMap<String, Set<Cordapp.Info>> = ConcurrentHashMap()
|
||||||
|
|
||||||
// TODO Use the StackWalker API once we migrate to Java 9+
|
// TODO Use the StackWalker API once we migrate to Java 9+
|
||||||
private var cordappInfoResolver: () -> CordappImpl.Info? = {
|
private var cordappInfoResolver: () -> Cordapp.Info? = {
|
||||||
Exception().stackTrace
|
Exception().stackTrace
|
||||||
.mapNotNull { cordappClasses[it.className] }
|
.mapNotNull { cordappClasses[it.className] }
|
||||||
// If there is more than one cordapp registered for a class name we can't determine the "correct" one and return null.
|
// If there is more than one cordapp registered for a class name we can't determine the "correct" one and return null.
|
||||||
@ -25,7 +26,7 @@ object CordappInfoResolver {
|
|||||||
* This could happen when trying to run different versions of the same CorDapp on the same node.
|
* This could happen when trying to run different versions of the same CorDapp on the same node.
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun register(classes: List<String>, cordapp: CordappImpl.Info) {
|
fun register(classes: List<String>, cordapp: Cordapp.Info) {
|
||||||
classes.forEach {
|
classes.forEach {
|
||||||
if (cordappClasses.containsKey(it)) {
|
if (cordappClasses.containsKey(it)) {
|
||||||
logger.warn("More than one CorDapp registered for $it.")
|
logger.warn("More than one CorDapp registered for $it.")
|
||||||
@ -45,7 +46,7 @@ object CordappInfoResolver {
|
|||||||
* @return Information about the CorDapp from which the invoker is called, null if called outside a CorDapp or the
|
* @return Information about the CorDapp from which the invoker is called, null if called outside a CorDapp or the
|
||||||
* calling CorDapp cannot be reliably determined.
|
* calling CorDapp cannot be reliably determined.
|
||||||
*/
|
*/
|
||||||
val currentCordappInfo: CordappImpl.Info? get() = cordappInfoResolver()
|
val currentCordappInfo: Cordapp.Info? get() = cordappInfoResolver()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the target version of the current calling CorDapp. Defaults to the current platform version if there isn't one.
|
* Returns the target version of the current calling CorDapp. Defaults to the current platform version if there isn't one.
|
||||||
@ -60,12 +61,13 @@ object CordappInfoResolver {
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
fun <T> withCordappInfo(shortName: String = "CordappInfoResolver.withCordappInfo",
|
fun <T> withCordappInfo(shortName: String = "CordappInfoResolver.withCordappInfo",
|
||||||
vendor: String = "Corda",
|
vendor: String = "Corda",
|
||||||
version: String = "1.0",
|
version: String = "1",
|
||||||
|
licence: String = "Apache",
|
||||||
minimumPlatformVersion: Int = 1,
|
minimumPlatformVersion: Int = 1,
|
||||||
targetPlatformVersion: Int = PLATFORM_VERSION,
|
targetPlatformVersion: Int = PLATFORM_VERSION,
|
||||||
block: () -> T): T {
|
block: () -> T): T {
|
||||||
val currentResolver = cordappInfoResolver
|
val currentResolver = cordappInfoResolver
|
||||||
cordappInfoResolver = { CordappImpl.Info(shortName, vendor, version, minimumPlatformVersion, targetPlatformVersion) }
|
cordappInfoResolver = { Cordapp.Info.Default(shortName, vendor, version, minimumPlatformVersion, targetPlatformVersion, licence) }
|
||||||
try {
|
try {
|
||||||
return block()
|
return block()
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
package net.corda.core.internal.cordapp
|
||||||
|
|
||||||
|
import net.corda.core.cordapp.Cordapp
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_LICENCE
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_NAME
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VENDOR
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_LICENCE
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_NAME
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_VENDOR
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.MIN_PLATFORM_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.TARGET_PLATFORM_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.UNKNOWN_VALUE
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.parseVersion
|
||||||
|
import java.util.jar.Attributes
|
||||||
|
import java.util.jar.Manifest
|
||||||
|
|
||||||
|
operator fun Manifest.set(key: String, value: String): String? {
|
||||||
|
return mainAttributes.putValue(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun Manifest.set(key: Attributes.Name, value: String): Any? {
|
||||||
|
return mainAttributes.put(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun Manifest.get(key: String): String? = mainAttributes.getValue(key)
|
||||||
|
|
||||||
|
val Manifest.targetPlatformVersion: Int
|
||||||
|
get() {
|
||||||
|
val minPlatformVersion = this[MIN_PLATFORM_VERSION]?.toIntOrNull() ?: 1
|
||||||
|
return this[TARGET_PLATFORM_VERSION]?.toIntOrNull() ?: minPlatformVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Manifest.toCordappInfo(defaultName: String): Cordapp.Info {
|
||||||
|
|
||||||
|
/** Common attributes */
|
||||||
|
val minPlatformVersion = this[MIN_PLATFORM_VERSION]?.toIntOrNull() ?: 1
|
||||||
|
val targetPlatformVersion = this[TARGET_PLATFORM_VERSION]?.toIntOrNull() ?: minPlatformVersion
|
||||||
|
|
||||||
|
/** new identifiers (Corda 4) */
|
||||||
|
// is it a Contract Jar?
|
||||||
|
val contractInfo =
|
||||||
|
if (this[CORDAPP_CONTRACT_NAME] != null) {
|
||||||
|
Cordapp.Info.Contract(shortName = this[CORDAPP_CONTRACT_NAME] ?: defaultName,
|
||||||
|
vendor = this[CORDAPP_CONTRACT_VENDOR] ?: UNKNOWN_VALUE,
|
||||||
|
versionId = parseVersion(this[CORDAPP_CONTRACT_VERSION], CORDAPP_CONTRACT_VERSION),
|
||||||
|
licence = this[CORDAPP_CONTRACT_LICENCE] ?: UNKNOWN_VALUE,
|
||||||
|
minimumPlatformVersion = minPlatformVersion,
|
||||||
|
targetPlatformVersion = targetPlatformVersion
|
||||||
|
)
|
||||||
|
} else null
|
||||||
|
|
||||||
|
// is it a Workflow (flows and services) Jar?
|
||||||
|
val workflowInfo =
|
||||||
|
if (this[CORDAPP_WORKFLOW_NAME] != null) {
|
||||||
|
Cordapp.Info.Workflow(shortName = this[CORDAPP_WORKFLOW_NAME] ?: defaultName,
|
||||||
|
vendor = this[CORDAPP_WORKFLOW_VENDOR] ?: UNKNOWN_VALUE,
|
||||||
|
versionId = parseVersion(this[CORDAPP_WORKFLOW_VERSION],CORDAPP_WORKFLOW_VERSION),
|
||||||
|
licence = this[CORDAPP_WORKFLOW_LICENCE] ?: UNKNOWN_VALUE,
|
||||||
|
minimumPlatformVersion = minPlatformVersion,
|
||||||
|
targetPlatformVersion = targetPlatformVersion
|
||||||
|
)
|
||||||
|
} else null
|
||||||
|
|
||||||
|
// combined Contract and Workflow Jar ?
|
||||||
|
if (contractInfo != null && workflowInfo != null) {
|
||||||
|
return Cordapp.Info.ContractAndWorkflow(contractInfo, workflowInfo, minPlatformVersion, targetPlatformVersion)
|
||||||
|
}
|
||||||
|
else if (contractInfo != null) return contractInfo
|
||||||
|
else if (workflowInfo != null) return workflowInfo
|
||||||
|
|
||||||
|
/** need to maintain backwards compatibility so use old identifiers if existent */
|
||||||
|
val shortName = this["Name"] ?: defaultName
|
||||||
|
val vendor = this["Implementation-Vendor"] ?: UNKNOWN_VALUE
|
||||||
|
val version = this["Implementation-Version"] ?: UNKNOWN_VALUE
|
||||||
|
return Cordapp.Info.Default(
|
||||||
|
shortName = shortName,
|
||||||
|
vendor = vendor,
|
||||||
|
version = version,
|
||||||
|
licence = UNKNOWN_VALUE,
|
||||||
|
minimumPlatformVersion = minPlatformVersion,
|
||||||
|
targetPlatformVersion = targetPlatformVersion
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,12 @@
|
|||||||
package net.corda.core.internal.rules
|
package net.corda.core.internal.rules
|
||||||
|
|
||||||
import net.corda.core.contracts.ContractState
|
import net.corda.core.contracts.ContractState
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.internal.cordapp.targetPlatformVersion
|
||||||
import net.corda.core.utilities.warnOnce
|
import net.corda.core.utilities.warnOnce
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.jar.JarInputStream
|
import java.util.jar.JarInputStream
|
||||||
import java.util.jar.Manifest
|
|
||||||
|
|
||||||
// This file provides rules that depend on the targetVersion of the current Contract or Flow.
|
// This file provides rules that depend on the targetVersion of the current Contract or Flow.
|
||||||
// Rules defined in this package are automatically removed from the DJVM in core-deterministic,
|
// Rules defined in this package are automatically removed from the DJVM in core-deterministic,
|
||||||
@ -48,8 +47,3 @@ object StateContractValidationEnforcementRule {
|
|||||||
return targetVersion >= 4
|
return targetVersion >= 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val Manifest.targetPlatformVersion: Int get() {
|
|
||||||
val minPlatformVersion = mainAttributes.getValue("Min-Platform-Version")?.toInt() ?: 1
|
|
||||||
return mainAttributes.getValue("Target-Platform-Version")?.toInt() ?: minPlatformVersion
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ import net.corda.core.contracts.TransactionVerificationException.OverlappingAtta
|
|||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.VisibleForTesting
|
import net.corda.core.internal.VisibleForTesting
|
||||||
|
import net.corda.core.internal.cordapp.targetPlatformVersion
|
||||||
import net.corda.core.internal.createSimpleCache
|
import net.corda.core.internal.createSimpleCache
|
||||||
import net.corda.core.internal.isUploaderTrusted
|
import net.corda.core.internal.isUploaderTrusted
|
||||||
import net.corda.core.internal.toSynchronised
|
import net.corda.core.internal.toSynchronised
|
||||||
@ -18,7 +19,6 @@ import java.io.ByteArrayOutputStream
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.*
|
import java.net.*
|
||||||
import java.util.jar.Manifest
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom ClassLoader that knows how to load classes from a set of attachments. The attachments themselves only
|
* A custom ClassLoader that knows how to load classes from a set of attachments. The attachments themselves only
|
||||||
@ -108,14 +108,6 @@ class AttachmentsClassLoader(attachments: List<Attachment>, parent: ClassLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This was reused from: https://github.com/corda/corda/pull/4240.
|
|
||||||
// TODO - Once that is merged it should be extracted to a utility.
|
|
||||||
private val Manifest.targetPlatformVersion: Int
|
|
||||||
get() {
|
|
||||||
val minPlatformVersion = mainAttributes.getValue("Min-Platform-Version")?.toInt() ?: 1
|
|
||||||
return mainAttributes.getValue("Target-Platform-Version")?.toInt() ?: minPlatformVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
private fun readAttachment(attachment: Attachment, filepath: String): ByteArray {
|
private fun readAttachment(attachment: Attachment, filepath: String): ByteArray {
|
||||||
ByteArrayOutputStream().use {
|
ByteArrayOutputStream().use {
|
||||||
|
@ -6,11 +6,11 @@ import net.corda.core.contracts.*
|
|||||||
import net.corda.core.contracts.TransactionVerificationException.TransactionContractConflictException
|
import net.corda.core.contracts.TransactionVerificationException.TransactionContractConflictException
|
||||||
import net.corda.core.contracts.TransactionVerificationException.TransactionRequiredContractUnspecifiedException
|
import net.corda.core.contracts.TransactionVerificationException.TransactionRequiredContractUnspecifiedException
|
||||||
import net.corda.core.contracts.Version
|
import net.corda.core.contracts.Version
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.isFulfilledBy
|
import net.corda.core.crypto.isFulfilledBy
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.internal.rules.StateContractValidationEnforcementRule
|
import net.corda.core.internal.rules.StateContractValidationEnforcementRule
|
||||||
import net.corda.core.internal.uncheckedCast
|
import net.corda.core.internal.uncheckedCast
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
|
@ -4,11 +4,11 @@ import co.paralleluniverse.strands.Strand
|
|||||||
import net.corda.core.CordaInternal
|
import net.corda.core.CordaInternal
|
||||||
import net.corda.core.DeleteForDJVM
|
import net.corda.core.DeleteForDJVM
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.contracts.ContractAttachment.Companion.getContractVersion
|
import net.corda.core.contracts.ContractAttachment.Companion.getContractVersion
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
import net.corda.core.node.ServicesForResolution
|
import net.corda.core.node.ServicesForResolution
|
||||||
|
@ -7,13 +7,12 @@ import net.corda.core.contracts.*
|
|||||||
import net.corda.core.contracts.ComponentGroupEnum.COMMANDS_GROUP
|
import net.corda.core.contracts.ComponentGroupEnum.COMMANDS_GROUP
|
||||||
import net.corda.core.contracts.ComponentGroupEnum.OUTPUTS_GROUP
|
import net.corda.core.contracts.ComponentGroupEnum.OUTPUTS_GROUP
|
||||||
import net.corda.core.contracts.ContractAttachment.Companion.getContractVersion
|
import net.corda.core.contracts.ContractAttachment.Companion.getContractVersion
|
||||||
import net.corda.core.contracts.Version
|
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.crypto.*
|
import net.corda.core.crypto.*
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
import net.corda.core.internal.Emoji
|
import net.corda.core.internal.Emoji
|
||||||
import net.corda.core.internal.SerializedStateAndRef
|
import net.corda.core.internal.SerializedStateAndRef
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.internal.createComponentGroups
|
import net.corda.core.internal.createComponentGroups
|
||||||
import net.corda.core.node.NetworkParameters
|
import net.corda.core.node.NetworkParameters
|
||||||
import net.corda.core.node.ServiceHub
|
import net.corda.core.node.ServiceHub
|
||||||
|
@ -4,19 +4,22 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import com.natpryce.hamkrest.*
|
import com.natpryce.hamkrest.*
|
||||||
import com.natpryce.hamkrest.assertion.assert
|
import com.natpryce.hamkrest.assertion.assert
|
||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.testing.internal.matchers.flow.willReturn
|
|
||||||
import net.corda.testing.internal.matchers.flow.willThrow
|
|
||||||
import net.corda.core.flows.mixins.WithMockNet
|
import net.corda.core.flows.mixins.WithMockNet
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.FetchAttachmentsFlow
|
import net.corda.core.internal.FetchAttachmentsFlow
|
||||||
import net.corda.core.internal.FetchDataFlow
|
import net.corda.core.internal.FetchDataFlow
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.internal.hash
|
import net.corda.core.internal.hash
|
||||||
import net.corda.node.services.persistence.NodeAttachmentService
|
import net.corda.node.services.persistence.NodeAttachmentService
|
||||||
import net.corda.testing.core.*
|
import net.corda.testing.core.ALICE_NAME
|
||||||
|
import net.corda.testing.core.BOB_NAME
|
||||||
|
import net.corda.testing.core.makeUnique
|
||||||
|
import net.corda.testing.core.singleIdentity
|
||||||
import net.corda.testing.internal.fakeAttachment
|
import net.corda.testing.internal.fakeAttachment
|
||||||
|
import net.corda.testing.internal.matchers.flow.willReturn
|
||||||
|
import net.corda.testing.internal.matchers.flow.willThrow
|
||||||
import net.corda.testing.node.internal.InternalMockNetwork
|
import net.corda.testing.node.internal.InternalMockNetwork
|
||||||
import net.corda.testing.node.internal.InternalMockNodeParameters
|
import net.corda.testing.node.internal.InternalMockNodeParameters
|
||||||
import net.corda.testing.node.internal.TestStartedNode
|
import net.corda.testing.node.internal.TestStartedNode
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.core.internal.cordapp
|
package net.corda.core.internal.cordapp
|
||||||
|
|
||||||
|
import net.corda.core.cordapp.Cordapp
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
@ -17,7 +18,7 @@ class CordappInfoResolverTest {
|
|||||||
fun `the correct cordapp resolver is used after calling withCordappInfo`() {
|
fun `the correct cordapp resolver is used after calling withCordappInfo`() {
|
||||||
val defaultTargetVersion = 222
|
val defaultTargetVersion = 222
|
||||||
|
|
||||||
CordappInfoResolver.register(listOf(javaClass.name), CordappImpl.Info("test", "test", "2", 3, defaultTargetVersion))
|
CordappInfoResolver.register(listOf(javaClass.name), Cordapp.Info.Default("test", "test", "2", 3, defaultTargetVersion))
|
||||||
assertEquals(defaultTargetVersion, CordappInfoResolver.currentTargetVersion)
|
assertEquals(defaultTargetVersion, CordappInfoResolver.currentTargetVersion)
|
||||||
|
|
||||||
val expectedTargetVersion = 555
|
val expectedTargetVersion = 555
|
||||||
@ -30,8 +31,8 @@ class CordappInfoResolverTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when more than one cordapp is registered for the same class, the resolver returns null`() {
|
fun `when more than one cordapp is registered for the same class, the resolver returns null`() {
|
||||||
CordappInfoResolver.register(listOf(javaClass.name), CordappImpl.Info("test", "test", "2", 3, 222))
|
CordappInfoResolver.register(listOf(javaClass.name), Cordapp.Info.Default("test", "test", "2", 3, 222))
|
||||||
CordappInfoResolver.register(listOf(javaClass.name), CordappImpl.Info("test1", "test1", "1", 2, 456))
|
CordappInfoResolver.register(listOf(javaClass.name), Cordapp.Info.Default("test1", "test1", "1", 2, 456))
|
||||||
assertThat(CordappInfoResolver.currentCordappInfo).isNull()
|
assertThat(CordappInfoResolver.currentCordappInfo).isNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import com.nhaarman.mockito_kotlin.doReturn
|
|||||||
import com.nhaarman.mockito_kotlin.whenever
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.cordapp.CordappProvider
|
import net.corda.core.cordapp.CordappProvider
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.crypto.CompositeKey
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
@ -12,6 +11,7 @@ import net.corda.core.internal.AbstractAttachment
|
|||||||
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
||||||
import net.corda.core.internal.PLATFORM_VERSION
|
import net.corda.core.internal.PLATFORM_VERSION
|
||||||
import net.corda.core.internal.RPC_UPLOADER
|
import net.corda.core.internal.RPC_UPLOADER
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.node.ServicesForResolution
|
import net.corda.core.node.ServicesForResolution
|
||||||
import net.corda.core.node.ZoneVersionTooLowException
|
import net.corda.core.node.ZoneVersionTooLowException
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
|
@ -18,6 +18,13 @@ Unreleased
|
|||||||
For a given contract class, the contract attachment of the output states must be of the same or newer version than the contract attachment of the input states.
|
For a given contract class, the contract attachment of the output states must be of the same or newer version than the contract attachment of the input states.
|
||||||
See :ref:`Contract attachment non-downgrade rule <contract_non-downgrade_rule_ref>` for further information.
|
See :ref:`Contract attachment non-downgrade rule <contract_non-downgrade_rule_ref>` for further information.
|
||||||
|
|
||||||
|
* Standardised CorDapp version identifiers in jar manifests (aligned with associated cordapp Gradle plugin changes).
|
||||||
|
Updated all samples to reflect new conventions.
|
||||||
|
|
||||||
|
* Introduction of unique CorDapp version identifiers in jar manifests for contract and flows/services CorDapps.
|
||||||
|
Updated all sample CorDapps to reflect new conventions.
|
||||||
|
See :ref:`CorDapp separation <cordapp_separation_ref>` for further information.
|
||||||
|
|
||||||
* Automatic Constraints propagation for hash-constrained states to signature-constrained states.
|
* Automatic Constraints propagation for hash-constrained states to signature-constrained states.
|
||||||
This allows Corda 4 signed CorDapps using signature constraints to consume existing hash constrained states generated
|
This allows Corda 4 signed CorDapps using signature constraints to consume existing hash constrained states generated
|
||||||
by unsigned CorDapps in previous versions of Corda.
|
by unsigned CorDapps in previous versions of Corda.
|
||||||
|
@ -368,13 +368,20 @@ There is an example project that demonstrates in ``samples`` called ``cordapp-co
|
|||||||
Minimum and target platform version
|
Minimum and target platform version
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
CorDapps can advertise their minimum and target platform version. The minimum platform version indicates that a node has to run at least this version in order to be able to run this CorDapp. The target platform version indicates that a CorDapp was tested with this version of the Corda Platform and should be run at this API level if possible. It provides a means of maintaining behavioural compatibility for the cases where the platform's behaviour has changed. These attributes are specified in the JAR manifest of the CorDapp, for example:
|
CorDapps can advertise their minimum and target platform version. The minimum platform version indicates that a node has to run at least this
|
||||||
|
version in order to be able to run this CorDapp. The target platform version indicates that a CorDapp was tested with this version of the Corda
|
||||||
|
Platform and should be run at this API level if possible. It provides a means of maintaining behavioural compatibility for the cases where the
|
||||||
|
platform's behaviour has changed. These attributes are specified in the JAR manifest of the CorDapp, for example:
|
||||||
|
|
||||||
.. sourcecode:: groovy
|
.. sourcecode:: groovy
|
||||||
|
|
||||||
'Min-Platform-Version': 4
|
'Min-Platform-Version': 4
|
||||||
'Target-Platform-Version': 4
|
'Target-Platform-Version': 4
|
||||||
|
|
||||||
|
**Defaults**
|
||||||
|
- ``Target-Platform-Version`` (mandatory) is a whole number and must comply with the rules mentioned above.
|
||||||
|
- ``Min-Platform-Version`` (optional) will default to 1 if not specified.
|
||||||
|
|
||||||
Using the `cordapp` Gradle plugin, this can be achieved by putting this in your CorDapp's `build.gradle`:
|
Using the `cordapp` Gradle plugin, this can be achieved by putting this in your CorDapp's `build.gradle`:
|
||||||
|
|
||||||
.. container:: codeset
|
.. container:: codeset
|
||||||
@ -382,23 +389,80 @@ Using the `cordapp` Gradle plugin, this can be achieved by putting this in your
|
|||||||
.. sourcecode:: groovy
|
.. sourcecode:: groovy
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
targetPlatformVersion 4
|
targetPlatformVersion 4
|
||||||
minimumPlatformVersion 4
|
minimumPlatformVersion 4
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Without using the `cordapp` plugin, you can achieve the same by modifying the jar task as shown in this example:
|
.. _cordapp_separation_ref:
|
||||||
|
|
||||||
|
Separation of CorDapp contracts, flows and services
|
||||||
|
---------------------------------------------------
|
||||||
|
It is recommended that **contract** code (states, commands, verification logic) be packaged separately from **business flows** (and associated services).
|
||||||
|
This decoupling enables *contracts* to evolve independently from the *flows* and *services* that use them. Contracts may even be specified and implemented by different
|
||||||
|
providers (eg. Corda currently ships with a cash financial contract which in turn is used in many other flows and many other CorDapps).
|
||||||
|
|
||||||
|
As of Corda 4, CorDapps can explicitly differentiate their type by specifying the following attributes in the JAR manifest:
|
||||||
|
|
||||||
|
.. sourcecode:: groovy
|
||||||
|
|
||||||
|
'Cordapp-Contract-Name'
|
||||||
|
'Cordapp-Contract-Version'
|
||||||
|
'Cordapp-Contract-Vendor'
|
||||||
|
'Cordapp-Contract-Licence'
|
||||||
|
|
||||||
|
'Cordapp-Workflow-Name'
|
||||||
|
'Cordapp-Workflow-Version'
|
||||||
|
'Cordapp-Workflow-Vendor'
|
||||||
|
'Cordapp-Workflow-Licence'
|
||||||
|
|
||||||
|
**Defaults**
|
||||||
|
|
||||||
|
``Cordapp-Contract-Name`` (optional) if specified, the following Contract related attributes are also used:
|
||||||
|
|
||||||
|
- ``Cordapp-Contract-Version`` (mandatory), must be a whole number starting from 1.
|
||||||
|
- ``Cordapp-Contract-Vendor`` (optional), defaults to UNKNOWN if not specified.
|
||||||
|
- ``Cordapp-Contract-Licence`` (optional), defaults to UNKNOWN if not specified.
|
||||||
|
|
||||||
|
``Cordapp-Workflow-Name`` (optional) if specified, the following Workflow related attributes are also used:
|
||||||
|
|
||||||
|
- ``Cordapp-Workflow-Version`` (mandatory), must be a whole number starting from 1.
|
||||||
|
- ``Cordapp-Workflow-Vendor`` (optional), defaults to UNKNOWN if not specified.
|
||||||
|
- ``Cordapp-Workflow-Licence`` (optional), defaults to UNKNOWN if not specified.
|
||||||
|
|
||||||
|
As with the general CorDapp attributes (minimum and target platform version), these can be specified using the Gradle `cordapp` plugin as follows:
|
||||||
|
|
||||||
|
For a contract only CorDapp we specify the `contract` tag:
|
||||||
|
|
||||||
.. container:: codeset
|
.. container:: codeset
|
||||||
|
|
||||||
.. sourcecode:: groovy
|
.. sourcecode:: groovy
|
||||||
|
|
||||||
jar {
|
cordapp {
|
||||||
manifest {
|
targetPlatformVersion 4
|
||||||
attributes(
|
minimumPlatformVersion 3
|
||||||
'Min-Platform-Version': 4
|
contract {
|
||||||
'Target-Platform-Version': 4
|
name "my contract name"
|
||||||
)
|
versionId 1
|
||||||
|
vendor "my company"
|
||||||
|
licence "my licence"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
For a CorDapp that contains flows and/or services we specify the `workflow` tag:
|
||||||
|
|
||||||
|
.. container:: codeset
|
||||||
|
|
||||||
|
.. sourcecode:: groovy
|
||||||
|
|
||||||
|
cordapp {
|
||||||
|
targetPlatformVersion 4
|
||||||
|
minimumPlatformVersion 3
|
||||||
|
workflow {
|
||||||
|
name "my workflow name"
|
||||||
|
versionId 1
|
||||||
|
vendor "my company"
|
||||||
|
licence "my licence"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.. note:: It is possible, but *not recommended*, to include everything in a single CorDapp jar and use both the ``contract`` and ``workflow`` Gradle plugin tags.
|
@ -35,12 +35,13 @@ publish {
|
|||||||
name 'corda-notary-bft-smart'
|
name 'corda-notary-bft-smart'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/experimental/notary-bft-smart"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
workflow {
|
||||||
|
name "net/corda/experimental/notary-bft-smart"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,12 @@ publish {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/experimental/notary-raft"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
workflow {
|
||||||
|
name "net/corda/experimental/notary-raft"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,30 +62,22 @@ artifacts {
|
|||||||
|
|
||||||
jar {
|
jar {
|
||||||
baseName 'corda-finance'
|
baseName 'corda-finance'
|
||||||
exclude "META-INF/*.DSA"
|
|
||||||
exclude "META-INF/*.RSA"
|
|
||||||
exclude "META-INF/*.SF"
|
|
||||||
exclude "META-INF/*.MF"
|
|
||||||
exclude "META-INF/LICENSE"
|
|
||||||
exclude "META-INF/NOTICE"
|
|
||||||
|
|
||||||
manifest {
|
|
||||||
attributes(
|
|
||||||
"Manifest-Version": "1.0",
|
|
||||||
"Specification-Title": description,
|
|
||||||
"Specification-Version": version,
|
|
||||||
"Specification-Vendor": "Corda Open Source",
|
|
||||||
"Implementation-Title": "$group.$baseName",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/finance"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
contract {
|
||||||
|
name "net/corda/finance/contracts"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
|
}
|
||||||
|
workflow {
|
||||||
|
name "net/corda/finance/flows"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
// By default the Cordapp is signed by Corda development certificate, for production build pass the following system properties to Gradle to use specific keystore e.g:
|
// By default the Cordapp is signed by Corda development certificate, for production build pass the following system properties to Gradle to use specific keystore e.g:
|
||||||
// ./gradlew -Dsigning.enabled="true" -Dsigning.keystore="/path/to/keystore.jks" -Dsigning.alias="alias" -Dsigning.storepass="password" -Dsigning.keypass="password"
|
// ./gradlew -Dsigning.enabled="true" -Dsigning.keystore="/path/to/keystore.jks" -Dsigning.alias="alias" -Dsigning.storepass="password" -Dsigning.keypass="password"
|
||||||
|
@ -4,13 +4,13 @@ import com.nhaarman.mockito_kotlin.any
|
|||||||
import com.nhaarman.mockito_kotlin.doReturn
|
import com.nhaarman.mockito_kotlin.doReturn
|
||||||
import com.nhaarman.mockito_kotlin.whenever
|
import com.nhaarman.mockito_kotlin.whenever
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.*
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.identity.AbstractParty
|
import net.corda.core.identity.AbstractParty
|
||||||
import net.corda.core.identity.CordaX500Name
|
import net.corda.core.identity.CordaX500Name
|
||||||
import net.corda.core.identity.Party
|
import net.corda.core.identity.Party
|
||||||
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
||||||
import net.corda.core.internal.RPC_UPLOADER
|
import net.corda.core.internal.RPC_UPLOADER
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.node.ServicesForResolution
|
import net.corda.core.node.ServicesForResolution
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.core.node.services.NetworkParametersStorage
|
import net.corda.core.node.services.NetworkParametersStorage
|
||||||
|
@ -35,8 +35,8 @@ import kotlin.test.assertNotNull
|
|||||||
class SignatureConstraintVersioningTests {
|
class SignatureConstraintVersioningTests {
|
||||||
|
|
||||||
private val base = cordappForPackages(MessageState::class.packageName, DummyMessageContract::class.packageName)
|
private val base = cordappForPackages(MessageState::class.packageName, DummyMessageContract::class.packageName)
|
||||||
private val oldCordapp = base.withCordappVersion("2")
|
private val oldCordapp = base.withVersion("2")
|
||||||
private val newCordapp = base.withCordappVersion("3")
|
private val newCordapp = base.withVersion("3")
|
||||||
private val user = User("mark", "dadada", setOf(startFlow<CreateMessage>(), startFlow<ConsumeMessage>(), invokeRpc("vaultQuery")))
|
private val user = User("mark", "dadada", setOf(startFlow<CreateMessage>(), startFlow<ConsumeMessage>(), invokeRpc("vaultQuery")))
|
||||||
private val message = Message("Hello world!")
|
private val message = Message("Hello world!")
|
||||||
private val transformetMessage = Message(message.value + "A")
|
private val transformetMessage = Message(message.value + "A")
|
||||||
|
@ -243,9 +243,7 @@ open class NodeStartup : NodeStartupLogging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected open fun logLoadedCorDapps(corDapps: List<CordappImpl>) {
|
protected open fun logLoadedCorDapps(corDapps: List<CordappImpl>) {
|
||||||
fun CordappImpl.Info.description() = "$shortName version $version by $vendor"
|
Node.printBasicNodeInfo("Loaded ${corDapps.size} CorDapp(s)", corDapps.map { it.info }.joinToString(", "))
|
||||||
|
|
||||||
Node.printBasicNodeInfo("Loaded ${corDapps.size} CorDapp(s)", corDapps.map { it.info }.joinToString(", ", transform = CordappImpl.Info::description))
|
|
||||||
corDapps.map { it.info }.filter { it.hasUnknownFields() }.let { malformed ->
|
corDapps.map { it.info }.filter { it.hasUnknownFields() }.let { malformed ->
|
||||||
if (malformed.isNotEmpty()) {
|
if (malformed.isNotEmpty()) {
|
||||||
logger.warn("Found ${malformed.size} CorDapp(s) with unknown information. They will be unable to run on Corda in the future.")
|
logger.warn("Found ${malformed.size} CorDapp(s) with unknown information. They will be unable to run on Corda in the future.")
|
||||||
|
@ -9,7 +9,9 @@ import net.corda.core.crypto.sha256
|
|||||||
import net.corda.core.flows.*
|
import net.corda.core.flows.*
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
import net.corda.core.internal.cordapp.CordappImpl
|
import net.corda.core.internal.cordapp.CordappImpl
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.UNKNOWN
|
||||||
import net.corda.core.internal.cordapp.CordappInfoResolver
|
import net.corda.core.internal.cordapp.CordappInfoResolver
|
||||||
|
import net.corda.core.internal.cordapp.toCordappInfo
|
||||||
import net.corda.core.internal.notary.NotaryService
|
import net.corda.core.internal.notary.NotaryService
|
||||||
import net.corda.core.internal.notary.SinglePartyNotaryService
|
import net.corda.core.internal.notary.SinglePartyNotaryService
|
||||||
import net.corda.core.node.services.CordaService
|
import net.corda.core.node.services.CordaService
|
||||||
@ -129,7 +131,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
|
|||||||
return cordapps
|
return cordapps
|
||||||
}
|
}
|
||||||
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl {
|
private fun RestrictedScanResult.toCordapp(url: RestrictedURL): CordappImpl {
|
||||||
val info = url.url.openStream().let(::JarInputStream).use { it.manifest?.toCordappInfo(CordappImpl.jarName(url.url)) ?: CordappImpl.Info.UNKNOWN }
|
val info = url.url.openStream().let(::JarInputStream).use { it.manifest?.toCordappInfo(CordappImpl.jarName(url.url)) ?: UNKNOWN }
|
||||||
return CordappImpl(
|
return CordappImpl(
|
||||||
findContractClassNames(this),
|
findContractClassNames(this),
|
||||||
findInitiatedFlows(this),
|
findInitiatedFlows(this),
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
package net.corda.node.internal.cordapp
|
|
||||||
|
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.internal.cordapp.CordappImpl
|
|
||||||
import net.corda.core.internal.cordapp.CordappImpl.Info.Companion.UNKNOWN_VALUE
|
|
||||||
import java.util.jar.Attributes
|
|
||||||
import java.util.jar.Manifest
|
|
||||||
|
|
||||||
//TODO implementationVersion parmemater and update `Implementation-Version` when we finally agree on a naming split for Contracts vs Flows jars.
|
|
||||||
fun createTestManifest(name: String, title: String, version: String, vendor: String, targetVersion: Int, implementationVersion: String): Manifest {
|
|
||||||
val manifest = Manifest()
|
|
||||||
|
|
||||||
// Mandatory manifest attribute. If not present, all other entries are silently skipped.
|
|
||||||
manifest.mainAttributes[Attributes.Name.MANIFEST_VERSION] = "1.0"
|
|
||||||
|
|
||||||
manifest["Name"] = name
|
|
||||||
|
|
||||||
manifest["Specification-Title"] = title
|
|
||||||
manifest["Specification-Version"] = version
|
|
||||||
manifest["Specification-Vendor"] = vendor
|
|
||||||
|
|
||||||
manifest["Implementation-Title"] = title
|
|
||||||
manifest[Attributes.Name.IMPLEMENTATION_VERSION] = implementationVersion
|
|
||||||
manifest["Implementation-Vendor"] = vendor
|
|
||||||
manifest["Target-Platform-Version"] = targetVersion.toString()
|
|
||||||
|
|
||||||
return manifest
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun Manifest.set(key: String, value: String): String? {
|
|
||||||
return mainAttributes.putValue(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun Manifest.set(key: Attributes.Name, value: String): Any? {
|
|
||||||
return mainAttributes.put(key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun Manifest.get(key: String): String? = mainAttributes.getValue(key)
|
|
||||||
|
|
||||||
fun Manifest.toCordappInfo(defaultShortName: String): CordappImpl.Info {
|
|
||||||
val shortName = this["Name"] ?: defaultShortName
|
|
||||||
val vendor = this["Implementation-Vendor"] ?: UNKNOWN_VALUE
|
|
||||||
val version = this["Implementation-Version"] ?: DEFAULT_CORDAPP_VERSION.toString()
|
|
||||||
val minPlatformVersion = this["Min-Platform-Version"]?.toIntOrNull() ?: 1
|
|
||||||
val targetPlatformVersion = this["Target-Platform-Version"]?.toIntOrNull() ?: minPlatformVersion
|
|
||||||
return CordappImpl.Info(
|
|
||||||
shortName = shortName,
|
|
||||||
vendor = vendor,
|
|
||||||
version = version,
|
|
||||||
minimumPlatformVersion = minPlatformVersion,
|
|
||||||
targetPlatformVersion = targetPlatformVersion
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
package net.corda.node.internal.cordapp
|
package net.corda.node.internal.cordapp
|
||||||
|
|
||||||
|
import net.corda.core.cordapp.Cordapp
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.flows.ContractUpgradeFlow
|
import net.corda.core.flows.ContractUpgradeFlow
|
||||||
import net.corda.core.internal.cordapp.CordappImpl
|
import net.corda.core.internal.cordapp.CordappImpl
|
||||||
@ -28,7 +29,7 @@ internal object VirtualCordapp {
|
|||||||
serializationWhitelists = listOf(),
|
serializationWhitelists = listOf(),
|
||||||
serializationCustomSerializers = listOf(),
|
serializationCustomSerializers = listOf(),
|
||||||
customSchemas = setOf(),
|
customSchemas = setOf(),
|
||||||
info = CordappImpl.Info("corda-core", versionInfo.vendor, versionInfo.releaseVersion, 1, versionInfo.platformVersion),
|
info = Cordapp.Info.Default("corda-core", versionInfo.vendor, versionInfo.releaseVersion, 1, versionInfo.platformVersion),
|
||||||
allFlows = listOf(),
|
allFlows = listOf(),
|
||||||
jarPath = ContractUpgradeFlow.javaClass.location, // Core JAR location
|
jarPath = ContractUpgradeFlow.javaClass.location, // Core JAR location
|
||||||
jarHash = SecureHash.allOnesHash,
|
jarHash = SecureHash.allOnesHash,
|
||||||
@ -49,7 +50,7 @@ internal object VirtualCordapp {
|
|||||||
serializationWhitelists = listOf(),
|
serializationWhitelists = listOf(),
|
||||||
serializationCustomSerializers = listOf(),
|
serializationCustomSerializers = listOf(),
|
||||||
customSchemas = setOf(NodeNotarySchemaV1),
|
customSchemas = setOf(NodeNotarySchemaV1),
|
||||||
info = CordappImpl.Info("corda-notary", versionInfo.vendor, versionInfo.releaseVersion, 1, versionInfo.platformVersion),
|
info = Cordapp.Info.Default("corda-notary", versionInfo.vendor, versionInfo.releaseVersion, 1, versionInfo.platformVersion),
|
||||||
allFlows = listOf(),
|
allFlows = listOf(),
|
||||||
jarPath = SimpleNotaryService::class.java.location,
|
jarPath = SimpleNotaryService::class.java.location,
|
||||||
jarHash = SecureHash.allOnesHash,
|
jarHash = SecureHash.allOnesHash,
|
||||||
|
@ -7,18 +7,20 @@ import com.google.common.hash.Hashing
|
|||||||
import com.google.common.hash.HashingInputStream
|
import com.google.common.hash.HashingInputStream
|
||||||
import com.google.common.io.CountingInputStream
|
import com.google.common.io.CountingInputStream
|
||||||
import net.corda.core.CordaRuntimeException
|
import net.corda.core.CordaRuntimeException
|
||||||
import net.corda.core.contracts.*
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.cordapp.CORDAPP_CONTRACT_VERSION
|
import net.corda.core.contracts.ContractAttachment
|
||||||
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VERSION
|
||||||
import net.corda.core.node.ServicesForResolution
|
import net.corda.core.node.ServicesForResolution
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||||
import net.corda.core.node.services.vault.AttachmentSort
|
import net.corda.core.node.services.vault.AttachmentSort
|
||||||
import net.corda.core.serialization.*
|
import net.corda.core.serialization.*
|
||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.node.services.vault.HibernateAttachmentQueryCriteriaParser
|
import net.corda.node.services.vault.HibernateAttachmentQueryCriteriaParser
|
||||||
import net.corda.node.utilities.NonInvalidatingCache
|
import net.corda.node.utilities.NonInvalidatingCache
|
||||||
import net.corda.node.utilities.NonInvalidatingWeightBasedCache
|
import net.corda.node.utilities.NonInvalidatingWeightBasedCache
|
||||||
|
@ -4,16 +4,12 @@ import co.paralleluniverse.fibers.Suspendable
|
|||||||
import com.codahale.metrics.MetricRegistry
|
import com.codahale.metrics.MetricRegistry
|
||||||
import com.google.common.jimfs.Configuration
|
import com.google.common.jimfs.Configuration
|
||||||
import com.google.common.jimfs.Jimfs
|
import com.google.common.jimfs.Jimfs
|
||||||
import net.corda.testing.core.internal.ContractJarTestUtils.makeTestContractJar
|
|
||||||
import net.corda.testing.core.internal.ContractJarTestUtils.makeTestJar
|
|
||||||
import net.corda.testing.core.internal.ContractJarTestUtils.makeTestSignedContractJar
|
|
||||||
import net.corda.testing.core.internal.SelfCleaningDir
|
|
||||||
import net.corda.core.contracts.ContractAttachment
|
import net.corda.core.contracts.ContractAttachment
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.flows.FlowLogic
|
import net.corda.core.flows.FlowLogic
|
||||||
import net.corda.core.internal.*
|
import net.corda.core.internal.*
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.node.ServicesForResolution
|
import net.corda.core.node.ServicesForResolution
|
||||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria.AttachmentsQueryCriteria
|
import net.corda.core.node.services.vault.AttachmentQueryCriteria.AttachmentsQueryCriteria
|
||||||
import net.corda.core.node.services.vault.AttachmentSort
|
import net.corda.core.node.services.vault.AttachmentSort
|
||||||
@ -23,6 +19,10 @@ import net.corda.core.utilities.getOrThrow
|
|||||||
import net.corda.node.services.transactions.PersistentUniquenessProvider
|
import net.corda.node.services.transactions.PersistentUniquenessProvider
|
||||||
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
import net.corda.nodeapi.internal.persistence.CordaPersistence
|
||||||
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
import net.corda.nodeapi.internal.persistence.DatabaseConfig
|
||||||
|
import net.corda.testing.core.internal.ContractJarTestUtils.makeTestContractJar
|
||||||
|
import net.corda.testing.core.internal.ContractJarTestUtils.makeTestJar
|
||||||
|
import net.corda.testing.core.internal.ContractJarTestUtils.makeTestSignedContractJar
|
||||||
|
import net.corda.testing.core.internal.SelfCleaningDir
|
||||||
import net.corda.testing.internal.LogHelper
|
import net.corda.testing.internal.LogHelper
|
||||||
import net.corda.testing.internal.TestingNamedCacheFactory
|
import net.corda.testing.internal.TestingNamedCacheFactory
|
||||||
import net.corda.testing.internal.configureDatabase
|
import net.corda.testing.internal.configureDatabase
|
||||||
|
@ -114,10 +114,12 @@ jar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/samples/attachment-demo"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
workflow {
|
||||||
|
name "net/corda/samples/attachment-demo"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,10 +115,12 @@ jar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/samples/bank-of-corda-demo"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
workflow {
|
||||||
|
name "net/corda/samples/bank-of-corda-demo"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,10 +59,12 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/samples/cordapp-configuration"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
workflow {
|
||||||
|
name "net/corda/samples/cordapp-configuration"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,10 +172,18 @@ artifacts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/irs-demo"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
contract {
|
||||||
|
name "net/corda/irs-demo/contract"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
|
}
|
||||||
|
workflow {
|
||||||
|
name "net/corda/irs-demo/flows"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,10 +53,12 @@ task deployNodes(type: net.corda.plugins.Cordform, dependsOn: ['jar', nodeTask])
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/samples/network-verifier"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
workflow {
|
||||||
|
name "net/corda/samples/network-verifier"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -255,10 +255,12 @@ jar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/samples/notary-demo"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
workflow {
|
||||||
|
name "net/corda/samples/notary-demo"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,8 +140,17 @@ task integrationTest(type: Test, dependsOn: []) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
vendor = 'R3'
|
|
||||||
targetPlatformVersion = corda_platform_version.toInteger()
|
targetPlatformVersion = corda_platform_version.toInteger()
|
||||||
|
contract {
|
||||||
|
name "net/corda/vega/contracts"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
|
}
|
||||||
|
workflow {
|
||||||
|
name "net/corda/vega/flows"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,8 @@ def javaHome = System.getProperty('java.home')
|
|||||||
def shrinkJar = file("$buildDir/libs/${project.name}-${project.version}-tiny.jar")
|
def shrinkJar = file("$buildDir/libs/${project.name}-${project.version}-tiny.jar")
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
vendor = 'R3'
|
|
||||||
targetPlatformVersion = corda_platform_version.toInteger()
|
targetPlatformVersion = corda_platform_version.toInteger()
|
||||||
}
|
minimumPlatformVersion 1
|
||||||
signing {
|
signing {
|
||||||
// Cordapp is signed after the "shrink" task.
|
// Cordapp is signed after the "shrink" task.
|
||||||
enabled false
|
enabled false
|
||||||
@ -16,6 +14,12 @@ cordapp {
|
|||||||
// Cannot seal JAR because other module also defines classes in the package net.corda.vega.analytics
|
// Cannot seal JAR because other module also defines classes in the package net.corda.vega.analytics
|
||||||
enabled false
|
enabled false
|
||||||
}
|
}
|
||||||
|
contract {
|
||||||
|
name "net/corda/vega/contracts"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
@ -2,14 +2,18 @@ apply plugin: 'net.corda.plugins.quasar-utils'
|
|||||||
apply plugin: 'net.corda.plugins.cordapp'
|
apply plugin: 'net.corda.plugins.cordapp'
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
vendor = 'R3'
|
|
||||||
targetPlatformVersion = corda_platform_version.toInteger()
|
targetPlatformVersion = corda_platform_version.toInteger()
|
||||||
}
|
minimumPlatformVersion 1
|
||||||
sealing {
|
sealing {
|
||||||
// Cannot seal JAR because other module also defines classes in the package net.corda.vega.analytics
|
// Cannot seal JAR because other module also defines classes in the package net.corda.vega.analytics
|
||||||
enabled false
|
enabled false
|
||||||
}
|
}
|
||||||
|
workflow {
|
||||||
|
name "net/corda/vega/flows"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -140,10 +140,12 @@ jar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cordapp {
|
cordapp {
|
||||||
info {
|
|
||||||
name "net/corda/samples/trader-demo"
|
|
||||||
vendor "Corda Open Source"
|
|
||||||
targetPlatformVersion corda_platform_version.toInteger()
|
targetPlatformVersion corda_platform_version.toInteger()
|
||||||
minimumPlatformVersion 1
|
minimumPlatformVersion 1
|
||||||
|
workflow {
|
||||||
|
name "net/corda/samples/trader-demo"
|
||||||
|
versionId 1
|
||||||
|
vendor "R3"
|
||||||
|
licence "Open Source (Apache 2)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.corda.testing.node
|
package net.corda.testing.node
|
||||||
|
|
||||||
import net.corda.core.DoNotImplement
|
import net.corda.core.DoNotImplement
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.internal.PLATFORM_VERSION
|
import net.corda.core.internal.PLATFORM_VERSION
|
||||||
import net.corda.testing.node.internal.TestCordappImpl
|
import net.corda.testing.node.internal.TestCordappImpl
|
||||||
import net.corda.testing.node.internal.simplifyScanPackages
|
import net.corda.testing.node.internal.simplifyScanPackages
|
||||||
@ -27,9 +26,6 @@ interface TestCordapp {
|
|||||||
/** Returns the target platform version, defaults to the current platform version if not specified. */
|
/** Returns the target platform version, defaults to the current platform version if not specified. */
|
||||||
val targetVersion: Int
|
val targetVersion: Int
|
||||||
|
|
||||||
/** Returns the cordapp version. */
|
|
||||||
val cordappVersion: String
|
|
||||||
|
|
||||||
/** Returns the config for this CorDapp, defaults to empty if not specified. */
|
/** Returns the config for this CorDapp, defaults to empty if not specified. */
|
||||||
val config: Map<String, Any>
|
val config: Map<String, Any>
|
||||||
|
|
||||||
@ -61,8 +57,6 @@ interface TestCordapp {
|
|||||||
* Optionally can pass in the location of an existing java key store to use */
|
* Optionally can pass in the location of an existing java key store to use */
|
||||||
fun signJar(keyStorePath: Path? = null): TestCordappImpl
|
fun signJar(keyStorePath: Path? = null): TestCordappImpl
|
||||||
|
|
||||||
fun withCordappVersion(version: String): TestCordappImpl
|
|
||||||
|
|
||||||
class Factory {
|
class Factory {
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
@ -80,11 +74,10 @@ interface TestCordapp {
|
|||||||
fun fromPackages(packageNames: Collection<String>): TestCordapp {
|
fun fromPackages(packageNames: Collection<String>): TestCordapp {
|
||||||
return TestCordappImpl(
|
return TestCordappImpl(
|
||||||
name = "test-name",
|
name = "test-name",
|
||||||
version = "1.0",
|
version = "1",
|
||||||
vendor = "test-vendor",
|
vendor = "test-vendor",
|
||||||
title = "test-title",
|
title = "test-title",
|
||||||
targetVersion = PLATFORM_VERSION,
|
targetVersion = PLATFORM_VERSION,
|
||||||
cordappVersion = DEFAULT_CORDAPP_VERSION.toString(),
|
|
||||||
config = emptyMap(),
|
config = emptyMap(),
|
||||||
packages = simplifyScanPackages(packageNames),
|
packages = simplifyScanPackages(packageNames),
|
||||||
classes = emptySet()
|
classes = emptySet()
|
||||||
|
@ -8,7 +8,6 @@ data class TestCordappImpl(override val name: String,
|
|||||||
override val vendor: String,
|
override val vendor: String,
|
||||||
override val title: String,
|
override val title: String,
|
||||||
override val targetVersion: Int,
|
override val targetVersion: Int,
|
||||||
override val cordappVersion: String,
|
|
||||||
override val config: Map<String, Any>,
|
override val config: Map<String, Any>,
|
||||||
override val packages: Set<String>,
|
override val packages: Set<String>,
|
||||||
override val signJar: Boolean = false,
|
override val signJar: Boolean = false,
|
||||||
@ -26,8 +25,6 @@ data class TestCordappImpl(override val name: String,
|
|||||||
|
|
||||||
override fun withTargetVersion(targetVersion: Int): TestCordappImpl = copy(targetVersion = targetVersion)
|
override fun withTargetVersion(targetVersion: Int): TestCordappImpl = copy(targetVersion = targetVersion)
|
||||||
|
|
||||||
override fun withCordappVersion(version: String): TestCordappImpl = copy(cordappVersion = version)
|
|
||||||
|
|
||||||
override fun withConfig(config: Map<String, Any>): TestCordappImpl = copy(config = config)
|
override fun withConfig(config: Map<String, Any>): TestCordappImpl = copy(config = config)
|
||||||
|
|
||||||
override fun signJar(keyStorePath: Path?): TestCordappImpl = copy(signJar = true, keyStorePath = keyStorePath)
|
override fun signJar(keyStorePath: Path?): TestCordappImpl = copy(signJar = true, keyStorePath = keyStorePath)
|
||||||
|
@ -1,15 +1,22 @@
|
|||||||
package net.corda.testing.node.internal
|
package net.corda.testing.node.internal
|
||||||
|
|
||||||
import io.github.classgraph.ClassGraph
|
import io.github.classgraph.ClassGraph
|
||||||
|
import net.corda.core.internal.cordapp.*
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_NAME
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_NAME
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.TARGET_PLATFORM_VERSION
|
||||||
import net.corda.core.internal.outputStream
|
import net.corda.core.internal.outputStream
|
||||||
import net.corda.node.internal.cordapp.createTestManifest
|
|
||||||
import net.corda.testing.node.TestCordapp
|
import net.corda.testing.node.TestCordapp
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.nio.file.attribute.FileTime
|
import java.nio.file.attribute.FileTime
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
import java.util.jar.Attributes
|
||||||
import java.util.jar.JarFile
|
import java.util.jar.JarFile
|
||||||
import java.util.jar.JarOutputStream
|
import java.util.jar.JarOutputStream
|
||||||
|
import java.util.jar.Manifest
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@ -66,7 +73,7 @@ fun TestCordappImpl.packageAsJar(file: Path) {
|
|||||||
.scan()
|
.scan()
|
||||||
|
|
||||||
scanResult.use {
|
scanResult.use {
|
||||||
val manifest = createTestManifest(name, title, version, vendor, targetVersion, cordappVersion)
|
val manifest = createTestManifest(name, title, version, vendor, targetVersion)
|
||||||
JarOutputStream(file.outputStream()).use { jos ->
|
JarOutputStream(file.outputStream()).use { jos ->
|
||||||
val time = FileTime.from(Instant.EPOCH)
|
val time = FileTime.from(Instant.EPOCH)
|
||||||
val manifestEntry = ZipEntry(JarFile.MANIFEST_NAME).setCreationTime(time).setLastAccessTime(time).setLastModifiedTime(time)
|
val manifestEntry = ZipEntry(JarFile.MANIFEST_NAME).setCreationTime(time).setLastAccessTime(time).setLastModifiedTime(time)
|
||||||
@ -85,3 +92,22 @@ fun TestCordappImpl.packageAsJar(file: Path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createTestManifest(name: String, title: String, version: String, vendor: String, targetVersion: Int): Manifest {
|
||||||
|
val manifest = Manifest()
|
||||||
|
|
||||||
|
// Mandatory manifest attribute. If not present, all other entries are silently skipped.
|
||||||
|
manifest[Attributes.Name.MANIFEST_VERSION.toString()] = "1.0"
|
||||||
|
|
||||||
|
manifest["Name"] = name
|
||||||
|
manifest[Attributes.Name.IMPLEMENTATION_TITLE] = title
|
||||||
|
manifest[Attributes.Name.IMPLEMENTATION_VERSION] = version
|
||||||
|
manifest[Attributes.Name.IMPLEMENTATION_VENDOR] = vendor
|
||||||
|
manifest[CORDAPP_CONTRACT_NAME] = name
|
||||||
|
manifest[CORDAPP_CONTRACT_VERSION] = version
|
||||||
|
manifest[CORDAPP_WORKFLOW_NAME] = name
|
||||||
|
manifest[CORDAPP_WORKFLOW_VERSION] = version
|
||||||
|
manifest[TARGET_PLATFORM_VERSION] = targetVersion.toString()
|
||||||
|
|
||||||
|
return manifest
|
||||||
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package net.corda.testing.node.internal
|
package net.corda.testing.node.internal
|
||||||
|
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_NAME
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_WORKFLOW_NAME
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.TARGET_PLATFORM_VERSION
|
||||||
|
import net.corda.core.internal.cordapp.get
|
||||||
import net.corda.core.internal.inputStream
|
import net.corda.core.internal.inputStream
|
||||||
import net.corda.node.internal.cordapp.get
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -34,8 +37,9 @@ class TestCordappsUtilsTest {
|
|||||||
|
|
||||||
val jarFile = packageAsJar(cordapp)
|
val jarFile = packageAsJar(cordapp)
|
||||||
JarInputStream(jarFile.inputStream()).use {
|
JarInputStream(jarFile.inputStream()).use {
|
||||||
assertThat(it.manifest["Target-Platform-Version"]).isEqualTo("123")
|
assertThat(it.manifest[TARGET_PLATFORM_VERSION]).isEqualTo("123")
|
||||||
assertThat(it.manifest["Name"]).isEqualTo("TestCordappsUtilsTest")
|
assertThat(it.manifest[CORDAPP_CONTRACT_NAME]).isEqualTo("TestCordappsUtilsTest")
|
||||||
|
assertThat(it.manifest[CORDAPP_WORKFLOW_NAME]).isEqualTo("TestCordappsUtilsTest")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
package net.corda.testing.core.internal
|
package net.corda.testing.core.internal
|
||||||
|
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.CORDAPP_CONTRACT_VERSION
|
||||||
|
import net.corda.core.internal.delete
|
||||||
|
import net.corda.core.internal.div
|
||||||
|
import net.corda.core.internal.toPath
|
||||||
|
import net.corda.testing.core.ALICE_NAME
|
||||||
import net.corda.testing.core.internal.JarSignatureTestUtils.addManifest
|
import net.corda.testing.core.internal.JarSignatureTestUtils.addManifest
|
||||||
import net.corda.testing.core.internal.JarSignatureTestUtils.createJar
|
import net.corda.testing.core.internal.JarSignatureTestUtils.createJar
|
||||||
import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey
|
import net.corda.testing.core.internal.JarSignatureTestUtils.generateKey
|
||||||
import net.corda.testing.core.internal.JarSignatureTestUtils.signJar
|
import net.corda.testing.core.internal.JarSignatureTestUtils.signJar
|
||||||
import net.corda.core.internal.delete
|
|
||||||
import net.corda.core.internal.div
|
|
||||||
import net.corda.core.internal.toPath
|
|
||||||
import net.corda.core.cordapp.CORDAPP_CONTRACT_VERSION
|
|
||||||
import net.corda.testing.core.ALICE_NAME
|
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.nio.file.*
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
import java.nio.file.Paths
|
||||||
|
import java.nio.file.StandardCopyOption
|
||||||
import java.security.PublicKey
|
import java.security.PublicKey
|
||||||
import java.util.jar.Attributes
|
import java.util.jar.Attributes
|
||||||
import java.util.jar.JarEntry
|
import java.util.jar.JarEntry
|
||||||
|
@ -16,7 +16,7 @@ import net.corda.core.schemas.MappedSchema
|
|||||||
import net.corda.core.serialization.internal.effectiveSerializationEnv
|
import net.corda.core.serialization.internal.effectiveSerializationEnv
|
||||||
import net.corda.core.transactions.WireTransaction
|
import net.corda.core.transactions.WireTransaction
|
||||||
import net.corda.core.utilities.loggerFor
|
import net.corda.core.utilities.loggerFor
|
||||||
import net.corda.node.internal.cordapp.set
|
import net.corda.core.internal.cordapp.set
|
||||||
import net.corda.node.internal.createCordaPersistence
|
import net.corda.node.internal.createCordaPersistence
|
||||||
import net.corda.node.internal.security.RPCSecurityManagerImpl
|
import net.corda.node.internal.security.RPCSecurityManagerImpl
|
||||||
import net.corda.node.internal.startHikariPool
|
import net.corda.node.internal.startHikariPool
|
||||||
|
@ -5,6 +5,7 @@ import net.corda.core.cordapp.Cordapp
|
|||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
import net.corda.core.internal.DEPLOYED_CORDAPP_UPLOADER
|
||||||
import net.corda.core.internal.cordapp.CordappImpl
|
import net.corda.core.internal.cordapp.CordappImpl
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.UNKNOWN
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
import net.corda.node.cordapp.CordappLoader
|
import net.corda.node.cordapp.CordappLoader
|
||||||
@ -40,7 +41,7 @@ class MockCordappProvider(
|
|||||||
serializationCustomSerializers = emptyList(),
|
serializationCustomSerializers = emptyList(),
|
||||||
customSchemas = emptySet(),
|
customSchemas = emptySet(),
|
||||||
jarPath = Paths.get("").toUri().toURL(),
|
jarPath = Paths.get("").toUri().toURL(),
|
||||||
info = CordappImpl.Info.UNKNOWN,
|
info = UNKNOWN,
|
||||||
allFlows = emptyList(),
|
allFlows = emptyList(),
|
||||||
jarHash = SecureHash.allOnesHash,
|
jarHash = SecureHash.allOnesHash,
|
||||||
notaryService = null
|
notaryService = null
|
||||||
|
@ -3,11 +3,11 @@ package net.corda.testing.services
|
|||||||
import net.corda.core.contracts.Attachment
|
import net.corda.core.contracts.Attachment
|
||||||
import net.corda.core.contracts.ContractAttachment
|
import net.corda.core.contracts.ContractAttachment
|
||||||
import net.corda.core.contracts.ContractClassName
|
import net.corda.core.contracts.ContractClassName
|
||||||
import net.corda.core.cordapp.DEFAULT_CORDAPP_VERSION
|
|
||||||
import net.corda.core.crypto.SecureHash
|
import net.corda.core.crypto.SecureHash
|
||||||
import net.corda.core.crypto.sha256
|
import net.corda.core.crypto.sha256
|
||||||
import net.corda.core.internal.AbstractAttachment
|
import net.corda.core.internal.AbstractAttachment
|
||||||
import net.corda.core.internal.UNKNOWN_UPLOADER
|
import net.corda.core.internal.UNKNOWN_UPLOADER
|
||||||
|
import net.corda.core.internal.cordapp.CordappImpl.Companion.DEFAULT_CORDAPP_VERSION
|
||||||
import net.corda.core.internal.readFully
|
import net.corda.core.internal.readFully
|
||||||
import net.corda.core.node.services.AttachmentId
|
import net.corda.core.node.services.AttachmentId
|
||||||
import net.corda.core.node.services.AttachmentStorage
|
import net.corda.core.node.services.AttachmentStorage
|
||||||
|
Loading…
Reference in New Issue
Block a user