contracts: Port CashTests to new dsl

This commit is contained in:
Andras Slemmer 2016-07-05 10:01:10 +01:00
parent f4a6a43aa6
commit 7634331f68

View File

@ -29,142 +29,146 @@ class CashTests {
@Test @Test
fun trivial() { fun trivial() {
transaction { ledger {
input { inState } transaction {
this `fails requirement` "the amounts balance" input { inState }
this `fails with` "the amounts balance"
tweak { tweak {
output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) } output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) }
this `fails requirement` "the amounts balance" this `fails with` "the amounts balance"
} }
tweak { tweak {
output { outState } output { outState }
// No command arguments // No command commanduments
this `fails requirement` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command" this `fails with` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command"
} }
tweak { tweak {
output { outState } output { outState }
arg(DUMMY_PUBKEY_2) { Cash.Commands.Move() } command(DUMMY_PUBKEY_2) { Cash.Commands.Move() }
this `fails requirement` "the owning keys are the same as the signing keys" this `fails with` "the owning keys are the same as the signing keys"
} }
tweak { tweak {
output { outState } output { outState }
output { outState `issued by` MINI_CORP } output { outState `issued by` MINI_CORP }
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } command(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
this `fails requirement` "at least one asset input" this `fails with` "at least one asset input"
} }
// Simple reallocation works. // Simple reallocation works.
tweak { tweak {
output { outState } output { outState }
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } command(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
this.accepts() this.verifies()
}
} }
} }
} }
@Test @Test
fun issueMoney() { fun issueMoney() {
// Check we can't "move" money into existence. ledger {
transaction { // Check we can't "move" money into existence.
input { DummyState() } transaction {
output { outState } input { DummyState() }
arg(MINI_CORP_PUBKEY) { Cash.Commands.Move() } output { outState }
command(MINI_CORP_PUBKEY) { Cash.Commands.Move() }
this `fails requirement` "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 }
arg(DUMMY_PUBKEY_1) { Cash.Commands.Issue() }
this `fails requirement` "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 {
arg(MINI_CORP_PUBKEY) { Cash.Commands.Issue(0) }
this `fails requirement` "has a nonce"
}
arg(MINI_CORP_PUBKEY) { Cash.Commands.Issue() }
this.accepts()
}
// 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 {
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
this `fails requirement` "at issuer MegaCorp the amounts balance"
} }
// Issue works. // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised
tweak { // institution is allowed to issue as much cash as they want.
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } transaction {
this.accepts() 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()
} }
}
// Can't use an issue command to lower the amount. // Test generation works.
transaction { val ptx = TransactionType.General.Builder()
input { inState } Cash().generateIssue(ptx, 100.DOLLARS `issued by` MINI_CORP.ref(12, 34), owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY)
output { inState.copy(amount = inState.amount / 2) } assertTrue(ptx.inputStates().isEmpty())
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } val s = ptx.outputStates()[0].data as Cash.State
this `fails requirement` "output values sum to more than the inputs" 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 have an issue command that doesn't actually issue money. // Test issuance from the issuance definition
transaction { val amount = 100.DOLLARS `issued by` MINI_CORP.ref(12, 34)
input { inState } val templatePtx = TransactionType.General.Builder()
output { inState } Cash().generateIssue(templatePtx, amount, owner = DUMMY_PUBKEY_1, notary = DUMMY_NOTARY)
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } assertTrue(templatePtx.inputStates().isEmpty())
this `fails requirement` "output values sum to more than the inputs" assertEquals(ptx.outputStates()[0], templatePtx.outputStates()[0])
}
// Can't have any other commands if we have an issue command (because the issue command overrules them) // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer.
transaction { transaction {
input { inState } input { inState }
output { inState.copy(amount = inState.amount * 2) } output { inState.copy(amount = inState.amount * 2) }
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() }
tweak { // Move fails: not allowed to summon money.
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() } tweak {
this `fails requirement` "there is only a single issue command" 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()
}
} }
tweak {
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Move() } // Can't use an issue command to lower the amount.
this `fails requirement` "there is only a single issue command" 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"
} }
tweak {
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(inState.amount / 2) } // Can't have an issue command that doesn't actually issue money.
this `fails requirement` "there is only a single issue command" transaction {
input { inState }
output { inState }
command(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() }
this `fails with` "output values sum to more than the inputs"
}
// 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()
} }
this.accepts()
} }
} }
@ -189,178 +193,190 @@ class CashTests {
@Test @Test
fun testMergeSplit() { fun testMergeSplit() {
// Splitting value works. ledger {
transaction { // Splitting value works.
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } transaction {
tweak { command(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
input { inState } tweak {
for (i in 1..4) output { inState.copy(amount = inState.amount / 4) } input { inState }
this.accepts() for (i in 1..4) output { inState.copy(amount = inState.amount / 4) }
} this.verifies()
// Merging 4 inputs into 2 outputs works. }
tweak { // Merging 4 inputs into 2 outputs works.
for (i in 1..4) input { inState.copy(amount = inState.amount / 4) } tweak {
output { inState.copy(amount = inState.amount / 2) } 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.accepts() output { inState.copy(amount = inState.amount / 2) }
} this.verifies()
// Merging 2 inputs into 1 works. }
tweak { // Merging 2 inputs into 1 works.
input { inState.copy(amount = inState.amount / 2) } tweak {
input { inState.copy(amount = inState.amount / 2) } input { inState.copy(amount = inState.amount / 2) }
output { inState } input { inState.copy(amount = inState.amount / 2) }
this.accepts() output { inState }
this.verifies()
}
} }
} }
} }
@Test @Test
fun zeroSizedValues() { fun zeroSizedValues() {
transaction { ledger {
input { inState } transaction {
input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } input { inState }
this `fails requirement` "zero sized inputs" input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) }
} this `fails with` "zero sized inputs"
transaction { }
input { inState } transaction {
output { inState } input { inState }
output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) } output { inState }
this `fails requirement` "zero sized outputs" output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) }
this `fails with` "zero sized outputs"
}
} }
} }
@Test @Test
fun trivialMismatches() { fun trivialMismatches() {
// Can't change issuer. ledger {
transaction { // Can't change issuer.
input { inState } transaction {
output { outState `issued by` MINI_CORP } input { inState }
this `fails requirement` "at issuer MegaCorp the amounts balance" output { outState `issued by` MINI_CORP }
} this `fails with` "at issuer MegaCorp the amounts balance"
// Can't change deposit reference when splitting. }
transaction { // Can't change deposit reference when splitting.
input { inState } transaction {
output { outState.copy(amount = inState.amount / 2).editDepositRef(0) } input { inState }
output { outState.copy(amount = inState.amount / 2).editDepositRef(1) } output { outState.copy(amount = inState.amount / 2).editDepositRef(0) }
this `fails requirement` "for deposit [01] at issuer MegaCorp the amounts balance" 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 { // Can't mix currencies.
input { inState } transaction {
output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) } input { inState }
output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) } output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) }
this `fails requirement` "the amounts balance" output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) }
} this `fails with` "the amounts balance"
transaction { }
input { inState } transaction {
input { input { inState }
inState.copy( input {
amount = 150.POUNDS `issued by` defaultIssuer, inState.copy(
owner = DUMMY_PUBKEY_2 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]"
} }
output { outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer) }
this `fails requirement` "the amounts balance"
}
// Can't have superfluous input states from different issuers.
transaction {
input { inState }
input { inState `issued by` MINI_CORP }
output { outState }
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
this `fails requirement` "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 requirement` "for deposit [01]"
} }
} }
@Test @Test
fun exitLedger() { fun exitLedger() {
// Single input/output straightforward case. ledger {
transaction { // Single input/output straightforward case.
input { inState } transaction {
output { outState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } input { inState }
output { outState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) }
tweak {
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(100.DOLLARS `issued by` defaultIssuer) }
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
this `fails requirement` "the amounts balance"
}
tweak {
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) }
this `fails requirement` "required com.r3corda.contracts.asset.FungibleAsset.Commands.Move command"
tweak { tweak {
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(100.DOLLARS `issued by` defaultIssuer) }
this.accepts() 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.
// Multi-issuer case. transaction {
transaction { input { inState }
input { inState } input { inState `issued by` MINI_CORP }
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)) `issued by` MINI_CORP }
output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) } output { inState.copy(amount = inState.amount - (200.DOLLARS `issued by` defaultIssuer)) }
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } command(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
this `fails requirement` "at issuer MegaCorp the amounts balance" this `fails with` "at issuer MegaCorp the amounts balance"
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) } command(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` defaultIssuer) }
this `fails requirement` "at issuer MiniCorp the amounts balance" this `fails with` "at issuer MiniCorp the amounts balance"
arg(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) } command(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) }
this.accepts() this.verifies()
}
} }
} }
@Test @Test
fun multiIssuer() { fun multiIssuer() {
transaction { ledger {
// Gather 2000 dollars from two different issuers. transaction {
input { inState } // Gather 2000 dollars from two different issuers.
input { inState `issued by` MINI_CORP } input { inState }
input { inState `issued by` MINI_CORP }
// Can't merge them together. // Can't merge them together.
tweak { tweak {
output { inState.copy(owner = DUMMY_PUBKEY_2, amount = 2000.DOLLARS `issued by` defaultIssuer) } output { inState.copy(owner = DUMMY_PUBKEY_2, amount = 2000.DOLLARS `issued by` defaultIssuer) }
this `fails requirement` "at issuer MegaCorp the amounts balance" this `fails with` "at issuer MegaCorp the amounts balance"
} }
// Missing MiniCorp deposit // Missing MiniCorp deposit
tweak { tweak {
output { inState.copy(owner = DUMMY_PUBKEY_2) } output { inState.copy(owner = DUMMY_PUBKEY_2) }
output { inState.copy(owner = DUMMY_PUBKEY_2) } output { inState.copy(owner = DUMMY_PUBKEY_2) }
this `fails requirement` "at issuer MegaCorp the amounts balance" this `fails with` "at issuer MegaCorp the amounts balance"
} }
// This works. // This works.
output { inState.copy(owner = DUMMY_PUBKEY_2) } output { inState.copy(owner = DUMMY_PUBKEY_2) }
output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP } output { inState.copy(owner = DUMMY_PUBKEY_2) `issued by` MINI_CORP }
arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } command(DUMMY_PUBKEY_1) { Cash.Commands.Move() }
this.accepts() this.verifies()
}
} }
} }
@Test @Test
fun multiCurrency() { fun multiCurrency() {
// Check we can do an atomic currency trade tx. ledger {
transaction { // Check we can do an atomic currency trade tx.
val pounds = Cash.State(658.POUNDS `issued by` MINI_CORP.ref(3, 4, 5), DUMMY_PUBKEY_2) transaction {
input { inState `owned by` DUMMY_PUBKEY_1 } val pounds = Cash.State(658.POUNDS `issued by` MINI_CORP.ref(3, 4, 5), DUMMY_PUBKEY_2)
input { pounds } input { inState `owned by` DUMMY_PUBKEY_1 }
output { inState `owned by` DUMMY_PUBKEY_2 } input { pounds }
output { pounds `owned by` DUMMY_PUBKEY_1 } output { inState `owned by` DUMMY_PUBKEY_2 }
arg(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Cash.Commands.Move() } output { pounds `owned by` DUMMY_PUBKEY_1 }
command(DUMMY_PUBKEY_1, DUMMY_PUBKEY_2) { Cash.Commands.Move() }
this.accepts() this.verifies()
}
} }
} }