Merge pull request #12 from corda/andrius-txverify-refactor

This commit is contained in:
Andrius Dagys 2016-12-01 13:54:59 +00:00 committed by GitHub
commit 84c127bfff

View File

@ -49,15 +49,20 @@ sealed class TransactionType {
/** Just uses the default [TransactionBuilder] with no special logic */ /** Just uses the default [TransactionBuilder] with no special logic */
class Builder(notary: Party?) : TransactionBuilder(General(), notary) {} 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) { 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 verifyNoNotaryChange(tx)
// are any inputs, all outputs must have the same notary. verifyEncumbrances(tx)
// TODO: Is that the correct set of restrictions? May need to come back to this, see if we can be more verifyContracts(tx)
// flexible on output notaries. }
/**
* 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()) { if (tx.notary != null && tx.inputs.isNotEmpty()) {
tx.outputs.forEach { tx.outputs.forEach {
if (it.notary != tx.notary) { if (it.notary != tx.notary) {
@ -65,25 +70,16 @@ sealed class TransactionType {
} }
} }
} }
}
val ctx = tx.toTransactionForContract() private fun verifyEncumbrances(tx: LedgerTransaction) {
// 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)
}
}
// Validate that all encumbrances exist within the set of input states. // Validate that all encumbrances exist within the set of input states.
tx.inputs.filter { it.state.data.encumbrance != null }.forEach { encumberedInput -> val encumberedInputs = tx.inputs.filter { it.state.data.encumbrance != null }
val isMissing = tx.inputs.none { encumberedInputs.forEach { encumberedInput ->
val encumbranceStateExists = tx.inputs.any {
it.ref.txhash == encumberedInput.ref.txhash && it.ref.index == encumberedInput.state.data.encumbrance it.ref.txhash == encumberedInput.ref.txhash && it.ref.index == encumberedInput.state.data.encumbrance
} }
if (isMissing) { if (!encumbranceStateExists) {
throw TransactionVerificationException.TransactionMissingEncumbranceException( throw TransactionVerificationException.TransactionMissingEncumbranceException(
tx, encumberedInput.state.data.encumbrance!!, tx, encumberedInput.state.data.encumbrance!!,
TransactionVerificationException.Direction.INPUT 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() override fun getRequiredSigners(tx: LedgerTransaction) = tx.commands.flatMap { it.signers }.toSet()
} }