mirror of
https://github.com/corda/corda.git
synced 2025-02-03 09:41:10 +00:00
Verification for Move command.
This commit is contained in:
parent
a50d68f4b1
commit
40bddc0a77
@ -24,7 +24,7 @@ class GenericContract : Contract {
|
||||
|
||||
// replace parties
|
||||
// must be signed by all parties present in contract before and after command
|
||||
class Move : TypeOnlyCommandData(), Commands
|
||||
class Move(val from: Party, val to: Party) : TypeOnlyCommandData(), Commands
|
||||
|
||||
// must be signed by all parties present in contract
|
||||
class Issue : TypeOnlyCommandData(), Commands
|
||||
@ -73,10 +73,20 @@ class GenericContract : Contract {
|
||||
is Commands.Issue -> {
|
||||
val outState = tx.outStates.single() as State
|
||||
requireThat {
|
||||
"the transaction is signed by all involved parties" by ( liableParties(outState.details).all { it in cmd.signers } )
|
||||
"the transaction is signed by all liable parties" by ( liableParties(outState.details).all { it in cmd.signers } )
|
||||
"the transaction has no input states" by tx.inStates.isEmpty()
|
||||
}
|
||||
}
|
||||
is Commands.Move -> {
|
||||
val inState = tx.inStates.single() as State
|
||||
val outState = tx.outStates.single() as State
|
||||
requireThat {
|
||||
// todo:
|
||||
// - check actual state output
|
||||
"the transaction is signed by all liable parties" by ( liableParties(outState.details).all { it in cmd.signers } )
|
||||
"output state does not reflect move command" by (replaceParty(inState.details, value.from, value.to).equals(outState.details))
|
||||
}
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unrecognised command")
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ data class Action(val name: String, val condition: Observable<Boolean>,
|
||||
// only actions can be or'ed together
|
||||
data class Or(val contracts: Set<Action>) : Kontract
|
||||
|
||||
/** returns list of involved parties for a given contract */
|
||||
/** returns list of potentially liable parties for a given contract */
|
||||
fun liableParties(contract: Kontract) : Set<PublicKey> {
|
||||
|
||||
fun visit(contract: Kontract) : ImmutableSet<PublicKey> {
|
||||
@ -58,6 +58,45 @@ fun liableParties(contract: Kontract) : Set<PublicKey> {
|
||||
return visit(contract);
|
||||
}
|
||||
|
||||
/** returns list of involved parties for a given contract */
|
||||
fun involvedParties(contract: Kontract) : Set<PublicKey> {
|
||||
|
||||
fun visit(contract: Kontract) : ImmutableSet<PublicKey> {
|
||||
return when (contract) {
|
||||
is Zero -> ImmutableSet.of<PublicKey>()
|
||||
is Transfer -> ImmutableSet.of(contract.from.owningKey)
|
||||
is Action -> Sets.union( visit(contract.kontract), contract.actors.map { it.owningKey }.toSet() ).immutableCopy()
|
||||
is And ->
|
||||
contract.kontracts.fold( ImmutableSet.builder<PublicKey>(), { builder, k -> builder.addAll( visit(k)) } ).build()
|
||||
is Or ->
|
||||
contract.contracts.fold( ImmutableSet.builder<PublicKey>(), { builder, k -> builder.addAll( visit(k)) } ).build()
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
||||
return visit(contract);
|
||||
}
|
||||
|
||||
fun replaceParty(action: Action, from: Party, to: Party) : Action {
|
||||
if (action.actors.contains(from)) {
|
||||
return Action( action.name, action.condition, action.actors - from + to, replaceParty(action.kontract, from, to))
|
||||
}
|
||||
return Action( action.name, action.condition, action.actors, replaceParty(action.kontract, from, to))
|
||||
}
|
||||
|
||||
fun replaceParty(contract: Kontract, from: Party, to: Party) : Kontract {
|
||||
return when (contract) {
|
||||
is Zero -> contract
|
||||
is Transfer -> Transfer( contract.amount, contract.currency,
|
||||
if (contract.from == from) to else contract.from,
|
||||
if (contract.to == from) to else contract.to )
|
||||
is Action -> replaceParty(contract, from, to)
|
||||
is And -> And( contract.kontracts.map { replaceParty(it, from, to) }.toSet() )
|
||||
is Or -> Or( contract.contracts.map { replaceParty(it, from, to) }.toSet() )
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
||||
fun actions(contract: Kontract) : Map<String, Action> {
|
||||
|
||||
when (contract) {
|
||||
|
@ -37,11 +37,11 @@ class FXSwap {
|
||||
|
||||
tweak {
|
||||
arg(roadRunner.owningKey) { GenericContract.Commands.Issue() }
|
||||
this `fails requirement` "the transaction is signed by all involved parties"
|
||||
this `fails requirement` "the transaction is signed by all liable parties"
|
||||
}
|
||||
tweak {
|
||||
arg(wileECoyote.owningKey) { GenericContract.Commands.Issue() }
|
||||
this `fails requirement` "the transaction is signed by all involved parties"
|
||||
this `fails requirement` "the transaction is signed by all liable parties"
|
||||
}
|
||||
|
||||
arg(wileECoyote.owningKey, roadRunner.owningKey) { GenericContract.Commands.Issue() }
|
||||
|
@ -17,6 +17,14 @@ class ZCB {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val contractMove =
|
||||
(porkyPig or wileECoyote).may {
|
||||
"execute".givenThat(after("01/09/2017")) {
|
||||
wileECoyote.gives(porkyPig, 100.K*GBP)
|
||||
}
|
||||
}
|
||||
|
||||
val transfer = kontract { wileECoyote.gives(roadRunner, 100.K*GBP) }
|
||||
val transferWrong = kontract { wileECoyote.gives(roadRunner, 80.K*GBP) }
|
||||
|
||||
@ -25,6 +33,8 @@ class ZCB {
|
||||
val outState = GenericContract.State( DUMMY_NOTARY, transfer )
|
||||
val outStateWrong = GenericContract.State( DUMMY_NOTARY, transferWrong )
|
||||
|
||||
val outStateMove = GenericContract.State( DUMMY_NOTARY, contractMove )
|
||||
|
||||
@Test
|
||||
fun basic() {
|
||||
assert( Zero().equals(Zero()))
|
||||
@ -41,7 +51,7 @@ class ZCB {
|
||||
|
||||
tweak {
|
||||
arg(roadRunner.owningKey) { GenericContract.Commands.Issue() }
|
||||
this `fails requirement` "the transaction is signed by all involved parties"
|
||||
this `fails requirement` "the transaction is signed by all liable parties"
|
||||
}
|
||||
|
||||
arg(wileECoyote.owningKey) { GenericContract.Commands.Issue() }
|
||||
@ -89,4 +99,34 @@ class ZCB {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun move() {
|
||||
transaction {
|
||||
input { inState }
|
||||
|
||||
tweak {
|
||||
output { outStateMove }
|
||||
arg(roadRunner.owningKey) {
|
||||
GenericContract.Commands.Move(roadRunner, porkyPig)
|
||||
}
|
||||
this `fails requirement` "the transaction is signed by all liable parties"
|
||||
}
|
||||
|
||||
tweak {
|
||||
output { inState }
|
||||
arg(roadRunner.owningKey, porkyPig.owningKey, wileECoyote.owningKey) {
|
||||
GenericContract.Commands.Move(roadRunner, porkyPig)
|
||||
}
|
||||
this `fails requirement` "output state does not reflect move command"
|
||||
}
|
||||
|
||||
output { outStateMove}
|
||||
|
||||
arg(roadRunner.owningKey, porkyPig.owningKey, wileECoyote.owningKey) {
|
||||
GenericContract.Commands.Move(roadRunner, porkyPig)
|
||||
}
|
||||
this.accepts()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user