diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index df4cb63a3f..992b76d1a6 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -85,7 +85,7 @@ class CommercialPaperTestsGeneric { input("paper") input("alice's $900") output("borrowed $900") { 900.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } - output("alice's paper") { "paper".output().data `owned by` ALICE_PUBKEY } + output("alice's paper") { "paper".output() `owned by` ALICE_PUBKEY } command(ALICE_PUBKEY) { Cash.Commands.Move() } command(MEGA_CORP_PUBKEY) { thisTest.getMoveCommand() } this.verifies() @@ -120,7 +120,7 @@ class CommercialPaperTestsGeneric { timestamp(TEST_TX_TIME + 8.days) tweak { - output { "paper".output().data } + output { "paper".output() } this `fails with` "must be destroyed" } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt index e771e25140..ad5e16482f 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt @@ -377,11 +377,11 @@ class IRSTests { input("irs post agreement") val postAgreement = "irs post agreement".output() output("irs post first fixing") { - postAgreement.data.copy( - postAgreement.data.fixedLeg, - postAgreement.data.floatingLeg, - postAgreement.data.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), - postAgreement.data.common + postAgreement.copy( + postAgreement.fixedLeg, + postAgreement.floatingLeg, + postAgreement.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), + postAgreement.common ) } command(ORACLE_PUBKEY) { @@ -693,20 +693,20 @@ class IRSTests { input("irs post agreement2") val postAgreement1 = "irs post agreement1".output() output("irs post first fixing1") { - postAgreement1.data.copy( - postAgreement1.data.fixedLeg, - postAgreement1.data.floatingLeg, - postAgreement1.data.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))), - postAgreement1.data.common.copy(tradeID = "t1") + postAgreement1.copy( + postAgreement1.fixedLeg, + postAgreement1.floatingLeg, + postAgreement1.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))), + postAgreement1.common.copy(tradeID = "t1") ) } val postAgreement2 = "irs post agreement2".output() output("irs post first fixing2") { - postAgreement2.data.copy( - postAgreement2.data.fixedLeg, - postAgreement2.data.floatingLeg, - postAgreement2.data.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))), - postAgreement2.data.common.copy(tradeID = "t2") + postAgreement2.copy( + postAgreement2.fixedLeg, + postAgreement2.floatingLeg, + postAgreement2.calculation.applyFixing(ld1, FixedRate(RatioUnit(bd1))), + postAgreement2.common.copy(tradeID = "t2") ) } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/TmpTest.java b/contracts/src/test/kotlin/com/r3corda/contracts/asset/TmpTest.java new file mode 100644 index 0000000000..79acf19ae9 --- /dev/null +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/TmpTest.java @@ -0,0 +1,225 @@ +package com.r3corda.contracts.asset; + +import kotlin.Unit; +import org.junit.Test; + +import static com.r3corda.core.testing.JavaTestHelpers.*; +import static com.r3corda.core.contracts.JavaTestHelpers.*; + +public class TmpTest { + + public static class Asd { + @Test + public void emptyLedger() { + ledger(l -> { + return Unit.INSTANCE; + }); + } +// +// @Test +// public void simpleCashDoesntCompile() { +// Cash.State inState = new Cash.State( +// issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), +// getDUMMY_PUBKEY_1() +// ); +// ledger(l -> { +// l.transaction(tx -> { +// tx.input(inState); +// }); +// return Unit.INSTANCE; +// }); +// } + + @Test + public void simpleCash() { + Cash.State inState = new Cash.State( + issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), + getDUMMY_PUBKEY_1() + ); + ledger(l -> { + l.transaction(tx -> { + tx.input(inState); + return tx.verifies(); + }); + return Unit.INSTANCE; + }); + } + + @Test + public void simpleCashFailsWith() { + Cash.State inState = new Cash.State( + issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), + getDUMMY_PUBKEY_1() + ); + ledger(l -> { + l.transaction(tx -> { + tx.input(inState); + return tx.failsWith("the amounts balance"); + }); + return Unit.INSTANCE; + }); + } + + @Test + public void simpleCashSuccess() { + Cash.State inState = new Cash.State( + issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), + getDUMMY_PUBKEY_1() + ); + ledger(l -> { + l.transaction(tx -> { + tx.input(inState); + tx.failsWith("the amounts balance"); + tx.output(inState.copy(inState.getAmount(), getDUMMY_PUBKEY_2())); + tx.command(getDUMMY_PUBKEY_1(), new Cash.Commands.Move()); + return tx.verifies(); + }); + return Unit.INSTANCE; + }); + } + + @Test + public void simpleCashTweakSuccess() { + Cash.State inState = new Cash.State( + issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), + getDUMMY_PUBKEY_1() + ); + ledger(l -> { + l.transaction(tx -> { + tx.input(inState); + tx.failsWith("the amounts balance"); + tx.output(inState.copy(inState.getAmount(), getDUMMY_PUBKEY_2())); + + tx.tweak(tw -> { + tw.command(getDUMMY_PUBKEY_2(), new Cash.Commands.Move()); + return tw.failsWith("the owning keys are the same as the signing keys"); + }); + tx.command(getDUMMY_PUBKEY_1(), new Cash.Commands.Move()); + return tx.verifies(); + }); + return Unit.INSTANCE; + }); + } + + @Test + public void simpleCashTweakSuccessTopLevelTransaction() { + Cash.State inState = new Cash.State( + issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), + getDUMMY_PUBKEY_1() + ); + transaction(tx -> { + tx.input(inState); + tx.failsWith("the amounts balance"); + tx.output(inState.copy(inState.getAmount(), getDUMMY_PUBKEY_2())); + + tx.tweak(tw -> { + tw.command(getDUMMY_PUBKEY_2(), new Cash.Commands.Move()); + return tw.failsWith("the owning keys are the same as the signing keys"); + }); + tx.command(getDUMMY_PUBKEY_1(), new Cash.Commands.Move()); + return tx.verifies(); + }); + } + + + @Test + public void chainCash() { + ledger(l -> { + l.unverifiedTransaction(tx -> { + tx.output("MEGA_CORP cash", + new Cash.State( + issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), + getMEGA_CORP_PUBKEY() + ) + ); + return Unit.INSTANCE; + }); + + l.transaction(tx -> { + tx.input("MEGA_CORP cash"); + Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash"); + tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_1())); + tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move()); + return tx.verifies(); + }); + + return Unit.INSTANCE; + }); + } + + @Test + public void chainCashDoubleSpend() { + ledger(l -> { + l.unverifiedTransaction(tx -> { + tx.output("MEGA_CORP cash", + new Cash.State( + issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), + getMEGA_CORP_PUBKEY() + ) + ); + return Unit.INSTANCE; + }); + + l.transaction(tx -> { + tx.input("MEGA_CORP cash"); + Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash"); + tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_1())); + tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move()); + return tx.verifies(); + }); + + l.transaction(tx -> { + tx.input("MEGA_CORP cash"); + Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash"); + // We send it to another pubkey so that the transaction is not identical to the previous one + tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_2())); + tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move()); + return tx.verifies(); + }); + + return Unit.INSTANCE; + }); + } + + @Test + public void chainCashDoubleSpendFailsWith() { + ledger(l -> { + l.unverifiedTransaction(tx -> { + tx.output("MEGA_CORP cash", + new Cash.State( + issuedBy(DOLLARS(1000), getMEGA_CORP().ref((byte)1, (byte)1)), + getMEGA_CORP_PUBKEY() + ) + ); + return Unit.INSTANCE; + }); + + l.transaction(tx -> { + tx.input("MEGA_CORP cash"); + Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash"); + tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_1())); + tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move()); + return tx.verifies(); + }); + + l.tweak(lw -> { + lw.transaction(tx -> { + tx.input("MEGA_CORP cash"); + Cash.State inputCash = l.retrieveOutput(Cash.State.class, "MEGA_CORP cash"); + // We send it to another pubkey so that the transaction is not identical to the previous one + tx.output(inputCash.copy(inputCash.getAmount(), getDUMMY_PUBKEY_2())); + tx.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move()); + return tx.verifies(); + }); + lw.fails(); + return Unit.INSTANCE; + }); + + l.verifies(); + return Unit.INSTANCE; + }); + } + + + } +} diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/TmpTest.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/TmpTest.kt new file mode 100644 index 0000000000..e77b341846 --- /dev/null +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/TmpTest.kt @@ -0,0 +1,209 @@ +package com.r3corda.contracts.asset + +import com.r3corda.core.contracts.DOLLARS +import com.r3corda.core.contracts.`issued by` +import com.r3corda.core.testing.* +import org.junit.Test + + +class Asd { + + class Asd { + + @Test + fun emptyLedger() { + ledger { + } + } +// +// @Test +// fun simpleCashFails() { +// ledger { +// transaction { +// input(Cash.State( +// amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), +// owner = DUMMY_PUBKEY_1 +// )) +// this.verifies() +// } +// } +// } + + @Test + fun simpleCash() { + val inState = Cash.State( + amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), + owner = DUMMY_PUBKEY_1 + ) + ledger { + transaction { + input(inState) + this.verifies() + } + } + } + + @Test + fun simpleCashFailsWith() { + val inState = Cash.State( + amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), + owner = DUMMY_PUBKEY_1 + ) + ledger { + transaction { + input(inState) + this `fails with` "the amounts balance" + } + } + } + + @Test + fun simpleCashSuccess() { + val inState = Cash.State( + amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), + owner = DUMMY_PUBKEY_1 + ) + ledger { + transaction { + input(inState) + this `fails with` "the amounts balance" + output(inState.copy(owner = DUMMY_PUBKEY_2)) + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } + } + } + + @Test + fun simpleCashTweakSuccess() { + val inState = Cash.State( + amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), + owner = DUMMY_PUBKEY_1 + ) + ledger { + transaction { + input(inState) + this `fails with` "the amounts balance" + output(inState.copy(owner = DUMMY_PUBKEY_2)) + + tweak { + command(DUMMY_PUBKEY_2) { Cash.Commands.Move() } + this `fails with` "the owning keys are the same as the signing keys" + } + + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } + } + } + + @Test + fun simpleCashTweakSuccessTopLevelTransaction() { + val inState = Cash.State( + amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), + owner = DUMMY_PUBKEY_1 + ) + transaction { + input(inState) + this `fails with` "the amounts balance" + output(inState.copy(owner = DUMMY_PUBKEY_2)) + + tweak { + command(DUMMY_PUBKEY_2) { Cash.Commands.Move() } + this `fails with` "the owning keys are the same as the signing keys" + } + + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } + } + + + @Test + fun chainCash() { + ledger { + unverifiedTransaction { + output("MEGA_CORP cash") { + Cash.State( + amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), + owner = MEGA_CORP_PUBKEY + ) + } + } + + transaction { + input("MEGA_CORP cash") + output("MEGA_CORP cash".output().copy(owner = DUMMY_PUBKEY_1)) + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this.verifies() + } + } + } + + + @Test + fun chainCashDoubleSpend() { + ledger { + unverifiedTransaction { + output("MEGA_CORP cash") { + Cash.State( + amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), + owner = MEGA_CORP_PUBKEY + ) + } + } + + transaction { + input("MEGA_CORP cash") + output("MEGA_CORP cash".output().copy(owner = DUMMY_PUBKEY_1)) + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this.verifies() + } + + transaction { + input("MEGA_CORP cash") + // We send it to another pubkey so that the transaction is not identical to the previous one + output("MEGA_CORP cash".output().copy(owner = DUMMY_PUBKEY_1)) + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this.verifies() + } + } + } + + @Test + fun chainCashDoubleSpendFailsWith() { + ledger { + unverifiedTransaction { + output("MEGA_CORP cash") { + Cash.State( + amount = 1000.DOLLARS `issued by` MEGA_CORP.ref(1, 1), + owner = MEGA_CORP_PUBKEY + ) + } + } + + transaction { + input("MEGA_CORP cash") + output("MEGA_CORP cash".output().copy(owner = DUMMY_PUBKEY_1)) + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this.verifies() + } + + tweak { + transaction { + input("MEGA_CORP cash") + // We send it to another pubkey so that the transaction is not identical to the previous one + output("MEGA_CORP cash".output().copy(owner = DUMMY_PUBKEY_2)) + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this.verifies() + } + this.fails() + } + + this.verifies() + } + } + } + +} + diff --git a/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt b/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt index 70c99809a5..60c1417dd3 100644 --- a/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt +++ b/core/src/main/kotlin/com/r3corda/core/crypto/CryptoUtilities.kt @@ -169,4 +169,4 @@ operator fun KeyPair.component1() = this.private operator fun KeyPair.component2() = this.public /** A simple wrapper that will make it easier to swap out the EC algorithm we use in future */ -fun generateKeyPair() = EddsaKeyPairGenerator().generateKeyPair()!! +fun generateKeyPair(): KeyPair = EddsaKeyPairGenerator().generateKeyPair() diff --git a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt index 92b18fe99c..c80aa84a9d 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/LedgerDSLInterpreter.kt @@ -61,6 +61,12 @@ interface LedgerDSLInterpreter> : Output * Verifies the ledger using [TransactionGroup.verify], throws if the verification fails. */ fun verifies() + + /** + * Verifies the ledger, expecting an exception to be thrown. + * @param expectedMessage: An optional string to be searched for in the raised exception. + */ + fun failsWith(expectedMessage: String?) } /** @@ -97,12 +103,28 @@ class LedgerDSL, out L : LedgerDSLInterp * Retrieves the output [TransactionState] based on the label. * @see OutputStateLookup.retrieveOutputStateAndRef */ - inline fun String.output(): TransactionState = - outputStateAndRef().state + inline fun String.output(): S = + outputStateAndRef().state.data /** * Retrieves the output [StateRef] based on the label. * @see OutputStateLookup.retrieveOutputStateAndRef */ fun String.outputRef(): StateRef = outputStateAndRef().ref + + /** + * @see OutputStateLookup.retrieveOutputStateAndRef + */ + fun retrieveOutput(clazz: Class, label: String) = + retrieveOutputStateAndRef(clazz, label).state.data + + /** + * Asserts that the transaction will fail verification + */ + fun fails() = failsWith(null) + + /** + * @see TransactionDSLInterpreter.failsWith + */ + infix fun `fails with`(msg: String) = failsWith(msg) } diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt index 5b26a17698..8a820c18a0 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt @@ -161,27 +161,8 @@ data class TestTransactionDSLInterpreter private constructor( } override fun failsWith(expectedMessage: String?): EnforceVerifyOrFail { - val exceptionThrown = try { + expectExceptionContainingString(expectedMessage) { this.verifies() - false - } catch (exception: Exception) { - if (expectedMessage != null) { - val exceptionMessage = exception.message - if (exceptionMessage == null) { - throw AssertionError( - "Expected exception containing '$expectedMessage' but raised exception had no message" - ) - } else if (!exceptionMessage.toLowerCase().contains(expectedMessage.toLowerCase())) { - throw AssertionError( - "Expected exception containing '$expectedMessage' but raised exception was '$exception'" - ) - } - } - true - } - - if (!exceptionThrown) { - throw AssertionError("Expected exception but didn't get one") } return EnforceVerifyOrFail.Token @@ -202,7 +183,6 @@ data class TestLedgerDSLInterpreter private constructor ( private val transactionWithLocations: HashMap = HashMap(), private val nonVerifiedTransactionWithLocations: HashMap = HashMap() ) : LedgerDSLInterpreter { - val wireTransactions: List get() = transactionWithLocations.values.map { it.transaction } // We specify [labelToOutputStateAndRefs] just so that Kotlin picks the primary constructor instead of cycling @@ -211,19 +191,25 @@ data class TestLedgerDSLInterpreter private constructor ( ) companion object { - private fun getCallerLocation(offset: Int): String { - val stackTraceElement = Thread.currentThread().stackTrace[3 + offset] - return stackTraceElement.toString() + private fun getCallerLocation(): String? { + val stackTrace = Thread.currentThread().stackTrace + for (i in 1 .. stackTrace.size) { + val stackTraceElement = stackTrace[i] + if (!stackTraceElement.fileName.contains("DSL")) { + return stackTraceElement.toString() + } + } + return null } } internal data class WireTransactionWithLocation( val label: String?, val transaction: WireTransaction, - val location: String + val location: String? ) - class VerifiesFailed(transactionLocation: String, cause: Throwable) : - Exception("Transaction defined at ($transactionLocation) didn't verify: $cause", cause) + class VerifiesFailed(transactionName: String, cause: Throwable) : + Exception("Transaction ($transactionName) didn't verify: $cause", cause) class TypeMismatch(requested: Class<*>, actual: Class<*>) : Exception("Actual type $actual is not a subtype of requested type $requested") @@ -309,7 +295,7 @@ data class TestLedgerDSLInterpreter private constructor ( dsl: TransactionDSL.() -> R, transactionMap: HashMap = HashMap() ): WireTransaction { - val transactionLocation = getCallerLocation(3) + val transactionLocation = getCallerLocation() val transactionInterpreter = interpretTransactionDsl(transactionBuilder, dsl) // Create the WireTransaction val wireTransaction = transactionInterpreter.toWireTransaction() @@ -353,7 +339,15 @@ data class TestLedgerDSLInterpreter private constructor ( try { transactionGroup.verify() } catch (exception: TransactionVerificationException) { - throw VerifiesFailed(transactionWithLocations[exception.tx.origHash]?.location ?: "", exception) + val transactionWithLocation = transactionWithLocations[exception.tx.origHash] + val transactionName = transactionWithLocation?.label ?: transactionWithLocation?.location ?: "" + throw VerifiesFailed(transactionName, exception) + } + } + + override fun failsWith(expectedMessage: String?) { + expectExceptionContainingString(expectedMessage) { + this.verifies() } } @@ -397,3 +391,28 @@ fun signAll(transactionsToSign: List, extraKeys: Array.signAll( vararg extraKeys: KeyPair) = signAll(this.interpreter.wireTransactions, extraKeys) + +internal inline fun expectExceptionContainingString(string: String?, body:() -> Unit) { + val exceptionThrown = try { + body() + false + } catch (exception: Exception) { + if (string != null) { + val exceptionMessage = exception.message + if (exceptionMessage == null) { + throw AssertionError( + "Expected exception containing '$string' but raised exception had no message" + ) + } else if (!exceptionMessage.toLowerCase().contains(string.toLowerCase())) { + throw AssertionError( + "Expected exception containing '$string' but raised exception was '$exception'" + ) + } + } + true + } + + if (!exceptionThrown) { + throw AssertionError("Expected exception but didn't get one") + } +} diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt index 6b93ec3294..2816d77990 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TransactionDSLInterpreter.kt @@ -96,10 +96,12 @@ class TransactionDSL> (val interpreter: /** * @see TransactionDSLInterpreter._output */ - @JvmOverloads - fun output(label: String? = null, contractState: ContractState) = + fun output(label: String, contractState: ContractState) = _output(label, DUMMY_NOTARY, contractState) + fun output(contractState: ContractState) = + _output(null, DUMMY_NOTARY, contractState) + /** * @see TransactionDSLInterpreter._command */ diff --git a/node/src/main/kotlin/com/r3corda/node/internal/testing/MockNode.kt b/node/src/main/kotlin/com/r3corda/node/internal/testing/MockNode.kt index 6245192984..cdb5699b91 100644 --- a/node/src/main/kotlin/com/r3corda/node/internal/testing/MockNode.kt +++ b/node/src/main/kotlin/com/r3corda/node/internal/testing/MockNode.kt @@ -88,7 +88,7 @@ class MockNetwork(private val networkSendManuallyPumped: Boolean = false, // Nothing to do } - override fun generateKeyPair(): KeyPair? = keyPair ?: super.generateKeyPair() + override fun generateKeyPair(): KeyPair = keyPair ?: super.generateKeyPair() // It's OK to not have a network map service in the mock network. override fun noNetworkMapConfigured() = Futures.immediateFuture(Unit)