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 package net.corda.core.contracts.clauses
import net.corda.core.contracts.AuthenticatedObject
import net.corda.core.contracts.CommandData import net.corda.core.contracts.CommandData
import net.corda.core.contracts.ContractState 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. * Compose a number of clauses, such that all of the clauses must run for verification to pass.
*/ */
// TODO: Rename to AllOf @Deprecated("Use AllOf")
class AllComposition<S : ContractState, C : CommandData, K : Any>(firstClause: Clause<S, C, K>, vararg remainingClauses: Clause<S, C, K>) : CompositeClause<S, C, K>() { 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)
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

@ -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 package net.corda.core.contracts.clauses
import net.corda.core.contracts.AuthenticatedObject
import net.corda.core.contracts.CommandData import net.corda.core.contracts.CommandData
import net.corda.core.contracts.ContractState 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. * Compose a number of clauses, such that any number of the clauses can run.
*/ */
// TODO: Rename to AnyOf @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>) : CompositeClause<S, C, K>() { class AnyComposition<in S : ContractState, C : CommandData, in K : Any>(vararg rawClauses: Clause<S, C, K>) : AnyOf<S, C, K>(*rawClauses)
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()}"
}

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. * 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<*, *, *>> open fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>
= listOf(this) = 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<*, *, *>> override fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>
= matchedClauses(commands).flatMap { it.getExecutionPath(commands) } = 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>> 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. * 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>() { 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 { companion object {
val logger = loggerFor<FirstComposition<*, *, *>>() 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.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
class AllCompositionTests { class AllOfTests {
@Test @Test
fun minimal() { fun minimal() {
val counter = AtomicInteger(0) 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()) val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>()) verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
@ -24,7 +24,7 @@ class AllCompositionTests {
@Test @Test
fun `not all match`() { fun `not all match`() {
val clause = AllComposition(matchedClause(), unmatchedClause()) val clause = AllOf(matchedClause(), unmatchedClause())
val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256()) val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
assertFailsWith<IllegalStateException> { verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>()) } 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 org.junit.Test
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class AnyCompositionTests { class AnyOfTests {
@Test @Test
fun minimal() { fun minimal() {
val counter = AtomicInteger(0) 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()) val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>()) verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
@ -23,7 +24,7 @@ class AnyCompositionTests {
@Test @Test
fun `not all match`() { fun `not all match`() {
val counter = AtomicInteger(0) 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()) val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>()) verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
@ -34,11 +35,10 @@ class AnyCompositionTests {
@Test @Test
fun `none match`() { fun `none match`() {
val counter = AtomicInteger(0) 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()) val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
assertFailsWith(IllegalArgumentException::class) {
verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>()) verifyClause(tx, clause, emptyList<AuthenticatedObject<CommandData>>())
}
// Check that we've run the verify() function of neither clause
assertEquals(0, counter.get())
} }
} }

View File

@ -7,6 +7,7 @@ import net.corda.core.contracts.TransactionForContract
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
internal fun matchedClause(counter: AtomicInteger? = null) = object : Clause<ContractState, CommandData, Unit>() { internal fun matchedClause(counter: AtomicInteger? = null) = object : Clause<ContractState, CommandData, Unit>() {
override val requiredCommands: Set<Class<out CommandData>> = emptySet()
override fun verify(tx: TransactionForContract, override fun verify(tx: TransactionForContract,
inputs: List<ContractState>, inputs: List<ContractState>,
outputs: 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 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 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 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 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. analysis of intent of a transaction.
@ -47,14 +47,14 @@ An example ``verify`` from ``Obligation`` contract:
.. sourcecode:: kotlin .. 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.Net<Commands, P>(),
Clauses.Group<P>() Clauses.Group<P>()
), tx.commands.select<Obligation.Commands>()) ), 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`` 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 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 `FirstComposition`_). ``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. 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 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. 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 providing a range of ways of assembling clauses together. They define a logic of verification execution specifying which clauses
will be run. will be run.
AllComposition AllOf
~~~~~~~~~~~~~~ ~~~~~
**Description** **Description**
Composes a number of clauses, such that all of the clauses must run for verification to pass. 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: Short description:
- ``AllComposition`` holds clauses *Cl1,..,Cl5*. - ``AllOf`` holds clauses *Cl1,..,Cl5*.
- Check if all clauses that compose ``AllComposition`` have associated commands in a command set - if not, verification fails. - 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. - After successful check runs verification logic specific for every clause *Cl1,..,Cl5* from that composition.
**Usage** **Usage**
See code in `GroupClauseVerifier`_. See code in `GroupClauseVerifier`_.
AnyComposition AnyOf
~~~~~~~~~~~~~~ ~~~~~
**Description** **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: 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. - After success runs verification logic specific for every *matched* (in this case *Cl2, Cl4, Cl5*) clause from composition.
**Usage** **Usage**
@ -108,7 +108,7 @@ Example from ``CommercialPaper.kt``:
.. sourcecode:: kotlin .. sourcecode:: kotlin
class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>( class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>(
AnyComposition( AnyOf(
Redeem(), Redeem(),
Move(), Move(),
Issue())) { Issue())) {
@ -116,14 +116,14 @@ Example from ``CommercialPaper.kt``:
= tx.groupStates<State, Issued<Terms>> { it.token } = tx.groupStates<State, Issued<Terms>> { it.token }
} }
FirstComposition FirstOf
~~~~~~~~~~~~~~~~ ~~~~~~~
**Description** **Description**
Composes a number of clauses, such that the first match is run, and it errors if none is run. 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: Short description:
@ -168,13 +168,13 @@ grouped input and output states with a grouping key used for each group. Example
.. sourcecode:: kotlin .. sourcecode:: kotlin
class Group<P> : GroupClauseVerifier<State<P>, Commands, Issued<Terms<P>>>( class Group<P> : GroupClauseVerifier<State<P>, Commands, Issued<Terms<P>>>(
AllComposition( AllOf(
NoZeroSizedOutputs<State<P>, Commands, Terms<P>>(), NoZeroSizedOutputs<State<P>, Commands, Terms<P>>(),
FirstComposition( FirstOf(
SetLifecycle<P>(), SetLifecycle<P>(),
AllComposition( AllOf(
VerifyLifecycle<State<P>, Commands, Issued<Terms<P>>, P>(), VerifyLifecycle<State<P>, Commands, Issued<Terms<P>>, P>(),
FirstComposition( FirstOf(
Settle<P>(), Settle<P>(),
Issue(), Issue(),
ConserveAmount() 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``. 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 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. 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: 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 * ``AnyOf``, whereby 1 or more clauses may match, and every matched clause must verify
* ``FirstComposition``, whereby at least one clause must match, and the first such 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. 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: For ``CommercialPaper``, this would look as follows:
.. image:: resources/commPaperClauses.png .. 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`. charts showing their execution and other details can be found in :doc:`clauses`.
.. _verify_ref: .. _verify_ref:
@ -225,7 +225,7 @@ its subclauses (wrapped move, issue, redeem). "Any" in this case means that it w
.. sourcecode:: kotlin .. sourcecode:: kotlin
class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>( class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>(
AnyComposition( AnyOf(
Redeem(), Redeem(),
Move(), Move(),
Issue())) { 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> { class Group extends GroupClauseVerifier<State, Commands, State> {
public Group() { public Group() {
super(new AnyComposition<>( super(new AnyOf<>(
new Clauses.Redeem(), new Clauses.Redeem(),
new Clauses.Move(), new Clauses.Move(),
new Clauses.Issue() new Clauses.Issue()

View File

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

View File

@ -3,7 +3,7 @@ package net.corda.contracts
import net.corda.contracts.asset.sumCashBy import net.corda.contracts.asset.sumCashBy
import net.corda.contracts.clause.AbstractIssue import net.corda.contracts.clause.AbstractIssue
import net.corda.core.contracts.* 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.Clause
import net.corda.core.contracts.clauses.GroupClauseVerifier import net.corda.core.contracts.clauses.GroupClauseVerifier
import net.corda.core.contracts.clauses.verifyClause import net.corda.core.contracts.clauses.verifyClause
@ -103,7 +103,7 @@ class CommercialPaper : Contract {
interface Clauses { interface Clauses {
class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>( class Group : GroupClauseVerifier<State, Commands, Issued<Terms>>(
AnyComposition( AnyOf(
Redeem(), Redeem(),
Move(), Move(),
Issue())) { Issue())) {

View File

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

View File

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

View File

@ -47,13 +47,13 @@ class Obligation<P> : Contract {
* Parent clause for clauses that operate on grouped states (those which are fungible). * Parent clause for clauses that operate on grouped states (those which are fungible).
*/ */
class Group<P> : GroupClauseVerifier<State<P>, Commands, Issued<Terms<P>>>( class Group<P> : GroupClauseVerifier<State<P>, Commands, Issued<Terms<P>>>(
AllComposition( AllOf(
NoZeroSizedOutputs<State<P>, Commands, Terms<P>>(), NoZeroSizedOutputs<State<P>, Commands, Terms<P>>(),
FirstComposition( FirstOf(
SetLifecycle<P>(), SetLifecycle<P>(),
AllComposition( AllOf(
VerifyLifecycle<State<P>, Commands, Issued<Terms<P>>, P>(), VerifyLifecycle<State<P>, Commands, Issued<Terms<P>>, P>(),
FirstComposition( FirstOf(
Settle<P>(), Settle<P>(),
Issue(), Issue(),
ConserveAmount() 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>> 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.Net<Commands, P>(),
Clauses.Group<P>() Clauses.Group<P>()
), tx.commands.select<Obligation.Commands>()) ), 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. * 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 { 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 { interface Commands : CommandData {
class Agree : TypeOnlyCommandData(), Commands // Both sides agree to trade 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>> override fun groupStates(tx: TransactionForContract): List<TransactionForContract.InOutGroup<IRSState, UniqueIdentifier>>
// Group by Trade ID for in / out states // Group by Trade ID for in / out states
= tx.groupStates() { state -> state.linearId } = tx.groupStates() { state -> state.linearId }

View File

@ -10,7 +10,7 @@ import net.corda.core.crypto.SecureHash
* of the portfolio arbitrarily. * of the portfolio arbitrarily.
*/ */
data class PortfolioSwap(override val legalContractReference: SecureHash = SecureHash.sha256("swordfish")) : Contract { 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 { interface Commands : CommandData {
class Agree : TypeOnlyCommandData(), Commands // Both sides agree to portfolio 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>> override fun groupStates(tx: TransactionForContract): List<TransactionForContract.InOutGroup<PortfolioState, UniqueIdentifier>>
// Group by Trade ID for in / out states // Group by Trade ID for in / out states
= tx.groupStates() { state -> state.linearId } = tx.groupStates() { state -> state.linearId }