diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt index 4e36dc0d69..3e7e06def1 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt @@ -93,11 +93,21 @@ fun List>.getTimestampByName(vararg names: Stri @Throws(IllegalArgumentException::class) // TODO: Can we have a common Move command for all contracts and avoid the reified type parameter here? inline fun verifyMoveCommand(inputs: List, tx: TransactionForContract) { + return verifyMoveCommand(inputs, tx.commands) +} + +/** + * Simple functionality for verifying a move command. Verifies that each input has a signature from its owning key. + * + * @param T the type of the move command + */ +@Throws(IllegalArgumentException::class) +inline fun verifyMoveCommand(inputs: List, commands: List>) { // Now check the digital signatures on the move command. Every input has an owning public key, and we must // see a signature from each of those keys. The actual signatures have been verified against the transaction // data by the platform before execution. val owningPubKeys = inputs.map { it.owner }.toSet() - val keysThatSigned = tx.commands.requireSingleCommand().signers.toSet() + val keysThatSigned = commands.requireSingleCommand().signers.toSet() requireThat { "the owning keys are the same as the signing keys" by keysThatSigned.containsAll(owningPubKeys) } diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/TransactionVerification.kt b/core/src/main/kotlin/com/r3corda/core/contracts/TransactionVerification.kt index 2b3c5551dd..bd83d1a629 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/TransactionVerification.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/TransactionVerification.kt @@ -93,6 +93,9 @@ data class TransactionForContract(val inputs: List, @Deprecated("This property was renamed to outputs", ReplaceWith("outputs")) val outStates: List get() = outputs + inline fun groupCommands(keySelector: (AuthenticatedObject) -> K): Map>> + = commands.select().groupBy(keySelector) + /** * Given a type and a function that returns a grouping key, associates inputs and outputs together so that they * can be processed as one. The grouping key is any arbitrary object that can act as a map key (so must implement diff --git a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt index 925a8f5983..1cae30a37c 100644 --- a/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt +++ b/core/src/main/kotlin/com/r3corda/core/testing/TestUtils.kt @@ -295,7 +295,7 @@ class TransactionGroupDSL(private val stateType: Class) { fun labelForState(output: TransactionState<*>): String? = outputsToLabels[output] inner class Roots { - fun transaction(vararg outputStates: LabeledOutput) { + fun transaction(vararg outputStates: LabeledOutput): Roots { val outs = outputStates.map { it.state } val wtx = WireTransaction(emptyList(), emptyList(), outs, emptyList(), emptyList(), TransactionType.General()) for ((index, state) in outputStates.withIndex()) { @@ -305,6 +305,7 @@ class TransactionGroupDSL(private val stateType: Class) { labelToOutputs[label] = state.state as TransactionState } rootTxns.add(wtx) + return this } /** @@ -370,8 +371,8 @@ class TransactionGroupDSL(private val stateType: Class) { verify() } assertEquals(index, e.index) - if (!e.cause!!.message!!.contains(message)) - throw AssertionError("Exception should have said '$message' but was actually: ${e.cause.message}", e.cause) + if (!(e.cause?.message ?: "") .contains(message)) + throw AssertionError("Exception should have said '$message' but was actually: ${e.cause?.message}", e.cause) return e }