mirror of
https://github.com/corda/corda.git
synced 2025-06-23 01:19:00 +00:00
Merged in rnicoll-cash-issue-only (pull request #83)
Require that a cash Issue command is the only command
This commit is contained in:
@ -93,8 +93,10 @@ class Cash : Contract {
|
|||||||
"there are no zero sized outputs" by outputs.none { it.amount.pennies == 0L }
|
"there are no zero sized outputs" by outputs.none { it.amount.pennies == 0L }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verifyIssueCommands(inputs, outputs, tx, currency, issuer)) continue
|
val issueCommand = tx.commands.select<Commands.Issue>().firstOrNull()
|
||||||
|
if (issueCommand != null) {
|
||||||
|
verifyIssueCommand(inputs, outputs, tx, issueCommand, currency, issuer)
|
||||||
|
} else {
|
||||||
val inputAmount = inputs.sumCashOrNull() ?: throw IllegalArgumentException("there is at least one cash input for this group")
|
val inputAmount = inputs.sumCashOrNull() ?: throw IllegalArgumentException("there is at least one cash input for this group")
|
||||||
val outputAmount = outputs.sumCashOrZero(currency)
|
val outputAmount = outputs.sumCashOrZero(currency)
|
||||||
|
|
||||||
@ -112,13 +114,14 @@ class Cash : Contract {
|
|||||||
verifyMoveCommands<Commands.Move>(inputs, tx)
|
verifyMoveCommands<Commands.Move>(inputs, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun verifyIssueCommands(inputs: List<State>, outputs: List<State>, tx: TransactionForVerification, currency: Currency, issuer: Party): Boolean {
|
|
||||||
val issueCommand = tx.commands.select<Commands.Issue>().singleOrNull()
|
|
||||||
if (issueCommand == null || outputs.isEmpty()) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun verifyIssueCommand(inputs: List<State>,
|
||||||
|
outputs: List<State>,
|
||||||
|
tx: TransactionForVerification,
|
||||||
|
issueCommand: AuthenticatedObject<Commands.Issue>,
|
||||||
|
currency: Currency,
|
||||||
|
issuer: Party) {
|
||||||
// If we have an issue command, perform special processing: the group is allowed to have no inputs,
|
// If we have an issue command, perform special processing: the group is allowed to have no inputs,
|
||||||
// and the output states must have a deposit reference owned by the signer.
|
// and the output states must have a deposit reference owned by the signer.
|
||||||
//
|
//
|
||||||
@ -132,12 +135,13 @@ class Cash : Contract {
|
|||||||
// The grouping ensures that all outputs have the same deposit reference and currency.
|
// The grouping ensures that all outputs have the same deposit reference and currency.
|
||||||
val inputAmount = inputs.sumCashOrZero(currency)
|
val inputAmount = inputs.sumCashOrZero(currency)
|
||||||
val outputAmount = outputs.sumCash()
|
val outputAmount = outputs.sumCash()
|
||||||
|
val cashCommands = tx.commands.select<Cash.Commands>()
|
||||||
requireThat {
|
requireThat {
|
||||||
"the issue command has a nonce" by (issueCommand.value.nonce != 0L)
|
"the issue command has a nonce" by (issueCommand.value.nonce != 0L)
|
||||||
"output deposits are owned by a command signer" by (issuer in issueCommand.signingParties)
|
"output deposits are owned by a command signer" by (issuer in issueCommand.signingParties)
|
||||||
"output values sum to more than the inputs" by (outputAmount > inputAmount)
|
"output values sum to more than the inputs" by (outputAmount > inputAmount)
|
||||||
|
"there is only a single issue command" by (cashCommands.count() == 1)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,6 +143,26 @@ class CashTests {
|
|||||||
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() }
|
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() }
|
||||||
this `fails requirement` "output values sum to more than the inputs"
|
this `fails requirement` "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) }
|
||||||
|
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() }
|
||||||
|
tweak {
|
||||||
|
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() }
|
||||||
|
this `fails requirement` "there is only a single issue command"
|
||||||
|
}
|
||||||
|
tweak {
|
||||||
|
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
||||||
|
this `fails requirement` "there is only a single issue command"
|
||||||
|
}
|
||||||
|
tweak {
|
||||||
|
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Exit(inState.amount / 2) }
|
||||||
|
this `fails requirement` "there is only a single issue command"
|
||||||
|
}
|
||||||
|
this.accepts()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Reference in New Issue
Block a user