Minor transaction verification logic refactoring

This commit is contained in:
Andrius Dagys 2016-12-01 12:05:32 +00:00
parent 053dd9a1fe
commit cef2c906ab

View File

@ -49,15 +49,20 @@ sealed class TransactionType {
/** Just uses the default [TransactionBuilder] with no special logic */
class Builder(notary: Party?) : TransactionBuilder(General(), notary) {}
/**
* Check the transaction is contract-valid by running the verify() for each input and output state contract.
* If any contract fails to verify, the whole transaction is considered to be invalid.
*/
override fun verifyTransaction(tx: LedgerTransaction) {
// Make sure the notary has stayed the same. As we can't tell how inputs and outputs connect, if there
// are any inputs, all outputs must have the same notary.
// TODO: Is that the correct set of restrictions? May need to come back to this, see if we can be more
// flexible on output notaries.
verifyNoNotaryChange(tx)
verifyEncumbrances(tx)
verifyContracts(tx)
}
/**
* Make sure the notary has stayed the same. As we can't tell how inputs and outputs connect, if there
* are any inputs, all outputs must have the same notary.
*
* TODO: Is that the correct set of restrictions? May need to come back to this, see if we can be more
* flexible on output notaries.
*/
private fun verifyNoNotaryChange(tx: LedgerTransaction) {
if (tx.notary != null && tx.inputs.isNotEmpty()) {
tx.outputs.forEach {
if (it.notary != tx.notary) {
@ -65,25 +70,16 @@ sealed class TransactionType {
}
}
}
}
val ctx = tx.toTransactionForContract()
// TODO: This will all be replaced in future once the sandbox and contract constraints work is done.
val contracts = (ctx.inputs.map { it.contract } + ctx.outputs.map { it.contract }).toSet()
for (contract in contracts) {
try {
contract.verify(ctx)
} catch(e: Throwable) {
throw TransactionVerificationException.ContractRejection(tx, contract, e)
}
}
private fun verifyEncumbrances(tx: LedgerTransaction) {
// Validate that all encumbrances exist within the set of input states.
tx.inputs.filter { it.state.data.encumbrance != null }.forEach { encumberedInput ->
val isMissing = tx.inputs.none {
val encumberedInputs = tx.inputs.filter { it.state.data.encumbrance != null }
encumberedInputs.forEach { encumberedInput ->
val encumbranceStateExists = tx.inputs.any {
it.ref.txhash == encumberedInput.ref.txhash && it.ref.index == encumberedInput.state.data.encumbrance
}
if (isMissing) {
if (!encumbranceStateExists) {
throw TransactionVerificationException.TransactionMissingEncumbranceException(
tx, encumberedInput.state.data.encumbrance!!,
TransactionVerificationException.Direction.INPUT
@ -103,6 +99,23 @@ sealed class TransactionType {
}
}
/**
* Check the transaction is contract-valid by running the verify() for each input and output state contract.
* If any contract fails to verify, the whole transaction is considered to be invalid.
*/
private fun verifyContracts(tx: LedgerTransaction) {
val ctx = tx.toTransactionForContract()
// TODO: This will all be replaced in future once the sandbox and contract constraints work is done.
val contracts = (ctx.inputs.map { it.contract } + ctx.outputs.map { it.contract }).toSet()
for (contract in contracts) {
try {
contract.verify(ctx)
} catch(e: Throwable) {
throw TransactionVerificationException.ContractRejection(tx, contract, e)
}
}
}
override fun getRequiredSigners(tx: LedgerTransaction) = tx.commands.flatMap { it.signers }.toSet()
}