diff --git a/src/contracts/Cash.kt b/src/contracts/Cash.kt index 086bd1693f..8b46c60fc9 100644 --- a/src/contracts/Cash.kt +++ b/src/contracts/Cash.kt @@ -66,7 +66,7 @@ object Cash : Contract { override fun verify(tx: TransactionForVerification) { // Each group is a set of input/output states with distinct (deposit, currency) attributes. These types // of cash are not fungible and must be kept separated for bookkeeping purposes. - val groups = groupStates(tx.inStates, tx.outStates) { Pair(it.deposit, it.amount.currency) } + val groups = tx.groupStates() { Pair(it.deposit, it.amount.currency) } for ((inputs, outputs) in groups) { requireThat { diff --git a/src/contracts/CommercialPaper.kt b/src/contracts/CommercialPaper.kt index b75b010ac8..18273ea20b 100644 --- a/src/contracts/CommercialPaper.kt +++ b/src/contracts/CommercialPaper.kt @@ -43,7 +43,7 @@ object CommercialPaper : Contract { override fun verify(tx: TransactionForVerification) { // Group by everything except owner: any modification to the CP at all is considered changing it fundamentally. - val groups = groupStates(tx.inStates, tx.outStates) { it.withoutOwner() } + val groups = tx.groupStates() { it.withoutOwner() } // There are two possible things that can be done with this CP. The first is trading it. The second is redeeming // it for cash on or after the maturity date. diff --git a/src/contracts/JavaCommercialPaper.java b/src/contracts/JavaCommercialPaper.java index 0326e4fdb2..0c81b06a9a 100644 --- a/src/contracts/JavaCommercialPaper.java +++ b/src/contracts/JavaCommercialPaper.java @@ -1,6 +1,7 @@ package contracts; import core.*; +import core.TransactionForVerification.*; import core.serialization.*; import kotlin.*; import org.jetbrains.annotations.*; @@ -77,8 +78,8 @@ public class JavaCommercialPaper implements Contract { public void verify(@NotNull TransactionForVerification tx) { // There are two possible things that can be done with CP. The first is trading it. The second is redeeming it // for cash on or after the maturity date. - List> groups = ContractTools.groupStates(State.class, tx.getInStates(), tx.getOutStates(), - state -> new Pair<>(state.getIssuance(), state.faceValue.getCurrency())); + List> groups = + tx.groupStates(State.class, state -> new Pair<>(state.getIssuance(), state.faceValue.getCurrency())); // Find the command that instructs us what to do and check there's exactly one. AuthenticatedObject cmd = requireSingleCommand(tx.getCommands(), Commands.class); diff --git a/src/core/ContractTools.kt b/src/core/ContractTools.kt deleted file mode 100644 index 188f5212e0..0000000000 --- a/src/core/ContractTools.kt +++ /dev/null @@ -1,52 +0,0 @@ -@file:JvmName("ContractTools") - -package core - -import java.util.* - -/** - * Utilities for contract writers to incorporate into their logic. - */ - -data class InOutGroup(val inputs: List, val outputs: List) - -// For Java users. -fun groupStates(ofType: Class, allInputs: List, - allOutputs: List, selector: (T) -> Any): List> { - val inputs = allInputs.filterIsInstance(ofType) - val outputs = allOutputs.filterIsInstance(ofType) - - val inGroups = inputs.groupBy(selector) - val outGroups = outputs.groupBy(selector) - - @Suppress("DEPRECATION") - return groupStatesInternal(inGroups, outGroups) -} - -// For Kotlin users: this version has nicer syntax and avoids reflection/object creation for the lambda. -inline fun groupStates(allInputs: List, - allOutputs: List, - selector: (T) -> Any): List> { - val inputs = allInputs.filterIsInstance() - val outputs = allOutputs.filterIsInstance() - - val inGroups = inputs.groupBy(selector) - val outGroups = outputs.groupBy(selector) - - @Suppress("DEPRECATION") - return groupStatesInternal(inGroups, outGroups) -} - -@Deprecated("Do not use this directly: exposed as public only due to function inlining") -fun groupStatesInternal(inGroups: Map>, outGroups: Map>): List> { - val result = ArrayList>() - - for ((k, v) in inGroups.entries) - result.add(InOutGroup(v, outGroups[k] ?: emptyList())) - for ((k, v) in outGroups.entries) { - if (inGroups[k] == null) - result.add(InOutGroup(emptyList(), v)) - } - - return result -} diff --git a/src/core/Transactions.kt b/src/core/Transactions.kt index c604b61627..53a6a2f053 100644 --- a/src/core/Transactions.kt +++ b/src/core/Transactions.kt @@ -207,6 +207,50 @@ data class TransactionForVerification(val inStates: List, } } } + + /** + * Utilities for contract writers to incorporate into their logic. + */ + + data class InOutGroup(val inputs: List, val outputs: List) + + // For Java users. + fun groupStates(ofType: Class, selector: (T) -> Any): List> { + val inputs = inStates.filterIsInstance(ofType) + val outputs = outStates.filterIsInstance(ofType) + + val inGroups = inputs.groupBy(selector) + val outGroups = outputs.groupBy(selector) + + @Suppress("DEPRECATION") + return groupStatesInternal(inGroups, outGroups) + } + + // For Kotlin users: this version has nicer syntax and avoids reflection/object creation for the lambda. + inline fun groupStates(selector: (T) -> Any): List> { + val inputs = inStates.filterIsInstance() + val outputs = outStates.filterIsInstance() + + val inGroups = inputs.groupBy(selector) + val outGroups = outputs.groupBy(selector) + + @Suppress("DEPRECATION") + return groupStatesInternal(inGroups, outGroups) + } + + @Deprecated("Do not use this directly: exposed as public only due to function inlining") + fun groupStatesInternal(inGroups: Map>, outGroups: Map>): List> { + val result = ArrayList>() + + for ((k, v) in inGroups.entries) + result.add(InOutGroup(v, outGroups[k] ?: emptyList())) + for ((k, v) in outGroups.entries) { + if (inGroups[k] == null) + result.add(InOutGroup(emptyList(), v)) + } + + return result + } } /** Thrown if a verification fails due to a contract rejection. */