diff --git a/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java b/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java index d986eb1130..b2a1997354 100644 --- a/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java +++ b/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java @@ -142,7 +142,7 @@ public class JavaCommercialPaper implements Contract { } } - class Move extends ConcreteClause { + class Move extends Clause { @NotNull @Override public Set> getRequiredCommands() { @@ -173,7 +173,7 @@ public class JavaCommercialPaper implements Contract { } } - class Redeem extends ConcreteClause { + class Redeem extends Clause { @NotNull @Override public Set> getRequiredCommands() { @@ -215,7 +215,7 @@ public class JavaCommercialPaper implements Contract { } } - class Issue extends ConcreteClause { + class Issue extends Clause { @NotNull @Override public Set> getRequiredCommands() { diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/CommercialPaper.kt b/contracts/src/main/kotlin/com/r3corda/contracts/CommercialPaper.kt index a224844b11..21e61320d2 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/CommercialPaper.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/CommercialPaper.kt @@ -107,7 +107,7 @@ class CommercialPaper : Contract { } } - class Move: ConcreteClause>() { + class Move: Clause>() { override val requiredCommands: Set> = setOf(Commands.Move::class.java) override fun verify(tx: TransactionForContract, @@ -127,7 +127,7 @@ class CommercialPaper : Contract { } } - class Redeem(): ConcreteClause>() { + class Redeem(): Clause>() { override val requiredCommands: Set> = setOf(Commands.Redeem::class.java) override fun verify(tx: TransactionForContract, diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt index af3d33c827..eeac0c81ed 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/IRS.kt @@ -454,7 +454,7 @@ class InterestRateSwap() : Contract { * Common superclass for IRS contract clauses, which defines behaviour on match/no-match, and provides * helper functions for the clauses. */ - abstract class AbstractIRSClause : ConcreteClause() { + abstract class AbstractIRSClause : Clause() { // These functions may make more sense to use for basket types, but for now let's leave them here fun checkLegDates(legs: List) { requireThat { @@ -502,7 +502,7 @@ class InterestRateSwap() : Contract { = tx.groupStates() { state -> state.linearId } } - class Timestamped : ConcreteClause() { + class Timestamped : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/asset/Obligation.kt b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Obligation.kt index 217a9bccb9..8dca61e63c 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/asset/Obligation.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/asset/Obligation.kt @@ -90,7 +90,7 @@ class Obligation

: Contract { /** * Obligation-specific clause for changing the lifecycle of one or more states. */ - class SetLifecycle

: ConcreteClause, Commands, Issued>>() { + class SetLifecycle

: Clause, Commands, Issued>>() { override val requiredCommands: Set> = setOf(Commands.SetLifecycle::class.java) override fun verify(tx: TransactionForContract, @@ -110,7 +110,7 @@ class Obligation

: Contract { * Obligation-specific clause for settling an outstanding obligation by witnessing * change of ownership of other states to fulfil */ - class Settle

: ConcreteClause, Commands, Issued>>() { + class Settle

: Clause, Commands, Issued>>() { override val requiredCommands: Set> = setOf(Commands.Settle::class.java) override fun verify(tx: TransactionForContract, inputs: List>, @@ -199,7 +199,7 @@ class Obligation

: Contract { * any lifecycle change clause, which is the only clause that involve * non-standard lifecycle states on input/output. */ - class VerifyLifecycle : ConcreteClause() { + class VerifyLifecycle : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/clause/AbstractConserveAmount.kt b/contracts/src/main/kotlin/com/r3corda/contracts/clause/AbstractConserveAmount.kt index 963e44ff27..cd3bd528b2 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/clause/AbstractConserveAmount.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/clause/AbstractConserveAmount.kt @@ -5,7 +5,7 @@ import com.r3corda.contracts.asset.InsufficientBalanceException import com.r3corda.contracts.asset.sumFungibleOrNull import com.r3corda.contracts.asset.sumFungibleOrZero import com.r3corda.core.contracts.* -import com.r3corda.core.contracts.clauses.ConcreteClause +import com.r3corda.core.contracts.clauses.Clause import com.r3corda.core.crypto.Party import java.security.PublicKey import java.util.* @@ -15,7 +15,7 @@ import java.util.* * Move command is provided, and errors if absent. Must be the last clause under a grouping clause; * errors on no-match, ends on match. */ -abstract class AbstractConserveAmount, C : CommandData, T : Any> : ConcreteClause>() { +abstract class AbstractConserveAmount, C : CommandData, T : Any> : Clause>() { /** * Gather assets from the given list of states, sufficient to match or exceed the given amount. * diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/clause/AbstractIssue.kt b/contracts/src/main/kotlin/com/r3corda/contracts/clause/AbstractIssue.kt index ee5b28089a..ecd3300083 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/clause/AbstractIssue.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/clause/AbstractIssue.kt @@ -1,7 +1,7 @@ package com.r3corda.contracts.clause import com.r3corda.core.contracts.* -import com.r3corda.core.contracts.clauses.ConcreteClause +import com.r3corda.core.contracts.clauses.Clause /** * Standard issue clause for contracts that issue fungible assets. @@ -16,7 +16,7 @@ import com.r3corda.core.contracts.clauses.ConcreteClause abstract class AbstractIssue( val sum: List.() -> Amount>, val sumOrZero: List.(token: Issued) -> Amount> -) : ConcreteClause>() { +) : Clause>() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/clause/Net.kt b/contracts/src/main/kotlin/com/r3corda/contracts/clause/Net.kt index d67f7be52e..674150aa61 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/clause/Net.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/clause/Net.kt @@ -5,7 +5,7 @@ import com.r3corda.contracts.asset.Obligation import com.r3corda.contracts.asset.extractAmountsDue import com.r3corda.contracts.asset.sumAmountsDue import com.r3corda.core.contracts.* -import com.r3corda.core.contracts.clauses.ConcreteClause +import com.r3corda.core.contracts.clauses.Clause import java.security.PublicKey /** @@ -42,7 +42,7 @@ data class MultilateralNetState

( * Clause for netting contract states. Currently only supports obligation contract. */ // TODO: Make this usable for any nettable contract states -open class NetClause : ConcreteClause() { +open class NetClause : Clause() { override val requiredCommands: Set> = setOf(Obligation.Commands.Net::class.java) @Suppress("ConvertLambdaToReference") diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/clause/NoZeroSizedOutputs.kt b/contracts/src/main/kotlin/com/r3corda/contracts/clause/NoZeroSizedOutputs.kt index ef59c4bd9c..f214587c89 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/clause/NoZeroSizedOutputs.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/clause/NoZeroSizedOutputs.kt @@ -2,13 +2,13 @@ package com.r3corda.contracts.clause import com.r3corda.contracts.asset.FungibleAsset import com.r3corda.core.contracts.* -import com.r3corda.core.contracts.clauses.ConcreteClause +import com.r3corda.core.contracts.clauses.Clause /** * Clause for fungible asset contracts, which enforces that no output state should have * a balance of zero. */ -open class NoZeroSizedOutputs, C : CommandData, T : Any> : ConcreteClause>() { +open class NoZeroSizedOutputs, C : CommandData, T : Any> : Clause>() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt index 34b5fc60af..b8c949a97c 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt @@ -1,6 +1,5 @@ package com.r3corda.core.contracts -import com.r3corda.core.contracts.clauses.ConcreteClause import com.r3corda.core.contracts.clauses.Clause import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.SecureHash @@ -218,7 +217,7 @@ interface LinearState: ContractState { /** * Standard clause to verify the LinearState safety properties. */ - class ClauseVerifier(val stateClass: Class) : ConcreteClause() { + class ClauseVerifier(val stateClass: Class) : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/Clause.kt b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/Clause.kt index 3b3072f695..a9060090c6 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/Clause.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/Clause.kt @@ -7,22 +7,28 @@ import com.r3corda.core.contracts.TransactionForContract import com.r3corda.core.utilities.loggerFor /** + * A clause of a contract, containing a chunk of verification logic. That logic may be delegated to other clauses, or + * provided directly by this clause. + * * @param S the type of contract state this clause operates on. * @param C a common supertype of commands this clause operates on. * @param K the type of the grouping key for states this clause operates on. Use [Unit] if not applicable. + * + * @see CompositeClause */ -interface Clause { +abstract class Clause { companion object { val log = loggerFor>() } /** Determine whether this clause runs or not */ - val requiredCommands: Set> + open val requiredCommands: Set> = emptySet() /** * Determine the subclauses which will be verified as a result of verifying this clause. */ - fun getExecutionPath(commands: List>): List> + open fun getExecutionPath(commands: List>): List> + = listOf(this) /** * Verify the transaction matches the conditions from this clause. For example, a "no zero amount output" clause @@ -45,11 +51,11 @@ interface Clause { * commands that were not required (for example the Exit command for fungible assets is optional). */ @Throws(IllegalStateException::class) - fun verify(tx: TransactionForContract, - inputs: List, - outputs: List, - commands: List>, - groupingKey: K?): Set + abstract fun verify(tx: TransactionForContract, + inputs: List, + outputs: List, + commands: List>, + groupingKey: K?): Set } /** diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/CompositeClause.kt b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/CompositeClause.kt index 90e2a3cb8f..f8a0bca4c6 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/CompositeClause.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/CompositeClause.kt @@ -6,13 +6,10 @@ import com.r3corda.core.contracts.ContractState /** * Abstract supertype for clauses which compose other clauses together in some logical manner. - * - * @see ConcreteClause */ -abstract class CompositeClause: Clause { +abstract class CompositeClause: Clause() { /** List of clauses under this composite clause */ abstract val clauses: List> - override val requiredCommands: Set> = emptySet() override fun getExecutionPath(commands: List>): List> = matchedClauses(commands).flatMap { it.getExecutionPath(commands) } /** Determine which clauses are matched by the supplied commands */ diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/ConcreteClause.kt b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/ConcreteClause.kt deleted file mode 100644 index 65d85a3a85..0000000000 --- a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/ConcreteClause.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.r3corda.core.contracts.clauses - -import com.r3corda.core.contracts.AuthenticatedObject -import com.r3corda.core.contracts.CommandData -import com.r3corda.core.contracts.ContractState - -/** - * Abstract supertype for clauses which provide their own verification logic, rather than delegating to subclauses. - * By default these clauses are always matched (they have no required commands). - * - * @see CompositeClause - */ -abstract class ConcreteClause: Clause { - override fun getExecutionPath(commands: List>): List> - = listOf(this) - override val requiredCommands: Set> = emptySet() -} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/GroupClauseVerifier.kt b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/GroupClauseVerifier.kt index 750233c7f1..d2af7c43cb 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/clauses/GroupClauseVerifier.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/clauses/GroupClauseVerifier.kt @@ -6,7 +6,7 @@ import com.r3corda.core.contracts.ContractState import com.r3corda.core.contracts.TransactionForContract import java.util.* -abstract class GroupClauseVerifier(val clause: Clause) : ConcreteClause() { +abstract class GroupClauseVerifier(val clause: Clause) : Clause() { abstract fun groupStates(tx: TransactionForContract): List> override fun getExecutionPath(commands: List>): List> diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/clauses/ClauseTestUtils.kt b/core/src/test/kotlin/com/r3corda/core/contracts/clauses/ClauseTestUtils.kt index ae8e4618ed..eaded6c2e0 100644 --- a/core/src/test/kotlin/com/r3corda/core/contracts/clauses/ClauseTestUtils.kt +++ b/core/src/test/kotlin/com/r3corda/core/contracts/clauses/ClauseTestUtils.kt @@ -6,7 +6,7 @@ import com.r3corda.core.contracts.ContractState import com.r3corda.core.contracts.TransactionForContract import java.util.concurrent.atomic.AtomicInteger -internal fun matchedClause(counter: AtomicInteger? = null) = object : ConcreteClause() { +internal fun matchedClause(counter: AtomicInteger? = null) = object : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, @@ -17,7 +17,7 @@ internal fun matchedClause(counter: AtomicInteger? = null) = object : ConcreteCl } /** A clause that can never be matched */ -internal fun unmatchedClause(counter: AtomicInteger? = null) = object : ConcreteClause() { +internal fun unmatchedClause(counter: AtomicInteger? = null) = object : Clause() { override val requiredCommands: Set> = setOf(object: CommandData {}.javaClass) override fun verify(tx: TransactionForContract, inputs: List, diff --git a/core/src/test/kotlin/com/r3corda/core/contracts/clauses/VerifyClausesTests.kt b/core/src/test/kotlin/com/r3corda/core/contracts/clauses/VerifyClausesTests.kt index e8b108b980..53a3c267f3 100644 --- a/core/src/test/kotlin/com/r3corda/core/contracts/clauses/VerifyClausesTests.kt +++ b/core/src/test/kotlin/com/r3corda/core/contracts/clauses/VerifyClausesTests.kt @@ -12,7 +12,7 @@ class VerifyClausesTests { /** Very simple check that the function doesn't error when given any clause */ @Test fun minimal() { - val clause = object : ConcreteClause() { + val clause = object : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, @@ -24,7 +24,7 @@ class VerifyClausesTests { @Test fun errorSuperfluousCommands() { - val clause = object : ConcreteClause() { + val clause = object : Clause() { override fun verify(tx: TransactionForContract, inputs: List, outputs: List, diff --git a/docs/source/tutorial-contract-clauses.rst b/docs/source/tutorial-contract-clauses.rst index 325fcc437c..895ff0d964 100644 --- a/docs/source/tutorial-contract-clauses.rst +++ b/docs/source/tutorial-contract-clauses.rst @@ -64,10 +64,10 @@ Clauses ------- We'll tackle the inner clauses that contain the bulk of the verification logic, first, and the clause which handles -grouping of input/output states later. The clauses must implement the ``Clause`` interface, which defines +grouping of input/output states later. The clauses must extend the ``Clause`` abstract class, which defines the ``verify`` function, and the ``requiredCommands`` property used to determine the conditions under which a clause -is triggered. Normally clauses would extend ``ConcreteClause`` which provides defaults suitable for a clause which -verifies transactions, rather than delegating to other clauses. +is triggered. Composite clauses should extend the ``CompositeClause`` abstract class, which extends ``Clause`` to +add support for wrapping around multiple clauses. The ``verify`` function defined in the ``Clause`` interface is similar to the conventional ``Contract`` verification function, although it adds new parameters and returns the set of commands which it has processed. Normally this returned @@ -80,7 +80,7 @@ The ``Move`` clause for the commercial paper contract is relatively simple, so w .. sourcecode:: kotlin - class Move: ConcreteClause>() { + class Move: Clause>() { override val requiredCommands: Set> get() = setOf(Commands.Move::class.java) @@ -103,7 +103,7 @@ The ``Move`` clause for the commercial paper contract is relatively simple, so w .. sourcecode:: java - class Move extends ConcreteClause { + class Move extends Clause { @NotNull @Override public Set> getRequiredCommands() {