From 5b4969d36673dbfa42c34b57e4927189c7ed3600 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Fri, 13 Nov 2015 14:43:59 +0100 Subject: [PATCH] Minor: make commands singletons when they contain no data and are purely type system markers. This may not be really compatible with sandboxing, later on. But we can always change it back if not. --- src/contracts/Cash.kt | 7 ++----- src/contracts/ComedyPaper.kt | 4 ++-- src/core/ContractsDSL.kt | 1 - src/core/Structures.kt | 1 + tests/contracts/CashTests.kt | 22 +++++++++++----------- tests/contracts/ComedyPaperTests.kt | 10 +++++----- 6 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/contracts/Cash.kt b/src/contracts/Cash.kt index 9117fcc071..3073c36f1b 100644 --- a/src/contracts/Cash.kt +++ b/src/contracts/Cash.kt @@ -51,10 +51,7 @@ object Cash : Contract { sealed class Commands { /** A command proving ownership of some input states, the signature covers the output states. */ - class Move : Command { - override fun equals(other: Any?) = other is Move - override fun hashCode() = 0 - } + object Move : Command /** * A command stating that money has been withdrawn from the shared ledger and is now accounted for @@ -181,7 +178,7 @@ object Cash : Contract { } else states // Finally, generate the commands. Pretend to sign here, real signatures aren't done yet. - val commands = keysUsed.map { VerifiedSigned(listOf(it), emptyList(), Commands.Move()) } + val commands = keysUsed.map { VerifiedSigned(listOf(it), emptyList(), Commands.Move) } return TransactionForTest(gathered.toArrayList(), outputs.toArrayList(), commands.toArrayList()) } diff --git a/src/contracts/ComedyPaper.kt b/src/contracts/ComedyPaper.kt index bb385395c6..21a5871da4 100644 --- a/src/contracts/ComedyPaper.kt +++ b/src/contracts/ComedyPaper.kt @@ -37,8 +37,8 @@ object ComedyPaper : Contract { } sealed class Commands : Command { - class Move : Commands() - class Redeem : Commands() + object Move : Commands() + object Redeem : Commands() } override fun verify(tx: TransactionForVerification) { diff --git a/src/core/ContractsDSL.kt b/src/core/ContractsDSL.kt index d452d0a208..98fc8d6fc6 100644 --- a/src/core/ContractsDSL.kt +++ b/src/core/ContractsDSL.kt @@ -27,7 +27,6 @@ inline fun List>.requireSingleComm } catch (e: NoSuchElementException) { throw IllegalStateException("Required ${T::class.qualifiedName} command") // Better error message. } - // endregion // region Currencies diff --git a/src/core/Structures.kt b/src/core/Structures.kt index 0f6fc51217..441374aa42 100644 --- a/src/core/Structures.kt +++ b/src/core/Structures.kt @@ -28,6 +28,7 @@ class Institution( override fun toString() = name } +/** Marker interface for objects that represent commands */ interface Command /** Provided as an input to a contract; converted to a [VerifiedSigned] by the platform before execution. */ diff --git a/tests/contracts/CashTests.kt b/tests/contracts/CashTests.kt index a78d6e28d3..548615b240 100644 --- a/tests/contracts/CashTests.kt +++ b/tests/contracts/CashTests.kt @@ -38,7 +38,7 @@ class CashTests { } transaction { output { outState } - arg(DUMMY_PUBKEY_2) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_2) { Cash.Commands.Move } this `fails requirement` "the owning keys are the same as the signing keys" } transaction { @@ -49,7 +49,7 @@ class CashTests { // Simple reallocation works. transaction { output { outState } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_1) { Cash.Commands.Move } this.accepts() } } @@ -70,7 +70,7 @@ class CashTests { fun testMergeSplit() { // Splitting value works. transaction { - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_1) { Cash.Commands.Move } transaction { input { inState } for (i in 1..4) output { inState.copy(amount = inState.amount / 4) } @@ -161,7 +161,7 @@ class CashTests { transaction { arg(MEGA_CORP_KEY) { Cash.Commands.Exit(100.DOLLARS) } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_1) { Cash.Commands.Move } this `fails requirement` "the amounts balance" } @@ -170,7 +170,7 @@ class CashTests { this `fails requirement` "required move command" transaction { - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_1) { Cash.Commands.Move } this.accepts() } } @@ -183,7 +183,7 @@ class CashTests { output { inState.copy(amount = inState.amount - 200.DOLLARS).editInstitution(MINI_CORP) } output { inState.copy(amount = inState.amount - 200.DOLLARS) } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_1) { Cash.Commands.Move } this `fails requirement` "at issuer MegaCorp the amounts balance" @@ -217,7 +217,7 @@ class CashTests { // This works. output { inState.copy(owner = DUMMY_PUBKEY_2) } output { inState.copy(owner = DUMMY_PUBKEY_2).editInstitution(MINI_CORP) } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_1) { Cash.Commands.Move } this.accepts() } @@ -246,7 +246,7 @@ class CashTests { transaction { input { WALLET[0] } output { WALLET[0].copy(owner = THEIR_PUBKEY_1) } - arg(OUR_PUBKEY_1) { Cash.Commands.Move() } + arg(OUR_PUBKEY_1) { Cash.Commands.Move } }, Cash.craftSpend(100.DOLLARS, THEIR_PUBKEY_1, WALLET) ) @@ -259,7 +259,7 @@ class CashTests { input { WALLET[0] } output { WALLET[0].copy(owner = THEIR_PUBKEY_1, amount = 10.DOLLARS) } output { WALLET[0].copy(owner = OUR_PUBKEY_1, amount = 90.DOLLARS) } - arg(OUR_PUBKEY_1) { Cash.Commands.Move() } + arg(OUR_PUBKEY_1) { Cash.Commands.Move } }, Cash.craftSpend(10.DOLLARS, THEIR_PUBKEY_1, WALLET) ) @@ -272,7 +272,7 @@ class CashTests { input { WALLET[0] } input { WALLET[1] } output { WALLET[0].copy(owner = THEIR_PUBKEY_1, amount = 500.DOLLARS) } - arg(OUR_PUBKEY_1) { Cash.Commands.Move() } + arg(OUR_PUBKEY_1) { Cash.Commands.Move } }, Cash.craftSpend(500.DOLLARS, THEIR_PUBKEY_1, WALLET) ) @@ -287,7 +287,7 @@ class CashTests { input { WALLET[2] } output { WALLET[0].copy(owner = THEIR_PUBKEY_1, amount = 500.DOLLARS) } output { WALLET[2].copy(owner = THEIR_PUBKEY_1) } - arg(OUR_PUBKEY_1) { Cash.Commands.Move() } + arg(OUR_PUBKEY_1) { Cash.Commands.Move } }, Cash.craftSpend(580.DOLLARS, THEIR_PUBKEY_1, WALLET) ) diff --git a/tests/contracts/ComedyPaperTests.kt b/tests/contracts/ComedyPaperTests.kt index 00fb615d8a..491b0959a1 100644 --- a/tests/contracts/ComedyPaperTests.kt +++ b/tests/contracts/ComedyPaperTests.kt @@ -30,22 +30,22 @@ class ComedyPaperTests { this.rejects() transaction { - arg(DUMMY_PUBKEY_2) { ComedyPaper.Commands.Move() } + arg(DUMMY_PUBKEY_2) { ComedyPaper.Commands.Move } this `fails requirement` "is signed by the owner" } - arg(DUMMY_PUBKEY_1) { ComedyPaper.Commands.Move() } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_1) { ComedyPaper.Commands.Move } + arg(DUMMY_PUBKEY_1) { Cash.Commands.Move } this.accepts() }.chain("a") { - arg(DUMMY_PUBKEY_2, MINI_CORP_KEY) { ComedyPaper.Commands.Redeem() } + arg(DUMMY_PUBKEY_2, MINI_CORP_KEY) { ComedyPaper.Commands.Redeem } // No cash output, can't redeem like that! this.rejects("no cash being redeemed") input { CASH_3 } output { CASH_2 } - arg(DUMMY_PUBKEY_1) { Cash.Commands.Move() } + arg(DUMMY_PUBKEY_1) { Cash.Commands.Move } // Time passes, but not enough. An attempt to redeem is made. this.rejects("must have matured")