diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt index 44a6d12700..c4b01fd7b1 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/CommercialPaperTests.kt @@ -97,7 +97,7 @@ class CommercialPaperTestsGeneric { input("alice's paper") input("some profits") - fun TransactionDSL>.outputs(aliceGetsBack: Amount>) { + fun TransactionDSL>.outputs(aliceGetsBack: Amount>) { output("Alice's profit") { aliceGetsBack.STATE `owned by` ALICE_PUBKEY } output("Change") { (someProfits - aliceGetsBack).STATE `owned by` MEGA_CORP_PUBKEY } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt index 6d10560a42..e771e25140 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/IRSTests.kt @@ -360,7 +360,7 @@ class IRSTests { /** * Generates a typical transactional history for an IRS. */ - fun trade(): LedgerDSL { + fun trade(): LedgerDSL { val ld = LocalDate.of(2016, 3, 8) val bd = BigDecimal("0.0063518") @@ -555,96 +555,93 @@ class IRSTests { @Test fun `various fixing tests`() { - ledger { + val ld = LocalDate.of(2016, 3, 8) + val bd = BigDecimal("0.0063518") - val ld = LocalDate.of(2016, 3, 8) - val bd = BigDecimal("0.0063518") + transaction { + output("irs post agreement") { singleIRS() } + command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + timestamp(TEST_TX_TIME) + this.verifies() + } - transaction { - output("irs post agreement") { singleIRS() } - command(MEGA_CORP_PUBKEY) { InterestRateSwap.Commands.Agree() } + val oldIRS = singleIRS(1) + val newIRS = oldIRS.copy(oldIRS.fixedLeg, + oldIRS.floatingLeg, + oldIRS.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), + oldIRS.common) + + transaction { + input() { + oldIRS + + } + + // Templated tweak for reference. A corrent fixing applied should be ok + tweak { + command(ORACLE_PUBKEY) { + InterestRateSwap.Commands.Fix() + } timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { + Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) + } + output() { newIRS } this.verifies() } - val oldIRS = singleIRS(1) - val newIRS = oldIRS.copy(oldIRS.fixedLeg, - oldIRS.floatingLeg, - oldIRS.calculation.applyFixing(ld, FixedRate(RatioUnit(bd))), - oldIRS.common) - - transaction { - input() { - oldIRS + // This test makes sure that verify confirms the fixing was applied and there is a difference in the old and new + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } + output() { oldIRS } + this `fails with` "There is at least one difference in the IRS floating leg payment schedules" + } + // This tests tries to sneak in a change to another fixing (which may or may not be the latest one) + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { + Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - // Templated tweak for reference. A corrent fixing applied should be ok - tweak { - command(ORACLE_PUBKEY) { - InterestRateSwap.Commands.Fix() - } - timestamp(TEST_TX_TIME) - command(ORACLE_PUBKEY) { - Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) - } - output() { newIRS } - this.verifies() + val firstResetKey = newIRS.calculation.floatingLegPaymentSchedule.keys.first() + val firstResetValue = newIRS.calculation.floatingLegPaymentSchedule[firstResetKey] + val modifiedFirstResetValue = firstResetValue!!.copy(notional = Amount(firstResetValue.notional.quantity, Currency.getInstance("JPY"))) + + output() { + newIRS.copy( + newIRS.fixedLeg, + newIRS.floatingLeg, + newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( + Pair(firstResetKey, modifiedFirstResetValue))), + newIRS.common + ) } + this `fails with` "There is only one change in the IRS floating leg payment schedule" + } - // This test makes sure that verify confirms the fixing was applied and there is a difference in the old and new - tweak { - command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - output() { oldIRS } - this `fails with` "There is at least one difference in the IRS floating leg payment schedules" - } - - // This tests tries to sneak in a change to another fixing (which may or may not be the latest one) - tweak { - command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - command(ORACLE_PUBKEY) { - Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) - } - - val firstResetKey = newIRS.calculation.floatingLegPaymentSchedule.keys.first() - val firstResetValue = newIRS.calculation.floatingLegPaymentSchedule[firstResetKey] - val modifiedFirstResetValue = firstResetValue!!.copy(notional = Amount(firstResetValue.notional.quantity, Currency.getInstance("JPY"))) - - output() { - newIRS.copy( - newIRS.fixedLeg, - newIRS.floatingLeg, - newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( - Pair(firstResetKey, modifiedFirstResetValue))), - newIRS.common - ) - } - this `fails with` "There is only one change in the IRS floating leg payment schedule" - } - - // This tests modifies the payment currency for the fixing - tweak { - command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } - timestamp(TEST_TX_TIME) - command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } - - val latestReset = newIRS.calculation.floatingLegPaymentSchedule.filter { it.value.rate is FixedRate }.maxBy { it.key } - val modifiedLatestResetValue = latestReset!!.value.copy(notional = Amount(latestReset.value.notional.quantity, Currency.getInstance("JPY"))) - - output() { - newIRS.copy( - newIRS.fixedLeg, - newIRS.floatingLeg, - newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( - Pair(latestReset.key, modifiedLatestResetValue))), - newIRS.common - ) - } - this `fails with` "The fix payment has the same currency as the notional" + // This tests modifies the payment currency for the fixing + tweak { + command(ORACLE_PUBKEY) { InterestRateSwap.Commands.Fix() } + timestamp(TEST_TX_TIME) + command(ORACLE_PUBKEY) { Fix(FixOf("ICE LIBOR", ld, Tenor("3M")), bd) } + + val latestReset = newIRS.calculation.floatingLegPaymentSchedule.filter { it.value.rate is FixedRate }.maxBy { it.key } + val modifiedLatestResetValue = latestReset!!.value.copy(notional = Amount(latestReset.value.notional.quantity, Currency.getInstance("JPY"))) + + output() { + newIRS.copy( + newIRS.fixedLeg, + newIRS.floatingLeg, + newIRS.calculation.copy(floatingLegPaymentSchedule = newIRS.calculation.floatingLegPaymentSchedule.plus( + Pair(latestReset.key, modifiedLatestResetValue))), + newIRS.common + ) } + this `fails with` "The fix payment has the same currency as the notional" } } } @@ -656,7 +653,7 @@ class IRSTests { * result and the grouping won't work either. * In reality, the only fields that should be in common will be the next fixing date and the reference rate. */ - fun tradegroups(): LedgerDSL { + fun tradegroups(): LedgerDSL { val ld1 = LocalDate.of(2016, 3, 8) val bd1 = BigDecimal("0.0063518") diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt index a384315b2c..bc7e11a9f7 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/CashTests.kt @@ -29,146 +29,142 @@ class CashTests { @Test fun trivial() { - ledger { - transaction { - input { inState } - this `fails with` "the amounts balance" + transaction { + input { inState } + this `fails with` "the amounts balance" - tweak { - output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) } - this `fails with` "the amounts balance" - } - tweak { - output { outState } - // No command commanduments - this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" - } - tweak { - output { outState } - command(DUMMY_PUBKEY_2) { Cash.Commands.Move() } - this `fails with` "the owning keys are the same as the signing keys" - } - tweak { - output { outState } - output { outState `issued by` MINI_CORP } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails with` "at least one asset input" - } - // Simple reallocation works. - tweak { - output { outState } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.verifies() - } + tweak { + output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + tweak { + output { outState } + // No command commanduments + this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" + } + tweak { + output { outState } + command(DUMMY_PUBKEY_2) { Cash.Commands.Move() } + this `fails with` "the owning keys are the same as the signing keys" + } + tweak { + output { outState } + output { outState `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at least one asset input" + } + // Simple reallocation works. + tweak { + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() } } } @Test fun issueMoney() { - ledger { - // Check we can't "move" money into existence. - transaction { - input { DummyState() } - output { outState } - command(MINI_CORP_PUBKEY) { Cash.Commands.Move() } + // Check we can't "move" money into existence. + transaction { + input { DummyState() } + output { outState } + command(MINI_CORP_PUBKEY) { Cash.Commands.Move() } - this `fails with` "there is at least one asset input" + this `fails with` "there is at least one asset input" + } + + // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised + // institution is allowed to issue as much cash as they want. + transaction { + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Issue() } + this `fails with` "output deposits are owned by a command signer" + } + transaction { + output { + Cash.State( + amount = 1000.DOLLARS `issued by` MINI_CORP.ref(12, 34), + owner = DUMMY_PUBKEY_1 + ) + } + tweak { + command(MINI_CORP_PUBKEY) { Cash.Commands.Issue(0) } + this `fails with` "has a nonce" + } + command(MINI_CORP_PUBKEY) { Cash.Commands.Issue() } + this.verifies() + } + + // Test generation works. + val ptx = TransactionType.General.Builder() + Cash().generateIssue(ptx, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + assertTrue(ptx.inputStates().isEmpty()) + val s = ptx.outputStates()[0].data as Cash.State + assertEquals(100.DOLLARS `issued by` MINI_CORP.ref(12, 34), s.amount) + assertEquals(MINI_CORP, s.deposit.party) + assertEquals(DUMMY_PUBKEY_1, s.owner) + assertTrue(ptx.commands()[0].value is Cash.Commands.Issue) + assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) + + // Test issuance from the issuance definition + val amount = 100.DOLLARS `issued by` MINI_CORP.ref(12, 34) + val templatePtx = TransactionType.General.Builder() + Cash().generateIssue(templatePtx, amount, owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) + assertTrue(templatePtx.inputStates().isEmpty()) + assertEquals(ptx.outputStates()[0], templatePtx.outputStates()[0]) + + // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. + transaction { + input { inState } + output { inState.copy(amount = inState.amount * 2) } + + // Move fails: not allowed to summon money. + tweak { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at issuer MegaCorp the amounts balance" } - // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised - // institution is allowed to issue as much cash as they want. - transaction { - output { outState } - command(DUMMY_PUBKEY_1) { Cash.Commands.Issue() } - this `fails with` "output deposits are owned by a command signer" - } - transaction { - output { - Cash.State( - amount = 1000.DOLLARS `issued by` MINI_CORP.ref(12, 34), - owner = DUMMY_PUBKEY_1 - ) - } - tweak { - command(MINI_CORP_PUBKEY) { Cash.Commands.Issue(0) } - this `fails with` "has a nonce" - } - command(MINI_CORP_PUBKEY) { Cash.Commands.Issue() } + // Issue works. + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } this.verifies() } + } - // Test generation works. - val ptx = TransactionType.General.Builder() - Cash().generateIssue(ptx, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) - assertTrue(ptx.inputStates().isEmpty()) - val s = ptx.outputStates()[0].data as Cash.State - assertEquals(100.DOLLARS `issued by` MINI_CORP.ref(12, 34), s.amount) - assertEquals(MINI_CORP, s.deposit.party) - assertEquals(DUMMY_PUBKEY_1, s.owner) - assertTrue(ptx.commands()[0].value is Cash.Commands.Issue) - assertEquals(MINI_CORP_PUBKEY, ptx.commands()[0].signers[0]) + // Can't use an issue command to lower the amount. + transaction { + input { inState } + output { inState.copy(amount = inState.amount / 2) } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + this `fails with` "output values sum to more than the inputs" + } - // Test issuance from the issuance definition - val amount = 100.DOLLARS `issued by` MINI_CORP.ref(12, 34) - val templatePtx = TransactionType.General.Builder() - Cash().generateIssue(templatePtx, amount, owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY) - assertTrue(templatePtx.inputStates().isEmpty()) - assertEquals(ptx.outputStates()[0], templatePtx.outputStates()[0]) + // Can't have an issue command that doesn't actually issue money. + transaction { + input { inState } + output { inState } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + this `fails with` "output values sum to more than the inputs" + } - // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. - transaction { - input { inState } - output { inState.copy(amount = inState.amount * 2) } - - // Move fails: not allowed to summon money. - tweak { - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails with` "at issuer MegaCorp the amounts balance" - } - - // Issue works. - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this.verifies() - } - } - - // Can't use an issue command to lower the amount. - transaction { - input { inState } - output { inState.copy(amount = inState.amount / 2) } + // Can't have any other commands if we have an issue command (because the issue command overrules them) + transaction { + input { inState } + output { inState.copy(amount = inState.amount * 2) } + command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } + tweak { command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails with` "output values sum to more than the inputs" + this `fails with` "there is only a single issue command" } - - // Can't have an issue command that doesn't actually issue money. - transaction { - input { inState } - output { inState } - command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails with` "output values sum to more than the inputs" + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } + this `fails with` "there is only a single issue command" } - - // Can't have any other commands if we have an issue command (because the issue command overrules them) - transaction { - input { inState } - output { inState.copy(amount = inState.amount * 2) } - command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } - this `fails with` "there is only a single issue command" - } - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } - this `fails with` "there is only a single issue command" - } - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(inState.amount / 2) } - this `fails with` "there is only a single issue command" - } - this.verifies() + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(inState.amount / 2) } + this `fails with` "there is only a single issue command" } + this.verifies() } } @@ -193,190 +189,178 @@ class CashTests { @Test fun testMergeSplit() { - ledger { - // Splitting value works. - transaction { - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - tweak { - input { inState } - for (i in 1..4) output { inState.copy(amount = inState.amount / 4) } - this.verifies() - } - // Merging 4 inputs into 2 outputs works. - tweak { - for (i in 1..4) input { inState.copy(amount = inState.amount / 4) } - output { inState.copy(amount = inState.amount / 2) } - output { inState.copy(amount = inState.amount / 2) } - this.verifies() - } - // Merging 2 inputs into 1 works. - tweak { - input { inState.copy(amount = inState.amount / 2) } - input { inState.copy(amount = inState.amount / 2) } - output { inState } - this.verifies() - } + // Splitting value works. + transaction { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + tweak { + input { inState } + for (i in 1..4) output { inState.copy(amount = inState.amount / 4) } + this.verifies() + } + // Merging 4 inputs into 2 outputs works. + tweak { + for (i in 1..4) input { inState.copy(amount = inState.amount / 4) } + output { inState.copy(amount = inState.amount / 2) } + output { inState.copy(amount = inState.amount / 2) } + this.verifies() + } + // Merging 2 inputs into 1 works. + tweak { + input { inState.copy(amount = inState.amount / 2) } + input { inState.copy(amount = inState.amount / 2) } + output { inState } + this.verifies() } } } @Test fun zeroSizedValues() { - ledger { - transaction { - input { inState } - input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } - this `fails with` "zero sized inputs" - } - transaction { - input { inState } - output { inState } - output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } - this `fails with` "zero sized outputs" - } + transaction { + input { inState } + input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } + this `fails with` "zero sized inputs" + } + transaction { + input { inState } + output { inState } + output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } + this `fails with` "zero sized outputs" } } @Test fun trivialMismatches() { - ledger { - // Can't change issuer. - transaction { - input { inState } - output { outState `issued by` MINI_CORP } - this `fails with` "at issuer MegaCorp the amounts balance" - } - // Can't change deposit reference when splitting. - transaction { - input { inState } - output { outState.copy(amount = inState.amount / 2).editDepositRef(0) } - output { outState.copy(amount = inState.amount / 2).editDepositRef(1) } - this `fails with` "for deposit [01] at issuer MegaCorp the amounts balance" - } - // Can't mix currencies. - transaction { - input { inState } - output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) } - output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) } - this `fails with` "the amounts balance" - } - transaction { - input { inState } - input { - inState.copy( - amount = 150.POUNDS `issued by` defaultIssuer, - owner = DUMMY_PUBKEY_2 - ) - } - output { outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer) } - this `fails with` "the amounts balance" - } - // Can't have superfluous input states from different issuers. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } - output { outState } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails with` "at issuer MiniCorp the amounts balance" - } - // Can't combine two different deposits at the same issuer. - transaction { - input { inState } - input { inState.editDepositRef(3) } - output { outState.copy(amount = inState.amount * 2).editDepositRef(3) } - this `fails with` "for deposit [01]" + // Can't change issuer. + transaction { + input { inState } + output { outState `issued by` MINI_CORP } + this `fails with` "at issuer MegaCorp the amounts balance" + } + // Can't change deposit reference when splitting. + transaction { + input { inState } + output { outState.copy(amount = inState.amount / 2).editDepositRef(0) } + output { outState.copy(amount = inState.amount / 2).editDepositRef(1) } + this `fails with` "for deposit [01] at issuer MegaCorp the amounts balance" + } + // Can't mix currencies. + transaction { + input { inState } + output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) } + output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + transaction { + input { inState } + input { + inState.copy( + amount = 150.POUNDS `issued by` defaultIssuer, + owner = DUMMY_PUBKEY_2 + ) } + output { outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer) } + this `fails with` "the amounts balance" + } + // Can't have superfluous input states from different issuers. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } + output { outState } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this `fails with` "at issuer MiniCorp the amounts balance" + } + // Can't combine two different deposits at the same issuer. + transaction { + input { inState } + input { inState.editDepositRef(3) } + output { outState.copy(amount = inState.amount * 2).editDepositRef(3) } + this `fails with` "for deposit [01]" } } @Test fun exitLedger() { - ledger { - // Single input/output straightforward case. - transaction { - input { inState } - output { outState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } - - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(100.DOLLARS `issued by` defaultIssuer) } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this `fails with` "the amounts balance" - } - - tweak { - command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } - this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" - - tweak { - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.verifies() - } - } - } - // Multi-issuer case. - transaction { - input { inState } - input { inState `issued by` MINI_CORP } - - output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) `issued by` MINI_CORP } - output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } + // Single input/output straightforward case. + transaction { + input { inState } + output { outState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(100.DOLLARS `issued by` defaultIssuer) } command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - - this `fails with` "at issuer MegaCorp the amounts balance" - - command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } - this `fails with` "at issuer MiniCorp the amounts balance" - - command(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) } - this.verifies() + this `fails with` "the amounts balance" } + + tweak { + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } + this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" + + tweak { + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() + } + } + } + // Multi-issuer case. + transaction { + input { inState } + input { inState `issued by` MINI_CORP } + + output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) `issued by` MINI_CORP } + output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } + + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + + this `fails with` "at issuer MegaCorp the amounts balance" + + command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } + this `fails with` "at issuer MiniCorp the amounts balance" + + command(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) } + this.verifies() } } @Test fun multiIssuer() { - ledger { - transaction { - // Gather 2000 dollars from two different issuers. - input { inState } - input { inState `issued by` MINI_CORP } + transaction { + // Gather 2000 dollars from two different issuers. + input { inState } + input { inState `issued by` MINI_CORP } - // Can't merge them together. - tweak { - output { inState.copy(owner = DUMMY_PUBKEY_2, amount = 2000.DOLLARS `issued by` defaultIssuer) } - this `fails with` "at issuer MegaCorp the amounts balance" - } - // Missing MiniCorp deposit - tweak { - output { inState.copy(owner = DUMMY_PUBKEY_2) } - output { inState.copy(owner = DUMMY_PUBKEY_2) } - this `fails with` "at issuer MegaCorp the amounts balance" - } - - // This works. - output { inState.copy(owner = DUMMY_PUBKEY_2) } - output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP } - command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } - this.verifies() + // Can't merge them together. + tweak { + output { inState.copy(owner = DUMMY_PUBKEY_2, amount = 2000.DOLLARS `issued by` defaultIssuer) } + this `fails with` "at issuer MegaCorp the amounts balance" } + // Missing MiniCorp deposit + tweak { + output { inState.copy(owner = DUMMY_PUBKEY_2) } + output { inState.copy(owner = DUMMY_PUBKEY_2) } + this `fails with` "at issuer MegaCorp the amounts balance" + } + + // This works. + output { inState.copy(owner = DUMMY_PUBKEY_2) } + output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP } + command(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + this.verifies() } } @Test fun multiCurrency() { - ledger { - // Check we can do an atomic currency trade tx. - transaction { - val pounds = Cash.State(658.POUNDS `issued by` MINI_CORP.ref(3, 4, 5), DUMMY_PUBKEY_2) - input { inState `owned by` DUMMY_PUBKEY_1 } - input { pounds } - output { inState `owned by` DUMMY_PUBKEY_2 } - output { pounds `owned by` DUMMY_PUBKEY_1 } - command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Cash.Commands.Move() } + // Check we can do an atomic currency trade tx. + transaction { + val pounds = Cash.State(658.POUNDS `issued by` MINI_CORP.ref(3, 4, 5), DUMMY_PUBKEY_2) + input { inState `owned by` DUMMY_PUBKEY_1 } + input { pounds } + output { inState `owned by` DUMMY_PUBKEY_2 } + output { pounds `owned by` DUMMY_PUBKEY_1 } + command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Cash.Commands.Move() } - this.verifies() - } + this.verifies() } } diff --git a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt index d6f8a6c1d6..5eec7d84c9 100644 --- a/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt +++ b/contracts/src/test/kotlin/com/r3corda/contracts/asset/ObligationTests.kt @@ -35,7 +35,7 @@ class ObligationTests { val outState = inState.copy(beneficiary = DUMMY_PUBKEY_2) private fun obligationTestRoots( - group: LedgerDSL + group: LedgerDSL ) = group.apply { unverifiedTransaction { output("Alice's $1,000,000 obligation to Bob", oneMillionDollars.OBLIGATION `between` Pair(ALICE, BOB_PUBKEY)) 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 9415e30811..564524dc85 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestDSL.kt @@ -17,15 +17,15 @@ import java.util.* fun transaction( transactionLabel: String? = null, dsl: TransactionDSL< - LastLineShouldTestForVerifiesOrFails, - TransactionDSLInterpreter - >.() -> LastLineShouldTestForVerifiesOrFails + EnforceVerifyOrFail, + TransactionDSLInterpreter + >.() -> EnforceVerifyOrFail ) = JavaTestHelpers.transaction(transactionLabel, dsl) fun ledger( identityService: IdentityService = MOCK_IDENTITY_SERVICE, storageService: StorageService = MockStorageService(), - dsl: LedgerDSL.() -> Unit + dsl: LedgerDSL.() -> Unit ) = JavaTestHelpers.ledger(identityService, storageService, dsl) @Deprecated( @@ -33,8 +33,8 @@ fun ledger( replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) @Suppress("UNUSED_PARAMETER") -fun TransactionDSLInterpreter.ledger( - dsl: LedgerDSL.() -> Unit) { +fun TransactionDSLInterpreter.ledger( + dsl: LedgerDSL.() -> Unit) { } @Deprecated( @@ -42,11 +42,11 @@ fun TransactionDSLInterpreter.ledger( replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) @Suppress("UNUSED_PARAMETER") -fun TransactionDSLInterpreter.transaction( +fun TransactionDSLInterpreter.transaction( dsl: TransactionDSL< - LastLineShouldTestForVerifiesOrFails, - TransactionDSLInterpreter - >.() -> LastLineShouldTestForVerifiesOrFails) { + EnforceVerifyOrFail, + TransactionDSLInterpreter + >.() -> EnforceVerifyOrFail) { } @Deprecated( @@ -54,8 +54,8 @@ fun TransactionDSLInterpreter.transaction( replaceWith = ReplaceWith("tweak"), level = DeprecationLevel.ERROR) @Suppress("UNUSED_PARAMETER") -fun LedgerDSLInterpreter>.ledger( - dsl: LedgerDSL.() -> Unit) { +fun LedgerDSLInterpreter>.ledger( + dsl: LedgerDSL.() -> Unit) { } /** @@ -64,8 +64,8 @@ fun LedgerDSLInterpreter = arrayListOf(), private val signers: LinkedHashSet = LinkedHashSet(), private val transactionType: TransactionType = TransactionType.General() -) : TransactionDSLInterpreter, OutputStateLookup by ledgerInterpreter { +) : TransactionDSLInterpreter, OutputStateLookup by ledgerInterpreter { private fun copy(): TestTransactionDSLInterpreter = TestTransactionDSLInterpreter( ledgerInterpreter = ledgerInterpreter, @@ -121,13 +121,13 @@ data class TestTransactionDSLInterpreter( commands.add(Command(commandData, signers)) } - override fun verifies(): LastLineShouldTestForVerifiesOrFails { + override fun verifies(): EnforceVerifyOrFail { val resolvedTransaction = ledgerInterpreter.resolveWireTransaction(toWireTransaction()) resolvedTransaction.verify() - return LastLineShouldTestForVerifiesOrFails.Token + return EnforceVerifyOrFail.Token } - override fun failsWith(expectedMessage: String?): LastLineShouldTestForVerifiesOrFails { + override fun failsWith(expectedMessage: String?): EnforceVerifyOrFail { val exceptionThrown = try { this.verifies() false @@ -151,14 +151,14 @@ data class TestTransactionDSLInterpreter( throw AssertionError("Expected exception but didn't get one") } - return LastLineShouldTestForVerifiesOrFails.Token + return EnforceVerifyOrFail.Token } override fun tweak( dsl: TransactionDSL< - LastLineShouldTestForVerifiesOrFails, - TransactionDSLInterpreter - >.() -> LastLineShouldTestForVerifiesOrFails + EnforceVerifyOrFail, + TransactionDSLInterpreter + >.() -> EnforceVerifyOrFail ) = dsl(TransactionDSL(copy())) } @@ -171,7 +171,7 @@ data class TestLedgerDSLInterpreter private constructor ( internal val labelToOutputStateAndRefs: HashMap> = HashMap(), private val transactionWithLocations: HashMap = HashMap(), private val nonVerifiedTransactionWithLocations: HashMap = HashMap() -) : LedgerDSLInterpreter { +) : LedgerDSLInterpreter { val wireTransactions: List get() = transactionWithLocations.values.map { it.transaction } @@ -243,7 +243,7 @@ data class TestLedgerDSLInterpreter private constructor ( storageService.attachments.openAttachment(attachmentId) ?: throw AttachmentResolutionException(attachmentId) private fun interpretTransactionDsl( - dsl: TransactionDSL.() -> Return + dsl: TransactionDSL.() -> Return ): TestTransactionDSLInterpreter { val transactionInterpreter = TestTransactionDSLInterpreter(this) dsl(TransactionDSL(transactionInterpreter)) @@ -274,7 +274,7 @@ data class TestLedgerDSLInterpreter private constructor ( private fun recordTransactionWithTransactionMap( transactionLabel: String?, - dsl: TransactionDSL.() -> R, + dsl: TransactionDSL.() -> R, transactionMap: HashMap = HashMap() ): WireTransaction { val transactionLocation = getCallerLocation(3) @@ -296,17 +296,17 @@ data class TestLedgerDSLInterpreter private constructor ( override fun transaction( transactionLabel: String?, - dsl: TransactionDSL.() -> LastLineShouldTestForVerifiesOrFails + dsl: TransactionDSL.() -> EnforceVerifyOrFail ) = recordTransactionWithTransactionMap(transactionLabel, dsl, transactionWithLocations) override fun unverifiedTransaction( transactionLabel: String?, - dsl: TransactionDSL.() -> Unit + dsl: TransactionDSL.() -> Unit ) = recordTransactionWithTransactionMap(transactionLabel, dsl, nonVerifiedTransactionWithLocations) override fun tweak( - dsl: LedgerDSL>.() -> Unit) = + dsl: LedgerDSL>.() -> Unit) = dsl(LedgerDSL(copy())) override fun attachment(attachment: InputStream): SecureHash { @@ -349,6 +349,6 @@ fun signAll(transactionsToSign: List, extraKeys: Array.signAll( +fun LedgerDSL.signAll( transactionsToSign: List = this.interpreter.wireTransactions, vararg extraKeys: KeyPair) = signAll(transactionsToSign, extraKeys) diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index db0361793f..ad3557ae39 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -93,8 +93,8 @@ object JavaTestHelpers { @JvmStatic @JvmOverloads fun ledger( identityService: IdentityService = MOCK_IDENTITY_SERVICE, storageService: StorageService = MockStorageService(), - dsl: LedgerDSL.() -> Unit - ): LedgerDSL { + dsl: LedgerDSL.() -> Unit + ): LedgerDSL { val ledgerDsl = LedgerDSL(TestLedgerDSLInterpreter(identityService, storageService)) dsl(ledgerDsl) return ledgerDsl @@ -103,9 +103,9 @@ object JavaTestHelpers { @JvmStatic @JvmOverloads fun transaction( transactionLabel: String? = null, dsl: TransactionDSL< - LastLineShouldTestForVerifiesOrFails, - TransactionDSLInterpreter - >.() -> LastLineShouldTestForVerifiesOrFails + EnforceVerifyOrFail, + TransactionDSLInterpreter + >.() -> EnforceVerifyOrFail ) = ledger { transaction(transactionLabel, dsl) } } diff --git a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt index d18ab013aa..0176a6eda9 100644 --- a/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt +++ b/node/src/test/kotlin/com/r3corda/node/messaging/TwoPartyTradeProtocolTests.kt @@ -366,7 +366,7 @@ class TwoPartyTradeProtocolTests { } } - private fun LedgerDSL.runWithError( + private fun LedgerDSL.runWithError( bobError: Boolean, aliceError: Boolean, expectedMessageSubstring: String @@ -431,7 +431,7 @@ class TwoPartyTradeProtocolTests { return signed.associateBy { it.id } } - private fun LedgerDSL.fillUpForBuyer( + private fun LedgerDSL.fillUpForBuyer( withError: Boolean, owner: PublicKey = BOB_PUBKEY, issuer: PartyAndReference = MEGA_CORP.ref(1)): Pair> { @@ -472,7 +472,7 @@ class TwoPartyTradeProtocolTests { return Pair(wallet, listOf(eb1, bc1, bc2)) } - private fun LedgerDSL.fillUpForSeller( + private fun LedgerDSL.fillUpForSeller( withError: Boolean, owner: PublicKey, amount: Amount>, diff --git a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt index 7b2292b35b..6b61416d5a 100644 --- a/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt +++ b/node/src/test/kotlin/com/r3corda/node/visualiser/GroupToGraphConversion.kt @@ -9,7 +9,7 @@ import org.graphstream.graph.Node import org.graphstream.graph.implementations.SingleGraph import kotlin.reflect.memberProperties -class GraphVisualiser(val dsl: LedgerDSL) { +class GraphVisualiser(val dsl: LedgerDSL) { companion object { val css = GraphVisualiser::class.java.getResourceAsStream("graph.css").bufferedReader().readText() }