Clean up semantics of composite clauses

This deprecates the existing composition clauses and adds new better named versions,
as well as changing 'AnyOf' to require at least one matching subclase (better matching
the name of the clause).
This commit is contained in:
Ross Nicoll 2017-01-13 14:10:54 +00:00
parent 7c0ffc78f8
commit 2efd44d46b
23 changed files with 187 additions and 113 deletions

View File

@ -1,39 +1,10 @@
package net.corda.core.contracts.clauses
import net.corda.core.contracts.AuthenticatedObject
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.TransactionForContract
import java.util.*
/**
* Compose a number of clauses, such that all of the clauses must run for verification to pass.
*/
// TODO: Rename to AllOf
class AllComposition<S : ContractState, C : CommandData, K : Any>(firstClause: Clause<S, C, K>, vararg remainingClauses: Clause<S, C, K>) : CompositeClause<S, C, K>() {
override val clauses = ArrayList<Clause<S, C, K>>()
init {
clauses.add(firstClause)
clauses.addAll(remainingClauses)
}
override fun matchedClauses(commands: List<AuthenticatedObject<C>>): List<Clause<S, C, K>> {
clauses.forEach { clause ->
check(clause.matches(commands)) { "Failed to match clause ${clause}" }
}
return clauses
}
override fun verify(tx: TransactionForContract,
inputs: List<S>,
outputs: List<S>,
commands: List<AuthenticatedObject<C>>,
groupingKey: K?): Set<C> {
return matchedClauses(commands).flatMapTo(HashSet<C>()) { clause ->
clause.verify(tx, inputs, outputs, commands, groupingKey)
}
}
override fun toString() = "All: $clauses.toList()"
}
@Deprecated("Use AllOf")
class AllComposition<S : ContractState, C : CommandData, K : Any>(firstClause: Clause<S, C, K>, vararg remainingClauses: Clause<S, C, K>) : AllOf<S, C, K>(firstClause, *remainingClauses)

View File

@ -0,0 +1,38 @@
package net.corda.core.contracts.clauses
import net.corda.core.contracts.AuthenticatedObject
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.TransactionForContract
import java.util.*
/**
* Compose a number of clauses, such that all of the clauses must run for verification to pass.
*/
open class AllOf<S : ContractState, C : CommandData, K : Any>(firstClause: Clause<S, C, K>, vararg remainingClauses: Clause<S, C, K>) : CompositeClause<S, C, K>() {
override val clauses = ArrayList<Clause<S, C, K>>()
init {
clauses.add(firstClause)
clauses.addAll(remainingClauses)
}
override fun matchedClauses(commands: List<AuthenticatedObject<C>>): List<Clause<S, C, K>> {
clauses.forEach { clause ->
check(clause.matches(commands)) { "Failed to match clause ${clause}" }
}
return clauses
}
override fun verify(tx: TransactionForContract,
inputs: List<S>,
outputs: List<S>,
commands: List<AuthenticatedObject<C>>,
groupingKey: K?): Set<C> {
return matchedClauses(commands).flatMapTo(HashSet<C>()) { clause ->
clause.verify(tx, inputs, outputs, commands, groupingKey)
}
}
override fun toString() = "All: $clauses.toList()"
}

View File

@ -1,25 +1,10 @@
package net.corda.core.contracts.clauses
import net.corda.core.contracts.AuthenticatedObject
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.TransactionForContract
import java.util.*
/**
* Compose a number of clauses, such that any number of the clauses can run.
*/
// TODO: Rename to AnyOf
class AnyComposition<in S : ContractState, C : CommandData, in K : Any>(vararg rawClauses: Clause<S, C, K>) : CompositeClause<S, C, K>() {
override val clauses: List<Clause<S, C, K>> = rawClauses.asList()
override fun matchedClauses(commands: List<AuthenticatedObject<C>>): List<Clause<S, C, K>> = clauses.filter { it.matches(commands) }
override fun verify(tx: TransactionForContract, inputs: List<S>, outputs: List<S>, commands: List<AuthenticatedObject<C>>, groupingKey: K?): Set<C> {
return matchedClauses(commands).flatMapTo(HashSet<C>()) { clause ->
clause.verify(tx, inputs, outputs, commands, groupingKey)
}
}
override fun toString(): String = "Or: ${clauses.toList()}"
}
@Deprecated("Use AnyOf instead, although note that any of requires at least one matched clause")
class AnyComposition<in S : ContractState, C : CommandData, in K : Any>(vararg rawClauses: Clause<S, C, K>) : AnyOf<S, C, K>(*rawClauses)

View File

@ -0,0 +1,28 @@
package net.corda.core.contracts.clauses
import net.corda.core.contracts.AuthenticatedObject
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.TransactionForContract
import java.util.*
/**
* Compose a number of clauses, such that one or more of the clauses can run.
*/
open class AnyOf<in S : ContractState, C : CommandData, in K : Any>(vararg rawClauses: Clause<S, C, K>) : CompositeClause<S, C, K>() {
override val clauses: List<Clause<S, C, K>> = rawClauses.toList()
override fun matchedClauses(commands: List<AuthenticatedObject<C>>): List<Clause<S, C, K>> {
val matched = clauses.filter { it.matches(commands) }
require(matched.isNotEmpty()) { "At least one clause must match" }
return matched
}
override fun verify(tx: TransactionForContract, inputs: List<S>, outputs: List<S>, commands: List<AuthenticatedObject<C>>, groupingKey: K?): Set<C> {
return matchedClauses(commands).flatMapTo(HashSet<C>()) { clause ->
clause.verify(tx, inputs, outputs, commands, groupingKey)
}
}
override fun toString(): String = "Any: ${clauses.toList()}"
}

View File

@ -26,7 +26,11 @@ abstract class Clause<in S : ContractState, C : CommandData, in K : Any> {
/**
* Determine the subclauses which will be verified as a result of verifying this clause.
*
* @throws IllegalStateException if the given commands do not result in a valid execution (for example no match
* with [FirstOf]).
*/
@Throws(IllegalStateException::class)
open fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>
= listOf(this)

View File

@ -14,6 +14,12 @@ abstract class CompositeClause<in S : ContractState, C : CommandData, in K : Any
override fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>
= matchedClauses(commands).flatMap { it.getExecutionPath(commands) }
/** Determine which clauses are matched by the supplied commands */
/**
* Determine which clauses are matched by the supplied commands.
*
* @throws IllegalStateException if the given commands do not result in a valid execution (for example no match
* with [FirstOf]).
*/
@Throws(IllegalStateException::class)
abstract fun matchedClauses(commands: List<AuthenticatedObject<C>>): List<Clause<S, C, K>>
}

View File

@ -10,7 +10,7 @@ import java.util.*
/**
* Compose a number of clauses, such that the first match is run, and it errors if none is run.
*/
// TODO: Rename to FirstOf
@Deprecated("Use FirstOf instead")
class FirstComposition<S : ContractState, C : CommandData, K : Any>(val firstClause: Clause<S, C, K>, vararg remainingClauses: Clause<S, C, K>) : CompositeClause<S, C, K>() {
companion object {
val logger = loggerFor<FirstComposition<*, *, *>>()

View File

@ -0,0 +1,41 @@
package net.corda.core.contracts.clauses
import net.corda.core.contracts.AuthenticatedObject
import net.corda.core.contracts.CommandData
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.TransactionForContract
import net.corda.core.utilities.loggerFor
import java.util.*
/**
* Compose a number of clauses, such that the first match is run, and it errors if none is run.
*/
class FirstOf<S : ContractState, C : CommandData, K : Any>(val firstClause: Clause<S, C, K>, vararg remainingClauses: Clause<S, C, K>) : CompositeClause<S, C, K>() {
companion object {
val logger = loggerFor<FirstOf<*, *, *>>()
}
override val clauses = ArrayList<Clause<S, C, K>>()
/**
* Get the single matched clause from the set this composes, based on the given commands. This is provided as
* helper method for internal use, rather than using the exposed [matchedClauses] function which unnecessarily
* wraps the clause in a list.
*/
private fun matchedClause(commands: List<AuthenticatedObject<C>>): Clause<S, C, K> {
return clauses.firstOrNull { it.matches(commands) } ?: throw IllegalStateException("No delegate clause matched in first composition")
}
override fun matchedClauses(commands: List<AuthenticatedObject<C>>) = listOf(matchedClause(commands))
init {
clauses.add(firstClause)
clauses.addAll(remainingClauses)
}
override fun verify(tx: TransactionForContract, inputs: List<S>, outputs: List<S>, commands: List<AuthenticatedObject<C>>, groupingKey: K?): Set<C> {
return matchedClause(commands).verify(tx, inputs, outputs, commands, groupingKey)
}
override fun toString() = "First: ${clauses.toList()}"
}

View File

@ -9,12 +9,12 @@ import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class AllCompositionTests {
class AllOfTests {
@Test
fun minimal() {
val counter = AtomicInteger(0)
val clause = AllComposition(matchedClause(counter), matchedClause(counter))
val clause = AllOf(matchedClause(counter), matchedClause(counter))
val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
@ -24,7 +24,7 @@ class AllCompositionTests {
@Test
fun `not all match`() {
val clause = AllComposition(matchedClause(), unmatchedClause())
val clause = AllOf(matchedClause(), unmatchedClause())
val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
assertFailsWith<IllegalStateException> { verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>()) }
}

View File

@ -7,12 +7,13 @@ import net.corda.core.crypto.SecureHash
import org.junit.Test
import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class AnyCompositionTests {
class AnyOfTests {
@Test
fun minimal() {
val counter = AtomicInteger(0)
val clause = AnyComposition(matchedClause(counter), matchedClause(counter))
val clause = AnyOf(matchedClause(counter), matchedClause(counter))
val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
@ -23,7 +24,7 @@ class AnyCompositionTests {
@Test
fun `not all match`() {
val counter = AtomicInteger(0)
val clause = AnyComposition(matchedClause(counter), unmatchedClause(counter))
val clause = AnyOf(matchedClause(counter), unmatchedClause(counter))
val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
@ -34,11 +35,10 @@ class AnyCompositionTests {
@Test
fun `none match`() {
val counter = AtomicInteger(0)
val clause = AnyComposition(unmatchedClause(counter), unmatchedClause(counter))
val clause = AnyOf(unmatchedClause(counter), unmatchedClause(counter))
val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
// Check that we've run the verify() function of neither clause
assertEquals(0, counter.get())
assertFailsWith(IllegalArgumentException::class) {
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
}
}
}

View File

@ -7,6 +7,7 @@ import net.corda.core.contracts.TransactionForContract
import java.util.concurrent.atomic.AtomicInteger
internal fun matchedClause(counter: AtomicInteger? = null) = object : Clause<ContractState, CommandData, Unit>() {
override val requiredCommands: Set<Class<out CommandData>> = emptySet()
override fun verify(tx: TransactionForContract,
inputs: List<ContractState>,
outputs: List<ContractState>,

View File

@ -37,7 +37,7 @@ When writing a contract you need to override the contract's ``verify`` function
there is a check if all of transaction's commands were matched. If not, then an exception is raised. This is done to
enforce that spurious commands cannot be included in a transaction, ensuring that the transaction is as clear as
possible. As an example imagine a transaction with two commands: ``Move`` and ``Issue`` included, with verification written
using ``FirstComposition`` on clauses that require single command set. Thus only one of transaction's commands will match
using ``FirstOf`` on clauses that require single command set. Thus only one of transaction's commands will match
leaving the second unprocessed. It should raise an error - we want to ensure that commands set is minimal to simplify
analysis of intent of a transaction.
@ -47,14 +47,14 @@ An example ``verify`` from ``Obligation`` contract:
.. sourcecode:: kotlin
override fun verify(tx: TransactionForContract) = verifyClause<Commands>(tx, FirstComposition<ContractState, Commands, Unit>(
override fun verify(tx: TransactionForContract) = verifyClause<Commands>(tx, FirstOf<ContractState, Commands, Unit>(
Clauses.Net<Commands, P>(),
Clauses.Group<P>()
), tx.commands.select<Obligation.Commands>())
It takes transaction to be verified, and passes it along with a top-level clause and commands to the ``verifyClause``
function. As you can see above we have used ``FirstComposition`` which is a special type of clause, which extends the
``CompositeClause`` abstract class (in that particular case, it ensures that either ``Net`` or ``Group`` will run - for explanation see `FirstComposition`_).
function. As you can see above we have used ``FirstOf`` which is a special type of clause, which extends the
``CompositeClause`` abstract class (in that particular case, it ensures that either ``Net`` or ``Group`` will run - for explanation see `FirstOf`_).
It's a type of clause that adds support for encapsulating multiple clauses and defines common behaviour for that composition.
There is also a ``GroupClauseVerifier`` special clause, which specifies how to group transaction input/output states
together and passes them to adequate clause for further processing.
@ -66,37 +66,37 @@ One of the most important concepts of clauses - composition clauses which extend
providing a range of ways of assembling clauses together. They define a logic of verification execution specifying which clauses
will be run.
AllComposition
~~~~~~~~~~~~~~
AllOf
~~~~~
**Description**
Composes a number of clauses, such that all of the clauses must run for verification to pass.
.. image:: resources/allCompositionChart.png
.. image:: resources/allOfChart.png
Short description:
- ``AllComposition`` holds clauses *Cl1,..,Cl5*.
- Check if all clauses that compose ``AllComposition`` have associated commands in a command set - if not, verification fails.
- ``AllOf`` holds clauses *Cl1,..,Cl5*.
- Check if all clauses that compose ``AllOf`` have associated commands in a command set - if not, verification fails.
- After successful check runs verification logic specific for every clause *Cl1,..,Cl5* from that composition.
**Usage**
See code in `GroupClauseVerifier`_.
AnyComposition
~~~~~~~~~~~~~~
AnyOf
~~~~~
**Description**
Composes a number of clauses, such that 0 or more of the clauses can be run.
Composes a number of clauses, such that 1 or more of the clauses can be run.
.. image:: resources/anyCompositionChart.png
.. image:: resources/anyOfChart.png
Short description:
- Checks if zero or more clauses that compose AnyComposition have associated commands in a command set.
- Checks if one or more clauses that compose AnyOf have associated commands in a command set.
- After success runs verification logic specific for every *matched* (in this case *Cl2, Cl4, Cl5*) clause from composition.
**Usage**
@ -108,7 +108,7 @@ Example from ``CommercialPaper.kt``:
.. sourcecode:: kotlin
class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>(
AnyComposition(
AnyOf(
Redeem(),
Move(),
Issue())) {
@ -116,14 +116,14 @@ Example from ``CommercialPaper.kt``:
= tx.groupStates<State, Issued<Terms>> { it.token }
}
FirstComposition
~~~~~~~~~~~~~~~~
FirstOf
~~~~~~~
**Description**
Composes a number of clauses, such that the first match is run, and it errors if none is run.
.. image:: resources/firstCompositionChart.png
.. image:: resources/firstOfChart.png
Short description:
@ -168,13 +168,13 @@ grouped input and output states with a grouping key used for each group. Example
.. sourcecode:: kotlin
class Group<P> : GroupClauseVerifier<State<P>, Commands, Issued<Terms<P>>>(
AllComposition(
AllOf(
NoZeroSizedOutputs<State<P>, Commands, Terms<P>>(),
FirstComposition(
FirstOf(
SetLifecycle<P>(),
AllComposition(
AllOf(
VerifyLifecycle<State<P>, Commands, Issued<Terms<P>>, P>(),
FirstComposition(
FirstOf(
Settle<P>(),
Issue(),
ConserveAmount()

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -36,20 +36,20 @@ to be considered valid. We refer to a clause as being "matched" when the transac
in question to trigger. Meanwhile, we talk about a clause "verifying" when its ``verify()`` function returns ``True``.
As an example, let's say we want a transaction to be valid only when every single one of its clauses matches and verifies. We implement this
by wrapping the individual clauses into an ``AllComposition`` composite clause, which ensures that a transaction is
by wrapping the individual clauses into an ``AllOf`` composite clause, which ensures that a transaction is
only considered valid if all of its clauses are both matched and verify.
There are two other basic composite clauses that you should be aware of:
* ``AnyComposition``, whereby any number of clauses (0+) may match, but each matched clause must verify
* ``FirstComposition``, whereby at least one clause must match, and the first such clause must verify
* ``AnyOf``, whereby 1 or more clauses may match, and every matched clause must verify
* ``FirstOf``, whereby at least one clause must match, and the first such clause must verify
In turn, composite clauses are themselves ``Clause`` s, and can, for example, be wrapped in the special ``GroupClauseVerifier`` grouping clause.
For ``CommercialPaper``, this would look as follows:
.. image:: resources/commPaperClauses.png
For this tutorial, we will be using ``GroupClauseVerifier`` and ``AnyComposition``. Since it's important to understand how these work,
For this tutorial, we will be using ``GroupClauseVerifier`` and ``AnyOf``. Since it's important to understand how these work,
charts showing their execution and other details can be found in :doc:`clauses`.
.. _verify_ref:
@ -225,7 +225,7 @@ its subclauses (wrapped move, issue, redeem). "Any" in this case means that it w
.. sourcecode:: kotlin
class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>(
AnyComposition(
AnyOf(
Redeem(),
Move(),
Issue())) {
@ -237,7 +237,7 @@ its subclauses (wrapped move, issue, redeem). "Any" in this case means that it w
class Group extends GroupClauseVerifier<State, Commands, State> {
public Group() {
super(new AnyComposition<>(
super(new AnyOf<>(
new Clauses.Redeem(),
new Clauses.Move(),
new Clauses.Issue()

View File

@ -131,10 +131,10 @@ public class JavaCommercialPaper implements Contract {
// warning.
@SuppressWarnings("unchecked")
Group() {
super(new AnyComposition<>(
new Clauses.Redeem(),
new Clauses.Move(),
new Clauses.Issue()
super(new AnyOf<>(
new Clauses.Redeem(),
new Clauses.Move(),
new Clauses.Issue()
));
}

View File

@ -3,7 +3,7 @@ package net.corda.contracts
import net.corda.contracts.asset.sumCashBy
import net.corda.contracts.clause.AbstractIssue
import net.corda.core.contracts.*
import net.corda.core.contracts.clauses.AnyComposition
import net.corda.core.contracts.clauses.AnyOf
import net.corda.core.contracts.clauses.Clause
import net.corda.core.contracts.clauses.GroupClauseVerifier
import net.corda.core.contracts.clauses.verifyClause
@ -103,10 +103,10 @@ class CommercialPaper : Contract {
interface Clauses {
class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>(
AnyComposition(
Redeem(),
Move(),
Issue())) {
AnyOf(
Redeem(),
Move(),
Issue())) {
override fun groupStates(tx: TransactionForContract): List<TransactionForContract.InOutGroup<State, Issued<Terms>>>
= tx.groupStates<State, Issued<Terms>> { it.token }
}

View File

@ -4,8 +4,8 @@ import net.corda.contracts.clause.AbstractConserveAmount
import net.corda.contracts.clause.AbstractIssue
import net.corda.contracts.clause.NoZeroSizedOutputs
import net.corda.core.contracts.*
import net.corda.core.contracts.clauses.AllComposition
import net.corda.core.contracts.clauses.FirstComposition
import net.corda.core.contracts.clauses.AllOf
import net.corda.core.contracts.clauses.FirstOf
import net.corda.core.contracts.clauses.GroupClauseVerifier
import net.corda.core.contracts.clauses.verifyClause
import net.corda.core.crypto.*
@ -56,9 +56,9 @@ class Cash : OnLedgerAsset<Currency, Cash.Commands, Cash.State>() {
= commands.select<Cash.Commands>()
interface Clauses {
class Group : GroupClauseVerifier<State, Commands, Issued<Currency>>(AllComposition<State, Commands, Issued<Currency>>(
class Group : GroupClauseVerifier<State, Commands, Issued<Currency>>(AllOf<State, Commands, Issued<Currency>>(
NoZeroSizedOutputs<State, Commands, Currency>(),
FirstComposition<State, Commands, Issued<Currency>>(
FirstOf<State, Commands, Issued<Currency>>(
Issue(),
ConserveAmount())
)

View File

@ -4,7 +4,7 @@ import net.corda.contracts.clause.AbstractConserveAmount
import net.corda.contracts.clause.AbstractIssue
import net.corda.contracts.clause.NoZeroSizedOutputs
import net.corda.core.contracts.*
import net.corda.core.contracts.clauses.AnyComposition
import net.corda.core.contracts.clauses.AnyOf
import net.corda.core.contracts.clauses.GroupClauseVerifier
import net.corda.core.contracts.clauses.verifyClause
import net.corda.core.crypto.CompositeKey
@ -62,7 +62,7 @@ class CommodityContract : OnLedgerAsset<Commodity, CommodityContract.Commands, C
* Grouping clause to extract input and output states into matched groups and then run a set of clauses over
* each group.
*/
class Group : GroupClauseVerifier<State, Commands, Issued<Commodity>>(AnyComposition(
class Group : GroupClauseVerifier<State, Commands, Issued<Commodity>>(AnyOf(
NoZeroSizedOutputs<State, Commands, Commodity>(),
Issue(),
ConserveAmount())) {

View File

@ -47,13 +47,13 @@ class Obligation<P> : Contract {
* Parent clause for clauses that operate on grouped states (those which are fungible).
*/
class Group<P> : GroupClauseVerifier<State<P>, Commands, Issued<Terms<P>>>(
AllComposition(
AllOf(
NoZeroSizedOutputs<State<P>, Commands, Terms<P>>(),
FirstComposition(
FirstOf(
SetLifecycle<P>(),
AllComposition(
AllOf(
VerifyLifecycle<State<P>, Commands, Issued<Terms<P>>, P>(),
FirstComposition(
FirstOf(
Settle<P>(),
Issue(),
ConserveAmount()
@ -364,7 +364,7 @@ class Obligation<P> : Contract {
data class Exit<P>(override val amount: Amount<Issued<Terms<P>>>) : Commands, FungibleAsset.Commands.Exit<Terms<P>>
}
override fun verify(tx: TransactionForContract) = verifyClause<Commands>(tx, FirstComposition<ContractState, Commands, Unit>(
override fun verify(tx: TransactionForContract) = verifyClause<Commands>(tx, FirstOf<ContractState, Commands, Unit>(
Clauses.Net<Commands, P>(),
Clauses.Group<P>()
), tx.commands.select<Obligation.Commands>())

View File

@ -9,7 +9,7 @@ import java.math.BigDecimal
* Specifies the contract between two parties that trade an OpenGamma IRS. Currently can only agree to trade.
*/
data class OGTrade(override val legalContractReference: SecureHash = SecureHash.sha256("OGTRADE.KT")) : Contract {
override fun verify(tx: TransactionForContract) = verifyClause(tx, AllComposition(Clauses.Timestamped(), Clauses.Group()), tx.commands.select<Commands>())
override fun verify(tx: TransactionForContract) = verifyClause(tx, AllOf(Clauses.Timestamped(), Clauses.Group()), tx.commands.select<Commands>())
interface Commands : CommandData {
class Agree : TypeOnlyCommandData(), Commands // Both sides agree to trade
@ -28,7 +28,7 @@ data class OGTrade(override val legalContractReference: SecureHash = SecureHash.
}
}
class Group : GroupClauseVerifier<IRSState, Commands, UniqueIdentifier>(AnyComposition(Agree())) {
class Group : GroupClauseVerifier<IRSState, Commands, UniqueIdentifier>(AnyOf(Agree())) {
override fun groupStates(tx: TransactionForContract): List<TransactionForContract.InOutGroup<IRSState, UniqueIdentifier>>
// Group by Trade ID for in / out states
= tx.groupStates() { state -> state.linearId }

View File

@ -10,7 +10,7 @@ import net.corda.core.crypto.SecureHash
* of the portfolio arbitrarily.
*/
data class PortfolioSwap(override val legalContractReference: SecureHash = SecureHash.sha256("swordfish")) : Contract {
override fun verify(tx: TransactionForContract) = verifyClause(tx, AllComposition(Clauses.Timestamped(), Clauses.Group()), tx.commands.select<Commands>())
override fun verify(tx: TransactionForContract) = verifyClause(tx, AllOf(Clauses.Timestamped(), Clauses.Group()), tx.commands.select<Commands>())
interface Commands : CommandData {
class Agree : TypeOnlyCommandData(), Commands // Both sides agree to portfolio
@ -30,7 +30,7 @@ data class PortfolioSwap(override val legalContractReference: SecureHash = Secur
}
}
class Group : GroupClauseVerifier<PortfolioState, Commands, UniqueIdentifier>(FirstComposition(Agree(), Update())) {
class Group : GroupClauseVerifier<PortfolioState, Commands, UniqueIdentifier>(FirstOf(Agree(), Update())) {
override fun groupStates(tx: TransactionForContract): List<TransactionForContract.InOutGroup<PortfolioState, UniqueIdentifier>>
// Group by Trade ID for in / out states
= tx.groupStates() { state -> state.linearId }