Merge branch 'master' into tudor_merge_os_24_10

# Conflicts:
#	core/src/main/kotlin/net/corda/core/internal/JarSignatureCollector.kt
#	core/src/main/kotlin/net/corda/core/transactions/LedgerTransaction.kt
#	core/src/main/kotlin/net/corda/core/transactions/TransactionBuilder.kt
#	core/src/main/kotlin/net/corda/core/utilities/KotlinUtils.kt
#	core/src/test/kotlin/net/corda/core/contracts/PackageOwnershipVerificationTests.kt
#	core/src/test/kotlin/net/corda/core/internal/JarSignatureCollectorTest.kt
#	node/src/main/kotlin/net/corda/node/internal/cordapp/JarScanningCordappLoader.kt
#	node/src/test/kotlin/net/corda/node/services/persistence/NodeAttachmentServiceTest.kt
#	testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TestDSL.kt
#	testing/test-utils/src/main/kotlin/net/corda/testing/dsl/TransactionDSLInterpreter.kt
#	testing/test-utils/src/main/kotlin/net/corda/testing/internal/MockCordappProvider.kt
This commit is contained in:
tudor.malene@gmail.com
2018-10-24 17:09:30 +01:00
532 changed files with 13655 additions and 5037 deletions

View File

@ -0,0 +1,36 @@
package net.corda.testing.contracts
import net.corda.core.contracts.*
import net.corda.core.identity.AbstractParty
import net.corda.core.transactions.LedgerTransaction
// The dummy contract doesn't do anything useful. It exists for testing purposes.
/**
* Dummy contract state for testing of the upgrade process.
*/
class DummyContractV3 : UpgradedContractWithLegacyConstraint<DummyContractV2.State, DummyContractV3.State> {
companion object {
const val PROGRAM_ID: ContractClassName = "net.corda.testing.contracts.DummyContractV3"
}
override val legacyContract: String = DummyContractV2.PROGRAM_ID
override val legacyContractConstraint: AttachmentConstraint = AlwaysAcceptAttachmentConstraint
data class State(val magicNumber: Int = 0, val owners: List<AbstractParty>) : ContractState {
override val participants: List<AbstractParty> = owners
}
interface Commands : CommandData {
class Create : TypeOnlyCommandData(), Commands
class Move : TypeOnlyCommandData(), Commands
}
override fun upgrade(state: DummyContractV2.State): State {
return State(state.magicNumber, state.participants)
}
override fun verify(tx: LedgerTransaction) {
// Other verifications.
}
}

View File

@ -3,9 +3,7 @@ package net.corda.testing.core
import com.nhaarman.mockito_kotlin.any
import com.nhaarman.mockito_kotlin.doAnswer
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.DoNotImplement
import net.corda.core.internal.staticField
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.internal.SerializationEnvironment
import net.corda.core.serialization.internal.effectiveSerializationEnv
import net.corda.testing.common.internal.asContextEnv
@ -40,7 +38,7 @@ class SerializationEnvironmentRule(private val inheritable: Boolean = false) : T
/** Do not call, instead use [SerializationEnvironmentRule] as a [org.junit.Rule]. */
fun <T> run(taskLabel: String, task: (SerializationEnvironment) -> T): T {
return SerializationEnvironmentRule().apply { init(taskLabel) }.runTask(task)
return SerializationEnvironmentRule().apply { init() }.runTask(task)
}
}
@ -48,14 +46,14 @@ class SerializationEnvironmentRule(private val inheritable: Boolean = false) : T
val serializationFactory get() = env.serializationFactory
override fun apply(base: Statement, description: Description): Statement {
init(description.toString())
init()
return object : Statement() {
override fun evaluate() = runTask { base.evaluate() }
}
}
private fun init(envLabel: String) {
env = createTestSerializationEnv(envLabel)
private fun init() {
env = createTestSerializationEnv()
}
private fun <T> runTask(task: (SerializationEnvironment) -> T): T {

View File

@ -39,7 +39,7 @@ class CheckpointSerializationEnvironmentRule(private val inheritable: Boolean =
/** Do not call, instead use [SerializationEnvironmentRule] as a [org.junit.Rule]. */
fun <T> run(taskLabel: String, task: (SerializationEnvironment) -> T): T {
return CheckpointSerializationEnvironmentRule().apply { init(taskLabel) }.runTask(task)
return CheckpointSerializationEnvironmentRule().apply { init() }.runTask(task)
}
}
@ -47,14 +47,14 @@ class CheckpointSerializationEnvironmentRule(private val inheritable: Boolean =
private lateinit var env: SerializationEnvironment
override fun apply(base: Statement, description: Description): Statement {
init(description.toString())
init()
return object : Statement() {
override fun evaluate() = runTask { base.evaluate() }
}
}
private fun init(envLabel: String) {
env = createTestSerializationEnv(envLabel)
private fun init() {
env = createTestSerializationEnv()
}
private fun <T> runTask(task: (SerializationEnvironment) -> T): T {
@ -65,7 +65,6 @@ class CheckpointSerializationEnvironmentRule(private val inheritable: Boolean =
}
}
val checkpointSerializationFactory get() = env.checkpointSerializationFactory
val checkpointSerializationContext get() = env.checkpointContext
val checkpointSerializer get() = env.checkpointSerializer
}

View File

@ -155,6 +155,10 @@ data class TestTransactionDSLInterpreter private constructor(
attachment((services.cordappProvider as MockCordappProvider).addMockCordapp(contractClassName, services.attachments as MockAttachmentStorage, attachmentId, signers))
}
override fun _attachment(contractClassName: ContractClassName, attachmentId: AttachmentId, signers: List<PublicKey>){
attachment((services.cordappProvider as MockCordappProvider).addMockCordapp(contractClassName, services.attachments as MockAttachmentStorage, attachmentId, signers))
}
}
data class TestLedgerDSLInterpreter private constructor(

View File

@ -4,11 +4,10 @@ import com.nhaarman.mockito_kotlin.doNothing
import com.nhaarman.mockito_kotlin.whenever
import net.corda.client.rpc.internal.serialization.amqp.AMQPClientSerializationScheme
import net.corda.core.DoNotImplement
import net.corda.core.serialization.internal.CheckpointSerializationFactory
import net.corda.core.serialization.internal.*
import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.KryoSerializationScheme
import net.corda.node.serialization.kryo.KryoCheckpointSerializer
import net.corda.serialization.internal.*
import net.corda.testing.core.SerializationEnvironmentRule
import java.util.concurrent.ConcurrentHashMap
@ -30,22 +29,20 @@ fun <T> withoutTestSerialization(callable: () -> T): T { // TODO: Delete this, s
}
}
internal fun createTestSerializationEnv(label: String): SerializationEnvironmentImpl {
internal fun createTestSerializationEnv(): SerializationEnvironment {
val factory = SerializationFactoryImpl().apply {
registerScheme(AMQPClientSerializationScheme(emptyList()))
registerScheme(AMQPServerSerializationScheme(emptyList()))
}
return object : SerializationEnvironmentImpl(
return SerializationEnvironment.with(
factory,
AMQP_P2P_CONTEXT,
AMQP_RPC_SERVER_CONTEXT,
AMQP_RPC_CLIENT_CONTEXT,
AMQP_STORAGE_CONTEXT,
KRYO_CHECKPOINT_CONTEXT,
CheckpointSerializationFactory(KryoSerializationScheme)
) {
override fun toString() = "testSerializationEnv($label)"
}
KryoCheckpointSerializer
)
}
/**
@ -54,7 +51,7 @@ internal fun createTestSerializationEnv(label: String): SerializationEnvironment
*/
fun setGlobalSerialization(armed: Boolean): GlobalSerializationEnvironment {
return if (armed) {
object : GlobalSerializationEnvironment, SerializationEnvironment by createTestSerializationEnv("<global>") {
object : GlobalSerializationEnvironment, SerializationEnvironment by createTestSerializationEnv() {
override fun unset() {
_globalSerializationEnv.set(null)
inVMExecutors.remove(this)

View File

@ -1,26 +1,42 @@
package net.corda.testing.internal
import net.corda.core.context.AuthServiceId
import net.corda.core.contracts.*
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.Crypto.generateKeyPair
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.NamedCacheFactory
import net.corda.core.node.NodeInfo
import net.corda.core.schemas.MappedSchema
import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.loggerFor
import net.corda.node.internal.createCordaPersistence
import net.corda.node.internal.security.RPCSecurityManagerImpl
import net.corda.node.internal.startHikariPool
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.SecurityConfiguration
import net.corda.node.services.schema.NodeSchemaService
import net.corda.nodeapi.BrokerRpcSslOptions
import net.corda.nodeapi.internal.config.MutualSslConfiguration
import net.corda.nodeapi.internal.registerDevP2pCertificates
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.createDevNodeCa
import net.corda.nodeapi.internal.crypto.*
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.loadDevCaTrustStore
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.nodeapi.internal.registerDevP2pCertificates
import net.corda.serialization.internal.amqp.AMQP_ENABLED
import net.corda.testing.internal.stubs.CertificateStoreStubs
import java.nio.file.Files
import java.nio.file.Path
import java.security.KeyPair
import java.util.*
import javax.security.auth.x500.X500Principal
@Suppress("unused")
@ -136,3 +152,24 @@ fun createWireTransaction(inputs: List<StateRef>,
val componentGroups = WireTransaction.createComponentGroups(inputs, outputs, commands, attachments, notary, timeWindow)
return WireTransaction(componentGroups, privacySalt)
}
/**
* Instantiate RPCSecurityManager initialised with users data from a list of [User]
*/
fun RPCSecurityManagerImpl.Companion.fromUserList(id: AuthServiceId, users: List<User>) =
RPCSecurityManagerImpl(SecurityConfiguration.AuthService.fromUsers(users).copy(id = id), TestingNamedCacheFactory())
/**
* Convenience method for configuring a database for some tests.
*/
fun configureDatabase(hikariProperties: Properties,
databaseConfig: DatabaseConfig,
wellKnownPartyFromX500Name: (CordaX500Name) -> Party?,
wellKnownPartyFromAnonymous: (AbstractParty) -> Party?,
schemaService: SchemaService = NodeSchemaService(),
internalSchemas: Set<MappedSchema> = NodeSchemaService().internalSchemas(),
cacheFactory: NamedCacheFactory = TestingNamedCacheFactory()): CordaPersistence {
val persistence = createCordaPersistence(databaseConfig, wellKnownPartyFromX500Name, wellKnownPartyFromAnonymous, schemaService, hikariProperties, cacheFactory)
persistence.startHikariPool(hikariProperties, databaseConfig, internalSchemas)
return persistence
}

View File

@ -0,0 +1,33 @@
package net.corda.testing.internal
import com.codahale.metrics.MetricRegistry
import com.github.benmanes.caffeine.cache.Cache
import com.github.benmanes.caffeine.cache.CacheLoader
import com.github.benmanes.caffeine.cache.Caffeine
import com.github.benmanes.caffeine.cache.LoadingCache
import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.node.services.config.MB
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.utilities.BindableNamedCacheFactory
class TestingNamedCacheFactory private constructor(private val sizeOverride: Long, private val metricRegistry: MetricRegistry?, private val nodeConfiguration: NodeConfiguration?) : BindableNamedCacheFactory, SingletonSerializeAsToken() {
constructor(sizeOverride: Long = 1024) : this(sizeOverride, null, null)
override fun bindWithMetrics(metricRegistry: MetricRegistry): BindableNamedCacheFactory = TestingNamedCacheFactory(sizeOverride, metricRegistry, this.nodeConfiguration)
override fun bindWithConfig(nodeConfiguration: NodeConfiguration): BindableNamedCacheFactory = TestingNamedCacheFactory(sizeOverride, this.metricRegistry, nodeConfiguration)
override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String): Cache<K, V> {
// Does not check metricRegistry or nodeConfiguration, because for tests we don't care.
return caffeine.maximumSize(sizeOverride).build<K, V>()
}
override fun <K, V> buildNamed(caffeine: Caffeine<in K, in V>, name: String, loader: CacheLoader<K, V>): LoadingCache<K, V> {
// Does not check metricRegistry or nodeConfiguration, because for tests we don't care.
val configuredCaffeine = when (name) {
"DBTransactionStorage_transactions" -> caffeine.maximumWeight(1.MB)
"NodeAttachmentService_attachmentContent" -> caffeine.maximumWeight(1.MB)
else -> caffeine.maximumSize(sizeOverride)
}
return configuredCaffeine.build<K, V>(loader)
}
}

View File

@ -1,6 +1,9 @@
package net.corda.testing.internal.stubs
import net.corda.core.internal.div
import net.corda.nodeapi.internal.DEV_CA_KEY_STORE_PASS
import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_PASS
import net.corda.nodeapi.internal.DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS
import net.corda.nodeapi.internal.config.FileBasedCertificateStoreSupplier
import net.corda.nodeapi.internal.config.SslConfiguration
import net.corda.nodeapi.internal.config.MutualSslConfiguration
@ -11,28 +14,27 @@ class CertificateStoreStubs {
companion object {
const val DEFAULT_CERTIFICATES_DIRECTORY_NAME = "certificates"
@JvmStatic
fun withStoreAt(certificateStorePath: Path, password: String): FileBasedCertificateStoreSupplier = FileBasedCertificateStoreSupplier(certificateStorePath, password)
}
class Signing {
companion object {
const val DEFAULT_STORE_FILE_NAME = "nodekeystore.jks"
const val DEFAULT_STORE_PASSWORD = "cordacadevpass"
private const val DEFAULT_STORE_FILE_NAME = "nodekeystore.jks"
private const val DEFAULT_STORE_PASSWORD = DEV_CA_KEY_STORE_PASS
@JvmStatic
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD,
keyPassword: String = password, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password)
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password, keyPassword)
}
@JvmStatic
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, keyPassword: String = password,
certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password)
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password, keyPassword)
}
}
}
@ -42,17 +44,23 @@ class CertificateStoreStubs {
companion object {
@JvmStatic
fun withCertificatesDirectory(certificatesDirectory: Path, keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME, keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD, trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME, trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD): MutualSslConfiguration {
fun withCertificatesDirectory(certificatesDirectory: Path, keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME,
keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD, keyPassword: String = keyStorePassword,
trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME, trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD, trustStoreKeyPassword: String = TrustStore.DEFAULT_KEY_PASSWORD,
useOpenSsl: Boolean = false): MutualSslConfiguration {
val keyStore = FileBasedCertificateStoreSupplier(certificatesDirectory / keyStoreFileName, keyStorePassword)
val trustStore = FileBasedCertificateStoreSupplier(certificatesDirectory / trustStoreFileName, trustStorePassword)
val keyStore = FileBasedCertificateStoreSupplier(certificatesDirectory / keyStoreFileName, keyStorePassword, keyPassword)
val trustStore = FileBasedCertificateStoreSupplier(certificatesDirectory / trustStoreFileName, trustStorePassword, trustStoreKeyPassword)
return SslConfiguration.mutual(keyStore, trustStore)
}
@JvmStatic
fun withBaseDirectory(baseDirectory: Path, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME, keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD, trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME, trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD): MutualSslConfiguration {
fun withBaseDirectory(baseDirectory: Path, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME,
keyStoreFileName: String = KeyStore.DEFAULT_STORE_FILE_NAME, keyStorePassword: String = KeyStore.DEFAULT_STORE_PASSWORD,
keyPassword: String = keyStorePassword, trustStoreFileName: String = TrustStore.DEFAULT_STORE_FILE_NAME,
trustStorePassword: String = TrustStore.DEFAULT_STORE_PASSWORD): MutualSslConfiguration {
return withCertificatesDirectory(baseDirectory / certificatesDirectoryName, keyStoreFileName, keyStorePassword, trustStoreFileName, trustStorePassword)
return withCertificatesDirectory(baseDirectory / certificatesDirectoryName, keyStoreFileName, keyStorePassword, keyPassword, trustStoreFileName, trustStorePassword)
}
}
@ -61,18 +69,20 @@ class CertificateStoreStubs {
companion object {
const val DEFAULT_STORE_FILE_NAME = "sslkeystore.jks"
const val DEFAULT_STORE_PASSWORD = "cordacadevpass"
const val DEFAULT_STORE_PASSWORD = DEV_CA_KEY_STORE_PASS
@JvmStatic
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, keyPassword: String = password,
certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password)
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password, keyPassword)
}
@JvmStatic
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, keyPassword: String = password,
certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password)
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password, keyPassword)
}
}
}
@ -82,18 +92,21 @@ class CertificateStoreStubs {
companion object {
const val DEFAULT_STORE_FILE_NAME = "truststore.jks"
const val DEFAULT_STORE_PASSWORD = "trustpass"
const val DEFAULT_STORE_PASSWORD = DEV_CA_TRUST_STORE_PASS
const val DEFAULT_KEY_PASSWORD = DEV_CA_TRUST_STORE_PRIVATE_KEY_PASS
@JvmStatic
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
fun withCertificatesDirectory(certificatesDirectory: Path, password: String = DEFAULT_STORE_PASSWORD,
keyPassword: String = DEFAULT_KEY_PASSWORD, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password)
return FileBasedCertificateStoreSupplier(certificatesDirectory / certificateStoreFileName, password, keyPassword)
}
@JvmStatic
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
fun withBaseDirectory(baseDirectory: Path, password: String = DEFAULT_STORE_PASSWORD, keyPassword: String = DEFAULT_KEY_PASSWORD,
certificatesDirectoryName: String = DEFAULT_CERTIFICATES_DIRECTORY_NAME, certificateStoreFileName: String = DEFAULT_STORE_FILE_NAME): FileBasedCertificateStoreSupplier {
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password)
return FileBasedCertificateStoreSupplier(baseDirectory / certificatesDirectoryName / certificateStoreFileName, password, keyPassword)
}
}
}

View File

@ -102,7 +102,8 @@ class VaultFiller @JvmOverloads constructor(
linearString: String = "",
linearNumber: Long = 0L,
linearBoolean: Boolean = false,
linearTimestamp: Instant = now()): Vault<LinearState> {
linearTimestamp: Instant = now(),
constraint: AttachmentConstraint = AutomaticHashConstraint): Vault<LinearState> {
val myKey: PublicKey = services.myInfo.chooseIdentity().owningKey
val me = AnonymousParty(myKey)
val issuerKey = defaultNotary.keyPair
@ -116,7 +117,8 @@ class VaultFiller @JvmOverloads constructor(
linearString = linearString,
linearNumber = linearNumber,
linearBoolean = linearBoolean,
linearTimestamp = linearTimestamp), DUMMY_LINEAR_CONTRACT_PROGRAM_ID)
linearTimestamp = linearTimestamp), DUMMY_LINEAR_CONTRACT_PROGRAM_ID,
constraint = constraint)
addCommand(dummyCommand())
}
return@map services.signInitialTransaction(dummyIssue).withAdditionalSignature(issuerKey, signatureMetadata)