Merge ConcreteClause into Clause

Change Clause to an abstract class, and merge ConcreteClause into it. CompositeClause now
overrides defaults provided in Clause which are more suitable for composition of clauses.
This commit is contained in:
Ross Nicoll 2016-08-31 17:40:42 +01:00
parent d81cbebe96
commit 203c4fb3d8
16 changed files with 44 additions and 59 deletions

View File

@ -142,7 +142,7 @@ public class JavaCommercialPaper implements Contract {
}
}
class Move extends ConcreteClause<State, Commands, State> {
class Move extends Clause<State, Commands, State> {
@NotNull
@Override
public Set<Class<? extends CommandData>> getRequiredCommands() {
@ -173,7 +173,7 @@ public class JavaCommercialPaper implements Contract {
}
}
class Redeem extends ConcreteClause<State, Commands, State> {
class Redeem extends Clause<State, Commands, State> {
@NotNull
@Override
public Set<Class<? extends CommandData>> getRequiredCommands() {
@ -215,7 +215,7 @@ public class JavaCommercialPaper implements Contract {
}
}
class Issue extends ConcreteClause<State, Commands, State> {
class Issue extends Clause<State, Commands, State> {
@NotNull
@Override
public Set<Class<? extends CommandData>> getRequiredCommands() {

View File

@ -107,7 +107,7 @@ class CommercialPaper : Contract {
}
}
class Move: ConcreteClause<State, Commands, Issued<Terms>>() {
class Move: Clause<State, Commands, Issued<Terms>>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Commands.Move::class.java)
override fun verify(tx: TransactionForContract,
@ -127,7 +127,7 @@ class CommercialPaper : Contract {
}
}
class Redeem(): ConcreteClause<State, Commands, Issued<Terms>>() {
class Redeem(): Clause<State, Commands, Issued<Terms>>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Commands.Redeem::class.java)
override fun verify(tx: TransactionForContract,

View File

@ -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<State, Commands, UniqueIdentifier>() {
abstract class AbstractIRSClause : Clause<State, Commands, UniqueIdentifier>() {
// These functions may make more sense to use for basket types, but for now let's leave them here
fun checkLegDates(legs: List<CommonLeg>) {
requireThat {
@ -502,7 +502,7 @@ class InterestRateSwap() : Contract {
= tx.groupStates() { state -> state.linearId }
}
class Timestamped : ConcreteClause<ContractState, Commands, Unit>() {
class Timestamped : Clause<ContractState, Commands, Unit>() {
override fun verify(tx: TransactionForContract,
inputs: List<ContractState>,
outputs: List<ContractState>,

View File

@ -90,7 +90,7 @@ class Obligation<P> : Contract {
/**
* Obligation-specific clause for changing the lifecycle of one or more states.
*/
class SetLifecycle<P> : ConcreteClause<State<P>, Commands, Issued<Terms<P>>>() {
class SetLifecycle<P> : Clause<State<P>, Commands, Issued<Terms<P>>>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Commands.SetLifecycle::class.java)
override fun verify(tx: TransactionForContract,
@ -110,7 +110,7 @@ class Obligation<P> : Contract {
* Obligation-specific clause for settling an outstanding obligation by witnessing
* change of ownership of other states to fulfil
*/
class Settle<P> : ConcreteClause<State<P>, Commands, Issued<Terms<P>>>() {
class Settle<P> : Clause<State<P>, Commands, Issued<Terms<P>>>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Commands.Settle::class.java)
override fun verify(tx: TransactionForContract,
inputs: List<State<P>>,
@ -199,7 +199,7 @@ class Obligation<P> : Contract {
* any lifecycle change clause, which is the only clause that involve
* non-standard lifecycle states on input/output.
*/
class VerifyLifecycle<S: ContractState, C: CommandData, T: Any, P> : ConcreteClause<S, C, T>() {
class VerifyLifecycle<S: ContractState, C: CommandData, T: Any, P> : Clause<S, C, T>() {
override fun verify(tx: TransactionForContract,
inputs: List<S>,
outputs: List<S>,

View File

@ -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<S : FungibleAsset<T>, C : CommandData, T : Any> : ConcreteClause<S, C, Issued<T>>() {
abstract class AbstractConserveAmount<S : FungibleAsset<T>, C : CommandData, T : Any> : Clause<S, C, Issued<T>>() {
/**
* Gather assets from the given list of states, sufficient to match or exceed the given amount.
*

View File

@ -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<in S: ContractState, C: CommandData, T: Any>(
val sum: List<S>.() -> Amount<Issued<T>>,
val sumOrZero: List<S>.(token: Issued<T>) -> Amount<Issued<T>>
) : ConcreteClause<S, C, Issued<T>>() {
) : Clause<S, C, Issued<T>>() {
override fun verify(tx: TransactionForContract,
inputs: List<S>,
outputs: List<S>,

View File

@ -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<P>(
* Clause for netting contract states. Currently only supports obligation contract.
*/
// TODO: Make this usable for any nettable contract states
open class NetClause<C: CommandData, P> : ConcreteClause<ContractState, C, Unit>() {
open class NetClause<C: CommandData, P> : Clause<ContractState, C, Unit>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(Obligation.Commands.Net::class.java)
@Suppress("ConvertLambdaToReference")

View File

@ -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<in S : FungibleAsset<T>, C : CommandData, T : Any> : ConcreteClause<S, C, Issued<T>>() {
open class NoZeroSizedOutputs<in S : FungibleAsset<T>, C : CommandData, T : Any> : Clause<S, C, Issued<T>>() {
override fun verify(tx: TransactionForContract,
inputs: List<S>,
outputs: List<S>,

View File

@ -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<S : LinearState>(val stateClass: Class<S>) : ConcreteClause<ContractState, CommandData, Unit>() {
class ClauseVerifier<S : LinearState>(val stateClass: Class<S>) : Clause<ContractState, CommandData, Unit>() {
override fun verify(tx: TransactionForContract,
inputs: List<ContractState>,
outputs: List<ContractState>,

View File

@ -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<in S : ContractState, C: CommandData, in K : Any> {
abstract class Clause<in S : ContractState, C : CommandData, in K : Any> {
companion object {
val log = loggerFor<Clause<*, *, *>>()
}
/** Determine whether this clause runs or not */
val requiredCommands: Set<Class<out CommandData>>
open val requiredCommands: Set<Class<out CommandData>> = emptySet()
/**
* Determine the subclauses which will be verified as a result of verifying this clause.
*/
fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>
open fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>
= 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<in S : ContractState, C: CommandData, in K : Any> {
* commands that were not required (for example the Exit command for fungible assets is optional).
*/
@Throws(IllegalStateException::class)
fun verify(tx: TransactionForContract,
inputs: List<S>,
outputs: List<S>,
commands: List<AuthenticatedObject<C>>,
groupingKey: K?): Set<C>
abstract fun verify(tx: TransactionForContract,
inputs: List<S>,
outputs: List<S>,
commands: List<AuthenticatedObject<C>>,
groupingKey: K?): Set<C>
}
/**

View File

@ -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<in S : ContractState, C: CommandData, in K : Any>: Clause<S, C, K> {
abstract class CompositeClause<in S : ContractState, C: CommandData, in K : Any>: Clause<S, C, K>() {
/** List of clauses under this composite clause */
abstract val clauses: List<Clause<S, C, K>>
override val requiredCommands: Set<Class<out CommandData>> = emptySet()
override fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>
= matchedClauses(commands).flatMap { it.getExecutionPath(commands) }
/** Determine which clauses are matched by the supplied commands */

View File

@ -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<in S : ContractState, C: CommandData, in T : Any>: Clause<S, C, T> {
override fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>
= listOf(this)
override val requiredCommands: Set<Class<out CommandData>> = emptySet()
}

View File

@ -6,7 +6,7 @@ import com.r3corda.core.contracts.ContractState
import com.r3corda.core.contracts.TransactionForContract
import java.util.*
abstract class GroupClauseVerifier<S : ContractState, C : CommandData, K : Any>(val clause: Clause<S, C, K>) : ConcreteClause<ContractState, C, Unit>() {
abstract class GroupClauseVerifier<S : ContractState, C : CommandData, K : Any>(val clause: Clause<S, C, K>) : Clause<ContractState, C, Unit>() {
abstract fun groupStates(tx: TransactionForContract): List<TransactionForContract.InOutGroup<S, K>>
override fun getExecutionPath(commands: List<AuthenticatedObject<C>>): List<Clause<*, *, *>>

View File

@ -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<ContractState, CommandData, Unit>() {
internal fun matchedClause(counter: AtomicInteger? = null) = object : Clause<ContractState, CommandData, Unit>() {
override fun verify(tx: TransactionForContract,
inputs: List<ContractState>,
outputs: List<ContractState>,
@ -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<ContractState, CommandData, Unit>() {
internal fun unmatchedClause(counter: AtomicInteger? = null) = object : Clause<ContractState, CommandData, Unit>() {
override val requiredCommands: Set<Class<out CommandData>> = setOf(object: CommandData {}.javaClass)
override fun verify(tx: TransactionForContract,
inputs: List<ContractState>,

View File

@ -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<ContractState, CommandData, Unit>() {
val clause = object : Clause<ContractState, CommandData, Unit>() {
override fun verify(tx: TransactionForContract,
inputs: List<ContractState>,
outputs: List<ContractState>,
@ -24,7 +24,7 @@ class VerifyClausesTests {
@Test
fun errorSuperfluousCommands() {
val clause = object : ConcreteClause<ContractState, CommandData, Unit>() {
val clause = object : Clause<ContractState, CommandData, Unit>() {
override fun verify(tx: TransactionForContract,
inputs: List<ContractState>,
outputs: List<ContractState>,

View File

@ -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<State, Commands, Issued<Terms>>() {
class Move: Clause<State, Commands, Issued<Terms>>() {
override val requiredCommands: Set<Class<out CommandData>>
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<State, Commands, State> {
class Move extends Clause<State, Commands, State> {
@NotNull
@Override
public Set<Class<? extends CommandData>> getRequiredCommands() {