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.
This commit is contained in:
Mike Hearn 2015-11-13 14:43:59 +01:00
parent 1b44081880
commit 5b4969d366
6 changed files with 21 additions and 24 deletions

View File

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

View File

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

View File

@ -27,7 +27,6 @@ inline fun <reified T : Command> List<VerifiedSigned<Command>>.requireSingleComm
} catch (e: NoSuchElementException) {
throw IllegalStateException("Required ${T::class.qualifiedName} command") // Better error message.
}
// endregion
// region Currencies

View File

@ -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. */

View File

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

View File

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