mirror of
https://github.com/corda/corda.git
synced 2025-06-18 15:18:16 +00:00
Change how clause verification is called
Change away from extending ClauseVerifier for contracts which support clauses, and explicitely call clause verification code in the verify() function. This should make the flow of control easier to understand.
This commit is contained in:
@ -0,0 +1,44 @@
|
||||
package com.r3corda.core.contracts.clauses
|
||||
|
||||
import com.r3corda.core.contracts.AuthenticatedObject
|
||||
import com.r3corda.core.contracts.CommandData
|
||||
import com.r3corda.core.contracts.TransactionForContract
|
||||
|
||||
/**
|
||||
* A clause that can be matched as part of execution of a contract.
|
||||
*/
|
||||
// TODO: ifNotMatched/ifMatched should be dropped, and replaced by logic in the calling code that understands
|
||||
// "or", "and", "single" etc. composition of sets of clauses.
|
||||
interface Clause {
|
||||
/** Classes for commands which must ALL be present in transaction for this clause to be triggered */
|
||||
val requiredCommands: Set<Class<out CommandData>>
|
||||
/** Behaviour if this clause is matched */
|
||||
val ifNotMatched: MatchBehaviour
|
||||
/** Behaviour if this clause is not matches */
|
||||
val ifMatched: MatchBehaviour
|
||||
}
|
||||
|
||||
enum class MatchBehaviour {
|
||||
CONTINUE,
|
||||
END,
|
||||
ERROR
|
||||
}
|
||||
|
||||
interface SingleVerify {
|
||||
/**
|
||||
* Verify the transaction matches the conditions from this clause. For example, a "no zero amount output" clause
|
||||
* would check each of the output states that it applies to, looking for a zero amount, and throw IllegalStateException
|
||||
* if any matched.
|
||||
*
|
||||
* @return the set of commands that are consumed IF this clause is matched, and cannot be used to match a
|
||||
* later clause. This would normally be all commands matching "requiredCommands" for this clause, but some
|
||||
* verify() functions may do further filtering on possible matches, and return a subset. This may also include
|
||||
* commands that were not required (for example the Exit command for fungible assets is optional).
|
||||
*/
|
||||
@Throws(IllegalStateException::class)
|
||||
fun verify(tx: TransactionForContract,
|
||||
commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData>
|
||||
|
||||
}
|
||||
|
||||
interface SingleClause : Clause, SingleVerify
|
@ -1,64 +1,10 @@
|
||||
@file:JvmName("ClauseVerifier")
|
||||
package com.r3corda.core.contracts.clauses
|
||||
|
||||
import com.r3corda.core.contracts.*
|
||||
import java.util.*
|
||||
|
||||
interface Clause {
|
||||
/** Classes for commands which must ALL be present in transaction for this clause to be triggered */
|
||||
val requiredCommands: Set<Class<out CommandData>>
|
||||
/** Behaviour if this clause is matched */
|
||||
val ifNotMatched: MatchBehaviour
|
||||
/** Behaviour if this clause is not matches */
|
||||
val ifMatched: MatchBehaviour
|
||||
}
|
||||
|
||||
enum class MatchBehaviour {
|
||||
CONTINUE,
|
||||
END,
|
||||
ERROR
|
||||
}
|
||||
|
||||
interface SingleVerify {
|
||||
/**
|
||||
* Verify the transaction matches the conditions from this clause. For example, a "no zero amount output" clause
|
||||
* would check each of the output states that it applies to, looking for a zero amount, and throw IllegalStateException
|
||||
* if any matched.
|
||||
*
|
||||
* @return the set of commands that are consumed IF this clause is matched, and cannot be used to match a
|
||||
* later clause. This would normally be all commands matching "requiredCommands" for this clause, but some
|
||||
* verify() functions may do further filtering on possible matches, and return a subset. This may also include
|
||||
* commands that were not required (for example the Exit command for fungible assets is optional).
|
||||
*/
|
||||
@Throws(IllegalStateException::class)
|
||||
fun verify(tx: TransactionForContract,
|
||||
commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData>
|
||||
|
||||
}
|
||||
|
||||
|
||||
interface SingleClause : Clause, SingleVerify
|
||||
|
||||
/**
|
||||
* Abstract superclass for clause-based contracts to extend, which provides a verify() function
|
||||
* that delegates to the supplied list of clauses.
|
||||
*/
|
||||
abstract class ClauseVerifier : Contract {
|
||||
abstract val clauses: List<SingleClause>
|
||||
abstract fun extractCommands(tx: TransactionForContract): Collection<AuthenticatedObject<CommandData>>
|
||||
override fun verify(tx: TransactionForContract) = verifyClauses(tx, clauses, extractCommands(tx))
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a transaction against the given list of clauses.
|
||||
*
|
||||
* @param tx transaction to be verified.
|
||||
* @param clauses the clauses to verify.
|
||||
* @param T common supertype of commands to extract from the transaction, which are of relevance to these clauses.
|
||||
*/
|
||||
inline fun <reified T : CommandData> verifyClauses(tx: TransactionForContract,
|
||||
clauses: List<SingleClause>)
|
||||
= verifyClauses(tx, clauses, tx.commands.select<T>())
|
||||
|
||||
// Wrapper object for exposing a JVM friend version of the clause verifier
|
||||
/**
|
||||
* Verify a transaction against the given list of clauses.
|
||||
*
|
||||
@ -89,4 +35,5 @@ fun verifyClauses(tx: TransactionForContract,
|
||||
}
|
||||
|
||||
require(unmatchedCommands.isEmpty()) { "All commands must be matched at end of execution." }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,10 +26,10 @@ abstract class GroupClauseVerifier<S : ContractState, T : Any> : SingleClause {
|
||||
override val requiredCommands: Set<Class<out CommandData>>
|
||||
get() = emptySet()
|
||||
|
||||
abstract fun extractGroups(tx: TransactionForContract): List<TransactionForContract.InOutGroup<S, T>>
|
||||
abstract fun groupStates(tx: TransactionForContract): List<TransactionForContract.InOutGroup<S, T>>
|
||||
|
||||
override fun verify(tx: TransactionForContract, commands: Collection<AuthenticatedObject<CommandData>>): Set<CommandData> {
|
||||
val groups = extractGroups(tx)
|
||||
val groups = groupStates(tx)
|
||||
val matchedCommands = HashSet<CommandData>()
|
||||
val unmatchedCommands = ArrayList(commands.map { it.value })
|
||||
|
||||
|
Reference in New Issue
Block a user