diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 4af7873898..43a1d65c41 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -45,6 +45,8 @@ + + @@ -53,6 +55,8 @@ + + @@ -73,11 +77,17 @@ + + + + + + @@ -122,6 +132,8 @@ + + @@ -139,6 +151,10 @@ + + + + @@ -200,10 +216,15 @@ + + + + + @@ -239,6 +260,8 @@ + + diff --git a/settings.gradle b/settings.gradle index db94bf05d5..4528f85bcc 100644 --- a/settings.gradle +++ b/settings.gradle @@ -82,11 +82,6 @@ include 'samples:cordapp-configuration' include 'serialization' include 'serialization-deterministic' include 'cordform-common' -include 'verify-enclave' include 'hsm-tool' -project(':hsm-tool').with { - name = 'sgx-hsm-tool' - projectDir = file("$settingsDir/sgx-jvm/hsm-tool") -} include 'launcher' include 'node:dist' diff --git a/verify-enclave/README.md b/verify-enclave/README.md deleted file mode 100644 index b7055a43d2..0000000000 --- a/verify-enclave/README.md +++ /dev/null @@ -1 +0,0 @@ -To build the enclavelet just run ./gradlew verify-enclave:jar diff --git a/verify-enclave/build.gradle b/verify-enclave/build.gradle deleted file mode 100644 index af2ed8b0f7..0000000000 --- a/verify-enclave/build.gradle +++ /dev/null @@ -1,97 +0,0 @@ -apply plugin: 'kotlin' - -repositories { - mavenLocal() - mavenCentral() - maven { - url 'http://oss.sonatype.org/content/repositories/snapshots' - } - jcenter() - maven { - url 'https://dl.bintray.com/kotlin/exposed' - } -} - -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -//noinspection GroovyAssignabilityCheck -configurations { - // we don't want isolated.jar in classPath, since we want to test jar being dynamically loaded as an attachment - runtime.exclude module: 'isolated' - - integrationTestCompile.extendsFrom testCompile - integrationTestRuntime.extendsFrom testRuntime -} - -sourceSets { - integrationTest { - kotlin { - compileClasspath += main.output + test.output - runtimeClasspath += main.output + test.output - srcDir file('src/integration-test/kotlin') - } - } -} - -dependencies { - compile project(':core') - compile project(':finance') - // This is added so that we include node-api/src/main/resources/META-INF/services/net.corda.core.node.CordaPluginRegistry - // which is needed for the serialisation whitelist initialisation. - // TODO think about this. - compile project(':node-api') - - compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - testCompile "org.jetbrains.kotlin:kotlin-test:$kotlin_version" - - testCompile project(':node-driver') -} - -jar { - - // De-duplicate dependencies - otherwise, they will appear multiple times in the resulting JAR file, which in turn - // will confuse ProGuard in the processing step in sgx-jvm/jvm-enclave. - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - - from '../node/capsule/NOTICE' // Copy CDDL notice - // Create a fat jar by packing all deps into the output - from { - configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } - } - exclude "META-INF/*.DSA" - exclude "META-INF/*.RSA" - exclude "META-INF/*.SF" - exclude "META-INF/*.MF" - archiveName "corda-enclavelet.jar" - manifest { - attributes( - 'Main-Class': 'com.r3.enclaves.txverify.Enclavelet', - ) - } -} - -task integrationTest(type: Test) { - testClassesDirs = sourceSets.integrationTest.output.classesDirs - classpath = sourceSets.integrationTest.runtimeClasspath - systemProperties['java.library.path'] = '../sgx-jvm/jvm-enclave/jni/build' -} - -test { - // Pending Gradle bug: https://github.com/gradle/gradle/issues/2657 - //systemProperties['java.system.class.loader'] = 'com.r3.enclaves.DummySystemClassLoader' -} - -task generateNativeSgxHeaders(type: Exec) { - def classpath = sourceSets.main.output.classesDirs.asPath - commandLine "javah", "-o", "$buildDir/native/include/jni_sgx_api.h", "-cp", classpath, "com.r3.enclaves.txverify.NativeSgxApi" - dependsOn classes -} diff --git a/verify-enclave/src/integration-test/kotlin/com/r3/enclaves/verify/NativeSgxApiTest.kt b/verify-enclave/src/integration-test/kotlin/com/r3/enclaves/verify/NativeSgxApiTest.kt deleted file mode 100644 index b2a67ecd22..0000000000 --- a/verify-enclave/src/integration-test/kotlin/com/r3/enclaves/verify/NativeSgxApiTest.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package com.r3.enclaves.verify - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever -import com.r3.enclaves.txverify.MockContractAttachment -import com.r3.enclaves.txverify.NativeSgxApi -import com.r3.enclaves.txverify.TransactionVerificationRequest -import net.corda.core.crypto.entropyToKeyPair -import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.CordaX500Name -import net.corda.core.identity.Party -import net.corda.core.serialization.serialize -import net.corda.finance.POUNDS -import net.corda.finance.`issued by` -import net.corda.finance.contracts.asset.Cash -import net.corda.node.services.api.IdentityServiceInternal -import net.corda.testing.core.DUMMY_NOTARY_NAME -import net.corda.testing.core.TestIdentity -import net.corda.testing.core.getTestPartyAndCertificate -import net.corda.testing.internal.rigorousMock -import net.corda.testing.node.MockServices -import net.corda.testing.node.ledger -import org.junit.Ignore -import org.junit.Test -import java.math.BigInteger -import kotlin.test.assertNull - -class NativeSgxApiTest { - companion object { - val enclavePath = "../sgx-jvm/jvm-enclave/enclave/build/cordaenclave.signed.so" - val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party - val DUMMY_CASH_ISSUER_KEY = entropyToKeyPair(BigInteger.valueOf(10)) - val DUMMY_CASH_ISSUER_IDENTITY = getTestPartyAndCertificate(Party(CordaX500Name("Snake Oil Issuer", "London", "GB"), DUMMY_CASH_ISSUER_KEY.public)) - val DUMMY_CASH_ISSUER = DUMMY_CASH_ISSUER_IDENTITY.party.ref(1) - val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")) - val MEGA_CORP get() = megaCorp.party - val MEGA_CORP_PUBKEY get() = megaCorp.keyPair.public - val MINI_CORP_PUBKEY = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).keyPair.public - } - - private val ledgerServices = MockServices(emptyList(), NativeSgxApiTest.MEGA_CORP.name, rigorousMock().also { - doReturn(NativeSgxApiTest.MEGA_CORP).whenever(it).partyFromKey(NativeSgxApiTest.MEGA_CORP_PUBKEY) - }) - - @Ignore("The SGX code is not part of the standard build yet") - @Test - fun `verification of valid transaction works`() { - ledgerServices.ledger(DUMMY_NOTARY) { - // Issue a couple of cash states and spend them. - val wtx1 = transaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "c1", Cash.State(1000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY))) - command(DUMMY_CASH_ISSUER.party.owningKey, Cash.Commands.Issue()) - verifies() - } - val wtx2 = transaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "c2", Cash.State(2000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY))) - command(DUMMY_CASH_ISSUER.party.owningKey, Cash.Commands.Issue()) - verifies() - } - val wtx3 = transaction { - attachments(Cash.PROGRAM_ID) - input("c1") - input("c2") - output(Cash.PROGRAM_ID, "c3", Cash.State(3000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MINI_CORP_PUBKEY))) - command(MEGA_CORP_PUBKEY, Cash.Commands.Move()) - verifies() - } - val cashContract = MockContractAttachment(interpreter.services.cordappProvider.getContractAttachmentID(Cash.PROGRAM_ID)!!, Cash.PROGRAM_ID) - val req = TransactionVerificationRequest(wtx3.serialize(), arrayOf(wtx1.serialize(), wtx2.serialize()), arrayOf(cashContract.serialize().bytes)) - val serialized = req.serialize() - assertNull(NativeSgxApi.verify(enclavePath, serialized.bytes)) - } - } -} \ No newline at end of file diff --git a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/Enclavelet.kt b/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/Enclavelet.kt deleted file mode 100644 index 31eb86641c..0000000000 --- a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/Enclavelet.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -@file:JvmName("Enclavelet") - -package com.r3.enclaves.txverify - -import net.corda.core.contracts.Attachment -import net.corda.core.serialization.CordaSerializable -import net.corda.core.serialization.SerializedBytes -import net.corda.core.serialization.deserialize -import net.corda.core.transactions.LedgerTransaction -import net.corda.core.transactions.WireTransaction -import java.io.File - -// This file implements the functionality of the SGX transaction verification enclave. - -/** This is just used to simplify marshalling across the enclave boundary (EDL is a bit awkward) */ -@CordaSerializable -class TransactionVerificationRequest(private val wtxToVerify: SerializedBytes, - private val dependencies: Array>, - val attachments: Array) { - fun toLedgerTransaction(): LedgerTransaction { - val deps = dependencies.map { it.deserialize() }.associateBy(WireTransaction::id) - val attachments = attachments.map { it.deserialize() } - val attachmentMap = attachments.associateBy(Attachment::id) - val contractAttachmentMap = attachments.mapNotNull { it as? MockContractAttachment }.associateBy(MockContractAttachment::contract) - return wtxToVerify.deserialize().toLedgerTransaction( - resolveIdentity = { null }, - resolveAttachment = { attachmentMap[it] }, - resolveStateRef = { deps[it.txhash]?.outputs?.get(it.index) }, - resolveContractAttachment = { contractAttachmentMap[it.contract]?.id } - ) - } -} - -/** - * Returns either null to indicate success when the transactions are validated, or a string with the - * contents of the error. Invoked via JNI in response to an enclave RPC. The argument is a serialised - * [TransactionVerificationRequest]. - * - * Note that it is assumed the signatures were already checked outside the sandbox: the purpose of this code - * is simply to check the sensitive, app specific parts of a transaction. - * - * TODO: Transaction data is meant to be encrypted under an enclave-private key. - */ -@Throws(Exception::class) -fun verifyInEnclave(reqBytes: ByteArray) { - var ex: Throwable? = null - val ltx = deserialise(reqBytes) - // Prevent this thread from linking new classes against any - // blacklisted classes, e.g. ones needed by Kryo or by the - // JVM itself. Note that java.lang.Thread is also blacklisted. - Thread { - ltx.verify() - }.apply { - startClassBlacklisting(this) - setUncaughtExceptionHandler { _, e -> ex = e } - start() - join() - } - throw ex ?: return -} - -private fun startClassBlacklisting(t: Thread) { - val systemClassLoader = ClassLoader.getSystemClassLoader() - systemClassLoader.javaClass.getMethod("startBlacklisting", t.javaClass).apply { - invoke(systemClassLoader, t) - } -} - -private fun deserialise(reqBytes: ByteArray): LedgerTransaction { - return reqBytes.deserialize() - .toLedgerTransaction() -} - -// Note: This is only here for debugging purposes -fun main(args: Array) { - Class.forName("com.r3.enclaves.txverify.EnclaveletSerializationScheme") - val reqBytes = File(args[0]).readBytes() - verifyInEnclave(reqBytes) -} \ No newline at end of file diff --git a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/EnclaveletSerializationScheme.kt b/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/EnclaveletSerializationScheme.kt deleted file mode 100644 index 8a8ecb4cb1..0000000000 --- a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/EnclaveletSerializationScheme.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -@file:JvmName("EnclaveletSerializationScheme") -package com.r3.enclaves.txverify - -import net.corda.core.serialization.SerializationContext -import net.corda.core.serialization.internal.SerializationEnvironmentImpl -import net.corda.core.serialization.internal.nodeSerializationEnv -import net.corda.core.utilities.toHexString -import net.corda.serialization.internal.AMQP_P2P_CONTEXT -import net.corda.serialization.internal.CordaSerializationMagic -import net.corda.serialization.internal.SerializationFactoryImpl -import net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme -import net.corda.serialization.internal.amqp.SerializerFactory -import net.corda.serialization.internal.amqp.amqpMagic - -@Suppress("UNUSED") -private class EnclaveletSerializationScheme { - /* - * Registers the serialisation schemes as soon as this class is loaded into the JVM. - */ - private companion object { - init { - nodeSerializationEnv = SerializationEnvironmentImpl( - SerializationFactoryImpl(HashMap()).apply { - registerScheme(AMQPVerifierSerializationScheme) - }, - /** - * Even though default context is set to Amqp P2P, the encoding will be adjusted depending on the - * incoming request received. - */ - AMQP_P2P_CONTEXT) - - /* - * Ensure that we initialise JAXP before blacklisting is enabled. - */ - ByteArray(0).toHexString() - } - } -} - -private object AMQPVerifierSerializationScheme : AbstractAMQPSerializationScheme(emptySet(), HashMap()) { - override fun canDeserializeVersion(magic: CordaSerializationMagic, target: SerializationContext.UseCase): Boolean { - return magic == amqpMagic && target == SerializationContext.UseCase.P2P - } - - override fun rpcClientSerializerFactory(context: SerializationContext): SerializerFactory = throw UnsupportedOperationException() - override fun rpcServerSerializerFactory(context: SerializationContext): SerializerFactory = throw UnsupportedOperationException() -} diff --git a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/MockContractAttachment.kt b/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/MockContractAttachment.kt deleted file mode 100644 index 8b22f5e102..0000000000 --- a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/MockContractAttachment.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package com.r3.enclaves.txverify - -import net.corda.core.contracts.Attachment -import net.corda.core.contracts.ContractClassName -import net.corda.core.crypto.SecureHash -import net.corda.core.identity.Party -import net.corda.core.serialization.CordaSerializable -import java.io.ByteArrayInputStream - -@CordaSerializable -class MockContractAttachment(override val id: SecureHash = SecureHash.zeroHash, val contract: ContractClassName, override val signers: List = ArrayList()) : Attachment { - override fun open() = ByteArrayInputStream(id.bytes) - override val size = id.size -} \ No newline at end of file diff --git a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/NativeSgxApi.kt b/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/NativeSgxApi.kt deleted file mode 100644 index 5f989553b4..0000000000 --- a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/NativeSgxApi.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package com.r3.enclaves.txverify - -object NativeSgxApi { - - init { - System.loadLibrary("untrusted_corda_sgx") - } - - @JvmStatic - external fun verify(enclavePath: String, transactionBytes: ByteArray): String? -} diff --git a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/SgxSecureRandomSpi.kt b/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/SgxSecureRandomSpi.kt deleted file mode 100644 index 35157385f9..0000000000 --- a/verify-enclave/src/main/kotlin/com/r3/enclaves/txverify/SgxSecureRandomSpi.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package com.r3.enclaves.txverify - -import java.security.SecureRandomSpi - -class SgxSecureRandomSpi : SecureRandomSpi() { - override fun engineSetSeed(p0: ByteArray?) { - println("SgxSecureRandomSpi.engineSetSeed called") - } - - override fun engineNextBytes(p0: ByteArray?) { - println("SgxSecureRandomSpi.engineNextBytes called") - } - - override fun engineGenerateSeed(numberOfBytes: Int): ByteArray { - println("SgxSecureRandomSpi.engineGenerateSeed called") - return ByteArray(numberOfBytes) - } -} \ No newline at end of file diff --git a/verify-enclave/src/test/kotlin/com/r3/enclaves/DummySystemClassLoader.kt b/verify-enclave/src/test/kotlin/com/r3/enclaves/DummySystemClassLoader.kt deleted file mode 100644 index c9599b6f40..0000000000 --- a/verify-enclave/src/test/kotlin/com/r3/enclaves/DummySystemClassLoader.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package com.r3.enclaves - -@Suppress("unused", "unused_parameter") -class DummySystemClassLoader(parent: ClassLoader) : ClassLoader(parent) { - fun startBlacklisting(t: Thread) {} -} diff --git a/verify-enclave/src/test/kotlin/com/r3/enclaves/txverify/EnclaveletTest.kt b/verify-enclave/src/test/kotlin/com/r3/enclaves/txverify/EnclaveletTest.kt deleted file mode 100644 index 293021786d..0000000000 --- a/verify-enclave/src/test/kotlin/com/r3/enclaves/txverify/EnclaveletTest.kt +++ /dev/null @@ -1,120 +0,0 @@ -/* - * R3 Proprietary and Confidential - * - * Copyright (c) 2018 R3 Limited. All rights reserved. - * - * The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law. - * - * Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited. - */ - -package com.r3.enclaves.txverify - -import com.nhaarman.mockito_kotlin.doReturn -import com.nhaarman.mockito_kotlin.whenever -import net.corda.core.crypto.entropyToKeyPair -import net.corda.core.identity.AnonymousParty -import net.corda.core.identity.CordaX500Name -import net.corda.core.identity.Party -import net.corda.core.serialization.serialize -import net.corda.finance.POUNDS -import net.corda.finance.`issued by` -import net.corda.finance.contracts.asset.Cash -import net.corda.node.services.api.IdentityServiceInternal -import net.corda.testing.core.* -import net.corda.testing.internal.rigorousMock -import net.corda.testing.node.MockServices -import net.corda.testing.node.ledger -import org.junit.Ignore -import org.junit.Rule -import org.junit.Test -import java.math.BigInteger -import java.nio.file.Files -import java.nio.file.Paths -import kotlin.test.assertFailsWith -import kotlin.test.assertTrue - -class EnclaveletTest { - private companion object { - val DUMMY_NOTARY = TestIdentity(DUMMY_NOTARY_NAME, 20).party - val DUMMY_CASH_ISSUER_KEY = entropyToKeyPair(BigInteger.valueOf(10)) - val DUMMY_CASH_ISSUER_IDENTITY = getTestPartyAndCertificate(Party(CordaX500Name("Snake Oil Issuer", "London", "GB"), DUMMY_CASH_ISSUER_KEY.public)) - val DUMMY_CASH_ISSUER = DUMMY_CASH_ISSUER_IDENTITY.party.ref(1) - val megaCorp = TestIdentity(CordaX500Name("MegaCorp", "London", "GB")) - val MEGA_CORP get() = megaCorp.party - val MEGA_CORP_PUBKEY get() = megaCorp.keyPair.public - val MINI_CORP_PUBKEY = TestIdentity(CordaX500Name("MiniCorp", "London", "GB")).keyPair.public - } - @Rule - @JvmField - val testSerialization = SerializationEnvironmentRule() - - private val ledgerServices = MockServices(emptyList(), MEGA_CORP.name, rigorousMock().also { - doReturn(MEGA_CORP).whenever(it).partyFromKey(MEGA_CORP_PUBKEY) - }) - - @Ignore("Pending Gradle bug: https://github.com/gradle/gradle/issues/2657") - @Test - fun success() { - ledgerServices.ledger(DUMMY_NOTARY) { - // Issue a couple of cash states and spend them. - val wtx1 = transaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "c1", Cash.State(1000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY))) - command(DUMMY_CASH_ISSUER.party.owningKey, Cash.Commands.Issue()) - verifies() - } - val wtx2 = transaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "c2", Cash.State(2000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY))) - command(DUMMY_CASH_ISSUER.party.owningKey, Cash.Commands.Issue()) - verifies() - } - val wtx3 = transaction { - attachments(Cash.PROGRAM_ID) - input("c1") - input("c2") - output(Cash.PROGRAM_ID, "c3", Cash.State(3000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MINI_CORP_PUBKEY))) - command(MEGA_CORP_PUBKEY, Cash.Commands.Move()) - verifies() - } - val cashContract = MockContractAttachment(interpreter.services.cordappProvider.getContractAttachmentID(Cash.PROGRAM_ID)!!, Cash.PROGRAM_ID) - val req = TransactionVerificationRequest(wtx3.serialize(), arrayOf(wtx1.serialize(), wtx2.serialize()), arrayOf(cashContract.serialize().bytes)) - val serialized = req.serialize() - Files.write(Paths.get(System.getProperty("java.io.tmpdir"), "req"), serialized.bytes) - verifyInEnclave(serialized.bytes) - } - } - - @Ignore("Pending Gradle bug: https://github.com/gradle/gradle/issues/2657") - @Test - fun fail() { - ledgerServices.ledger(DUMMY_NOTARY) { - // Issue a couple of cash states and spend them. - val wtx1 = transaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "c1", Cash.State(1000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY))) - command(DUMMY_CASH_ISSUER.party.owningKey, Cash.Commands.Issue()) - verifies() - } - val wtx2 = transaction { - attachments(Cash.PROGRAM_ID) - output(Cash.PROGRAM_ID, "c2", Cash.State(2000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MEGA_CORP_PUBKEY))) - command(DUMMY_CASH_ISSUER.party.owningKey, Cash.Commands.Issue()) - verifies() - } - val wtx3 = transaction { - attachments(Cash.PROGRAM_ID) - input("c1") - input("c2") - command(DUMMY_CASH_ISSUER.party.owningKey, DummyCommandData) - output(Cash.PROGRAM_ID, "c3", Cash.State(3000.POUNDS `issued by` DUMMY_CASH_ISSUER, AnonymousParty(MINI_CORP_PUBKEY))) - failsWith("Required ${Cash.Commands.Move::class.java.canonicalName} command") - } - val cashContract = MockContractAttachment(interpreter.services.cordappProvider.getContractAttachmentID(Cash.PROGRAM_ID)!!, Cash.PROGRAM_ID) - val req = TransactionVerificationRequest(wtx3.serialize(), arrayOf(wtx1.serialize(), wtx2.serialize()), arrayOf(cashContract.serialize().bytes)) - val e = assertFailsWith { verifyInEnclave(req.serialize().bytes) } - assertTrue(e.message!!.contains("Required ${Cash.Commands.Move::class.java.canonicalName} command")) - } - } -} \ No newline at end of file