mirror of
https://github.com/corda/corda.git
synced 2025-05-28 13:14:24 +00:00
Merged in rnicoll-clause-default (pull request #290)
Add default values for ifMatched/ifNotMatched/requiredCommands
This commit is contained in:
commit
88da5ba942
@ -517,11 +517,7 @@ class InterestRateSwap() : Contract {
|
|||||||
override val clauses = listOf(Agree(), Fix(), Pay(), Mature())
|
override val clauses = listOf(Agree(), Fix(), Pay(), Mature())
|
||||||
}
|
}
|
||||||
|
|
||||||
class Timestamped : SingleClause {
|
class Timestamped : SingleClause() {
|
||||||
override val ifMatched = MatchBehaviour.CONTINUE
|
|
||||||
override val ifNotMatched = MatchBehaviour.ERROR
|
|
||||||
override val requiredCommands = emptySet<Class<out CommandData>>()
|
|
||||||
|
|
||||||
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> {
|
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> {
|
||||||
require(tx.timestamp?.midpoint != null) { "must be timestamped" }
|
require(tx.timestamp?.midpoint != null) { "must be timestamped" }
|
||||||
// We return an empty set because we don't process any commands
|
// We return an empty set because we don't process any commands
|
||||||
|
@ -197,11 +197,7 @@ class Obligation<P> : Contract {
|
|||||||
* any lifecycle change clause, which is the only clause that involve
|
* any lifecycle change clause, which is the only clause that involve
|
||||||
* non-standard lifecycle states on input/output.
|
* non-standard lifecycle states on input/output.
|
||||||
*/
|
*/
|
||||||
class VerifyLifecycle<P> : SingleClause, GroupClause<State<P>, Issued<Terms<P>>> {
|
class VerifyLifecycle<P> : SingleClause(), GroupClause<State<P>, Issued<Terms<P>>> {
|
||||||
override val requiredCommands: Set<Class<out CommandData>> = emptySet()
|
|
||||||
override val ifMatched: MatchBehaviour = MatchBehaviour.CONTINUE
|
|
||||||
override val ifNotMatched: MatchBehaviour = MatchBehaviour.ERROR
|
|
||||||
|
|
||||||
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData>
|
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData>
|
||||||
= verify(
|
= verify(
|
||||||
tx.inputs.filterIsInstance<State<P>>(),
|
tx.inputs.filterIsInstance<State<P>>(),
|
||||||
|
@ -43,13 +43,10 @@ data class MultilateralNetState<P>(
|
|||||||
* Clause for netting contract states. Currently only supports obligation contract.
|
* Clause for netting contract states. Currently only supports obligation contract.
|
||||||
*/
|
*/
|
||||||
// TODO: Make this usable for any nettable contract states
|
// TODO: Make this usable for any nettable contract states
|
||||||
open class NetClause<P> : SingleClause {
|
open class NetClause<P> : SingleClause() {
|
||||||
override val ifNotMatched: MatchBehaviour
|
override val ifMatched: MatchBehaviour = MatchBehaviour.END
|
||||||
get() = MatchBehaviour.CONTINUE
|
override val ifNotMatched: MatchBehaviour = MatchBehaviour.CONTINUE
|
||||||
override val ifMatched: MatchBehaviour
|
override val requiredCommands: Set<Class<out CommandData>> = setOf(Obligation.Commands.Net::class.java)
|
||||||
get() = MatchBehaviour.END
|
|
||||||
override val requiredCommands: Set<Class<out CommandData>>
|
|
||||||
get() = setOf(Obligation.Commands.Net::class.java)
|
|
||||||
|
|
||||||
@Suppress("ConvertLambdaToReference")
|
@Suppress("ConvertLambdaToReference")
|
||||||
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> {
|
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> {
|
||||||
|
@ -218,11 +218,7 @@ interface LinearState: ContractState {
|
|||||||
/**
|
/**
|
||||||
* Standard clause to verify the LinearState safety properties.
|
* Standard clause to verify the LinearState safety properties.
|
||||||
*/
|
*/
|
||||||
class ClauseVerifier<S: LinearState>(val stateClass: Class<S>) : SingleClause {
|
class ClauseVerifier<S: LinearState>(val stateClass: Class<S>) : SingleClause() {
|
||||||
override val ifMatched = MatchBehaviour.CONTINUE
|
|
||||||
override val ifNotMatched = MatchBehaviour.ERROR
|
|
||||||
override val requiredCommands = emptySet<Class<out CommandData>>()
|
|
||||||
|
|
||||||
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> {
|
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> {
|
||||||
val inputs = tx.inputs.filterIsInstance(stateClass)
|
val inputs = tx.inputs.filterIsInstance(stateClass)
|
||||||
val inputIds = inputs.map { it.linearId }.distinct()
|
val inputIds = inputs.map { it.linearId }.distinct()
|
||||||
|
@ -41,4 +41,12 @@ interface SingleVerify {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SingleClause : Clause, SingleVerify
|
/**
|
||||||
|
* A single verifiable clause. By default always matches, continues to the next clause when matched and errors
|
||||||
|
* if not matched.
|
||||||
|
*/
|
||||||
|
abstract class SingleClause : Clause, SingleVerify {
|
||||||
|
override val ifMatched: MatchBehaviour = MatchBehaviour.CONTINUE
|
||||||
|
override val ifNotMatched: MatchBehaviour = MatchBehaviour.ERROR
|
||||||
|
override val requiredCommands: Set<Class<out CommandData>> = emptySet()
|
||||||
|
}
|
@ -27,7 +27,7 @@ fun verifyClauses(tx: TransactionForContract,
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (matchBehaviour) {
|
when (matchBehaviour) {
|
||||||
MatchBehaviour.ERROR -> throw IllegalStateException()
|
MatchBehaviour.ERROR -> throw IllegalStateException("Error due to matching/not matching ${clause}")
|
||||||
MatchBehaviour.CONTINUE -> {
|
MatchBehaviour.CONTINUE -> {
|
||||||
}
|
}
|
||||||
MatchBehaviour.END -> break@verify
|
MatchBehaviour.END -> break@verify
|
||||||
|
@ -21,7 +21,7 @@ interface GroupVerify<in S, in T : Any> {
|
|||||||
|
|
||||||
interface GroupClause<in S : ContractState, in T : Any> : Clause, GroupVerify<S, T>
|
interface GroupClause<in S : ContractState, in T : Any> : Clause, GroupVerify<S, T>
|
||||||
|
|
||||||
abstract class GroupClauseVerifier<S : ContractState, T : Any> : SingleClause {
|
abstract class GroupClauseVerifier<S : ContractState, T : Any> : SingleClause() {
|
||||||
abstract val clauses: List<GroupClause<S, T>>
|
abstract val clauses: List<GroupClause<S, T>>
|
||||||
override val requiredCommands: Set<Class<out CommandData>>
|
override val requiredCommands: Set<Class<out CommandData>>
|
||||||
get() = emptySet()
|
get() = emptySet()
|
||||||
|
@ -9,10 +9,10 @@ import java.util.*
|
|||||||
* A clause which intercepts calls to a wrapped clause, and passes them through verification
|
* A clause which intercepts calls to a wrapped clause, and passes them through verification
|
||||||
* only from a pre-clause. This is similar to an inceptor in aspect orientated programming.
|
* only from a pre-clause. This is similar to an inceptor in aspect orientated programming.
|
||||||
*/
|
*/
|
||||||
data class InterceptorClause(
|
class InterceptorClause(
|
||||||
val preclause: SingleVerify,
|
val preclause: SingleVerify,
|
||||||
val clause: SingleClause
|
val clause: SingleClause
|
||||||
) : SingleClause {
|
) : SingleClause() {
|
||||||
override val ifNotMatched: MatchBehaviour
|
override val ifNotMatched: MatchBehaviour
|
||||||
get() = clause.ifNotMatched
|
get() = clause.ifNotMatched
|
||||||
override val ifMatched: MatchBehaviour
|
override val ifMatched: MatchBehaviour
|
||||||
@ -25,4 +25,6 @@ data class InterceptorClause(
|
|||||||
consumed.addAll(clause.verify(tx, commands))
|
consumed.addAll(clause.verify(tx, commands))
|
||||||
return consumed
|
return consumed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString(): String = "Interceptor clause [${clause}]"
|
||||||
}
|
}
|
@ -19,11 +19,7 @@ class VerifyClausesTests {
|
|||||||
/** Very simple check that the function doesn't error when given any clause */
|
/** Very simple check that the function doesn't error when given any clause */
|
||||||
@Test
|
@Test
|
||||||
fun minimal() {
|
fun minimal() {
|
||||||
val clause = object : SingleClause {
|
val clause = object : SingleClause() {
|
||||||
override val requiredCommands: Set<Class<out CommandData>>
|
|
||||||
get() = emptySet()
|
|
||||||
override val ifMatched: MatchBehaviour
|
|
||||||
get() = MatchBehaviour.CONTINUE
|
|
||||||
override val ifNotMatched: MatchBehaviour
|
override val ifNotMatched: MatchBehaviour
|
||||||
get() = MatchBehaviour.CONTINUE
|
get() = MatchBehaviour.CONTINUE
|
||||||
|
|
||||||
@ -36,14 +32,7 @@ class VerifyClausesTests {
|
|||||||
/** Check that when there are no required commands, a clause always matches */
|
/** Check that when there are no required commands, a clause always matches */
|
||||||
@Test
|
@Test
|
||||||
fun emptyAlwaysMatches() {
|
fun emptyAlwaysMatches() {
|
||||||
val clause = object : SingleClause {
|
val clause = object : SingleClause() {
|
||||||
override val requiredCommands: Set<Class<out CommandData>>
|
|
||||||
get() = emptySet()
|
|
||||||
override val ifMatched: MatchBehaviour
|
|
||||||
get() = MatchBehaviour.CONTINUE
|
|
||||||
override val ifNotMatched: MatchBehaviour
|
|
||||||
get() = MatchBehaviour.ERROR
|
|
||||||
|
|
||||||
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> = emptySet()
|
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> = emptySet()
|
||||||
}
|
}
|
||||||
val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
|
val tx = TransactionForContract(emptyList(), emptyList(), emptyList(), emptyList(), SecureHash.randomSHA256())
|
||||||
@ -53,9 +42,7 @@ class VerifyClausesTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun errorSuperfluousCommands() {
|
fun errorSuperfluousCommands() {
|
||||||
val clause = object : SingleClause {
|
val clause = object : SingleClause() {
|
||||||
override val requiredCommands: Set<Class<out CommandData>>
|
|
||||||
get() = emptySet()
|
|
||||||
override val ifMatched: MatchBehaviour
|
override val ifMatched: MatchBehaviour
|
||||||
get() = MatchBehaviour.ERROR
|
get() = MatchBehaviour.ERROR
|
||||||
override val ifNotMatched: MatchBehaviour
|
override val ifNotMatched: MatchBehaviour
|
||||||
@ -73,7 +60,7 @@ class VerifyClausesTests {
|
|||||||
/** Check triggering of error if matched */
|
/** Check triggering of error if matched */
|
||||||
@Test
|
@Test
|
||||||
fun errorMatched() {
|
fun errorMatched() {
|
||||||
val clause = object : SingleClause {
|
val clause = object : SingleClause() {
|
||||||
override val requiredCommands: Set<Class<out CommandData>>
|
override val requiredCommands: Set<Class<out CommandData>>
|
||||||
get() = setOf(DummyContract.Commands.Create::class.java)
|
get() = setOf(DummyContract.Commands.Create::class.java)
|
||||||
override val ifMatched: MatchBehaviour
|
override val ifMatched: MatchBehaviour
|
||||||
@ -98,13 +85,9 @@ class VerifyClausesTests {
|
|||||||
/** Check triggering of error if unmatched */
|
/** Check triggering of error if unmatched */
|
||||||
@Test
|
@Test
|
||||||
fun errorUnmatched() {
|
fun errorUnmatched() {
|
||||||
val clause = object : SingleClause {
|
val clause = object : SingleClause() {
|
||||||
override val requiredCommands: Set<Class<out CommandData>>
|
override val requiredCommands: Set<Class<out CommandData>>
|
||||||
get() = setOf(DummyContract.Commands.Create::class.java)
|
get() = setOf(DummyContract.Commands.Create::class.java)
|
||||||
override val ifMatched: MatchBehaviour
|
|
||||||
get() = MatchBehaviour.CONTINUE
|
|
||||||
override val ifNotMatched: MatchBehaviour
|
|
||||||
get() = MatchBehaviour.ERROR
|
|
||||||
|
|
||||||
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> = emptySet()
|
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> = emptySet()
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ API changes:
|
|||||||
* The ``arg`` method in the test DSL is now called ``command`` to be consistent with the rest of the data model.
|
* The ``arg`` method in the test DSL is now called ``command`` to be consistent with the rest of the data model.
|
||||||
* The messaging APIs have changed somewhat to now use a new ``TopicSession`` object. These APIs will continue to change
|
* The messaging APIs have changed somewhat to now use a new ``TopicSession`` object. These APIs will continue to change
|
||||||
in the upcoming releases.
|
in the upcoming releases.
|
||||||
|
* Clauses now have default values provided for ``ifMatched``, ``ifNotMatched`` and ``requiredCommands``.
|
||||||
|
|
||||||
New documentation:
|
New documentation:
|
||||||
|
|
||||||
|
@ -16,13 +16,13 @@ generally the same for all fungible contracts, so a single issuance clause can b
|
|||||||
error, and improves consistency of behaviour.
|
error, and improves consistency of behaviour.
|
||||||
|
|
||||||
Clauses can be composed of subclauses, either to combine clauses in different ways, or to apply specialised clauses.
|
Clauses can be composed of subclauses, either to combine clauses in different ways, or to apply specialised clauses.
|
||||||
In the case of commercial paper, we have a "Grouping" outermost clause, which will contain the "Issue", "Move" and
|
In the case of commercial paper, we have a ``Group`` outermost clause, which will contain the ``Issue``, ``Move`` and
|
||||||
"Redeem" clauses. The result is a contract that looks something like this:
|
``Redeem`` clauses. The result is a contract that looks something like this:
|
||||||
|
|
||||||
1. Group input and output states together, and then apply the following clauses on each group:
|
1. Group input and output states together, and then apply the following clauses on each group:
|
||||||
a. If an Issue command is present, run appropriate tests and end processing this group.
|
a. If an ``Issue`` command is present, run appropriate tests and end processing this group.
|
||||||
b. If a Move command is present, run appropriate tests and end processing this group.
|
b. If a ``Move`` command is present, run appropriate tests and end processing this group.
|
||||||
c. If a Redeem command is present, run appropriate tests and end processing this group.
|
c. If a ``Redeem`` command is present, run appropriate tests and end processing this group.
|
||||||
|
|
||||||
Commercial paper class
|
Commercial paper class
|
||||||
----------------------
|
----------------------
|
||||||
@ -71,9 +71,9 @@ Clauses
|
|||||||
|
|
||||||
We'll tackle the inner clauses that contain the bulk of the verification logic, first, and the clause which handles
|
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 inner clauses need to implement the ``GroupClause`` interface, which defines
|
grouping of input/output states later. The inner clauses need to implement the ``GroupClause`` interface, which defines
|
||||||
the verify() function, and properties for key information on how the clause is processed. These properties specify the
|
the verify() function, and properties (``ifMatched``, ``ifNotMatched`` and ``requiredCommands``) defining how the clause
|
||||||
command(s) which must be present in order for the clause to be matched, and what to do after processing the clause
|
is processed. These properties specify the command(s) which must be present in order for the clause to be matched,
|
||||||
depending on whether it was matched or not.
|
and what to do after processing the clause depending on whether it was matched or not.
|
||||||
|
|
||||||
The ``verify()`` functions defined in the ``SingleClause`` and ``GroupClause`` interfaces is similar to the conventional
|
The ``verify()`` functions defined in the ``SingleClause`` and ``GroupClause`` interfaces is similar to the conventional
|
||||||
``Contract`` verification function, although it adds new parameters and returns the set of commands which it has processed.
|
``Contract`` verification function, although it adds new parameters and returns the set of commands which it has processed.
|
||||||
@ -157,7 +157,9 @@ The post-processing ``MatchBehaviour`` options are:
|
|||||||
* ERROR
|
* ERROR
|
||||||
|
|
||||||
In this case we process commands against each group, until the first matching clause is found, so we ``END`` on a match
|
In this case we process commands against each group, until the first matching clause is found, so we ``END`` on a match
|
||||||
and ``CONTINUE`` otherwise. ``ERROR`` can be used as a part of a clause which must always/never be matched.
|
and ``CONTINUE`` otherwise. ``ERROR`` can be used as a part of a clause which must always/never be matched. By default
|
||||||
|
clauses are always matched (``requiredCommands`` is an empty set), execution continues after a clause is matched, and an
|
||||||
|
error is raised if a clause is not matched.
|
||||||
|
|
||||||
Group Clause
|
Group Clause
|
||||||
------------
|
------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user