Remove verify-enclave

This commit is contained in:
Andras Slemmer 2018-06-22 10:31:00 +01:00
parent dcfcd4f64b
commit 013f1a3cb6
12 changed files with 23 additions and 544 deletions

23
.idea/compiler.xml generated
View File

@ -45,6 +45,8 @@
<module name="capsule-hsm_test" target="1.8" />
<module name="client_main" target="1.8" />
<module name="client_test" target="1.8" />
<module name="common_main" target="1.8" />
<module name="common_test" target="1.8" />
<module name="confidential-identities_main" target="1.8" />
<module name="confidential-identities_test" target="1.8" />
<module name="contracts-states_integrationTest" target="1.8" />
@ -53,6 +55,8 @@
<module name="corda-core_integrationTest" target="1.8" />
<module name="corda-core_smokeTest" target="1.8" />
<module name="corda-finance_integrationTest" target="1.8" />
<module name="corda-project-testing_main" target="1.8" />
<module name="corda-project-testing_test" target="1.8" />
<module name="corda-project-tools_main" target="1.8" />
<module name="corda-project-tools_test" target="1.8" />
<module name="corda-project_main" target="1.8" />
@ -73,11 +77,17 @@
<module name="cordformation_main" target="1.8" />
<module name="cordformation_runnodes" target="1.8" />
<module name="cordformation_test" target="1.8" />
<module name="core-deterministic-testing_main" target="1.8" />
<module name="core-deterministic-testing_test" target="1.8" />
<module name="core-deterministic_main" target="1.8" />
<module name="core-deterministic_test" target="1.8" />
<module name="core_extraResource" target="1.8" />
<module name="core_integrationTest" target="1.8" />
<module name="core_main" target="1.8" />
<module name="core_smokeTest" target="1.8" />
<module name="core_test" target="1.8" />
<module name="data_main" target="1.8" />
<module name="data_test" target="1.8" />
<module name="dbmigration_main" target="1.8" />
<module name="dbmigration_test" target="1.8" />
<module name="demobench_main" target="1.8" />
@ -122,6 +132,8 @@
<module name="graphs_test" target="1.8" />
<module name="ha-testing_main" target="1.8" />
<module name="ha-testing_test" target="1.8" />
<module name="hsm-tool_main" target="1.8" />
<module name="hsm-tool_test" target="1.8" />
<module name="intellij-plugin_main" target="1.8" />
<module name="intellij-plugin_test" target="1.8" />
<module name="irs-demo-cordapp_integrationTest" target="1.8" />
@ -139,6 +151,10 @@
<module name="isolated_test" target="1.8" />
<module name="jackson_main" target="1.8" />
<module name="jackson_test" target="1.8" />
<module name="jarfilter_main" target="1.8" />
<module name="jarfilter_test" target="1.8" />
<module name="jdk8u-deterministic_main" target="1.8" />
<module name="jdk8u-deterministic_test" target="1.8" />
<module name="jfx_integrationTest" target="1.8" />
<module name="jfx_main" target="1.8" />
<module name="jfx_test" target="1.8" />
@ -200,10 +216,15 @@
<module name="samples_test" target="1.8" />
<module name="sandbox_main" target="1.8" />
<module name="sandbox_test" target="1.8" />
<module name="serialization-deterministic_main" target="1.8" />
<module name="serialization-deterministic_test" target="1.8" />
<module name="serialization_main" target="1.8" />
<module name="serialization_test" target="1.8" />
<module name="sgx-hsm-tool_main" target="1.8" />
<module name="sgx-hsm-tool_test" target="1.8" />
<module name="shell-cli_integrationTest" target="1.8" />
<module name="shell-cli_main" target="1.8" />
<module name="shell-cli_test" target="1.8" />
<module name="shell_integrationTest" target="1.8" />
<module name="shell_main" target="1.8" />
<module name="shell_test" target="1.8" />
@ -239,6 +260,8 @@
<module name="trader-demo_integrationTest" target="1.8" />
<module name="trader-demo_main" target="1.8" />
<module name="trader-demo_test" target="1.8" />
<module name="unwanteds_main" target="1.8" />
<module name="unwanteds_test" target="1.8" />
<module name="verifier_integrationTest" target="1.8" />
<module name="verifier_main" target="1.8" />
<module name="verifier_test" target="1.8" />

View File

@ -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'

View File

@ -1 +0,0 @@
To build the enclavelet just run ./gradlew verify-enclave:jar

View File

@ -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
}

View File

@ -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<IdentityServiceInternal>().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))
}
}
}

View File

@ -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<WireTransaction>,
private val dependencies: Array<SerializedBytes<WireTransaction>>,
val attachments: Array<ByteArray>) {
fun toLedgerTransaction(): LedgerTransaction {
val deps = dependencies.map { it.deserialize() }.associateBy(WireTransaction::id)
val attachments = attachments.map { it.deserialize<Attachment>() }
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<TransactionVerificationRequest>()
.toLedgerTransaction()
}
// Note: This is only here for debugging purposes
fun main(args: Array<String>) {
Class.forName("com.r3.enclaves.txverify.EnclaveletSerializationScheme")
val reqBytes = File(args[0]).readBytes()
verifyInEnclave(reqBytes)
}

View File

@ -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()
}

View File

@ -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<Party> = ArrayList()) : Attachment {
override fun open() = ByteArrayInputStream(id.bytes)
override val size = id.size
}

View File

@ -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?
}

View File

@ -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)
}
}

View File

@ -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) {}
}

View File

@ -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<IdentityServiceInternal>().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<Exception> { verifyInEnclave(req.serialize().bytes) }
assertTrue(e.message!!.contains("Required ${Cash.Commands.Move::class.java.canonicalName} command"))
}
}
}