Convert script errors to RuleErrors.

This commit modifies the error return type for errors during script
validation to use the RuleError so they are consistent with the rest of
the errors.  This also helps the calling code differentiate blocks
rejected due to script parsing and validation errors as opposed to
internal issues such as inability to read from the disk.

To accomplish this, two new two new RuleErrors, ErrScriptMalformed and
ErrScriptValidation, have been added.

Also, the errors for script parsing issues and script validation errors
have been improved to include both transaction hashes and indexes involved
in the validation effort.  Previously script parsing issues had almost no
additional information as to which transaction input/outputs the failing
script came from.
This commit is contained in:
Dave Collins 2014-06-26 23:29:57 -05:00
parent cf3ad14d4d
commit a22da99f91
3 changed files with 38 additions and 12 deletions

View file

@ -151,6 +151,17 @@ const (
// coinbase transaction for version 2 and higher blocks does not match
// the expected value.
ErrBadCoinbaseHeight
// ErrScriptMalformed indicates a transaction script is malformed in
// some way. For example, it might be longer than the maximum allowed
// length or fail to parse.
ErrScriptMalformed
// ErrScriptValidation indicates the result of executing transaction
// script failed. The error covers any failure when executing scripts
// such signature verification failures and execution past the end of
// the stack.
ErrScriptValidation
)
// Map of ErrorCode values back to their constant names for pretty printing.
@ -187,6 +198,8 @@ var errorCodeStrings = map[ErrorCode]string{
ErrBadCoinbaseValue: "ErrBadCoinbaseValue",
ErrMissingCoinbaseHeight: "ErrMissingCoinbaseHeight",
ErrBadCoinbaseHeight: "ErrBadCoinbaseHeight",
ErrScriptMalformed: "ErrScriptMalformed",
ErrScriptValidation: "ErrScriptValidation",
}
// String returns the ErrorCode as a human-readable name.

View file

@ -48,6 +48,8 @@ func TestErrorCodeStringer(t *testing.T) {
{btcchain.ErrBadCoinbaseValue, "ErrBadCoinbaseValue"},
{btcchain.ErrMissingCoinbaseHeight, "ErrMissingCoinbaseHeight"},
{btcchain.ErrBadCoinbaseHeight, "ErrBadCoinbaseHeight"},
{btcchain.ErrScriptMalformed, "ErrScriptMalformed"},
{btcchain.ErrScriptValidation, "ErrScriptValidation"},
{0xffff, "Unknown ErrorCode (65535)"},
}

View file

@ -51,15 +51,15 @@ out:
select {
case txVI := <-v.validateChan:
// Ensure the referenced input transaction is available.
//txIn := txVI.tx.MsgTx().TxIn[txVI.txInIdx]
txIn := txVI.txIn
txInHash := &txIn.PreviousOutpoint.Hash
originTx, exists := v.txStore[*txInHash]
originTxHash := &txIn.PreviousOutpoint.Hash
originTx, exists := v.txStore[*originTxHash]
if !exists || originTx.Err != nil || originTx.Tx == nil {
err := fmt.Errorf("unable to find input "+
str := fmt.Sprintf("unable to find input "+
"transaction %v referenced from "+
"transaction %v", txInHash,
"transaction %v", originTxHash,
txVI.tx.Sha())
err := ruleError(ErrMissingTx, str)
v.sendResult(err)
break out
}
@ -69,10 +69,12 @@ out:
// is available.
originTxIndex := txIn.PreviousOutpoint.Index
if originTxIndex >= uint32(len(originMsgTx.TxOut)) {
err := fmt.Errorf("out of bounds "+
str := fmt.Sprintf("out of bounds "+
"input index %d in transaction %v "+
"referenced from transaction %v",
originTxIndex, txInHash, txVI.tx.Sha())
originTxIndex, originTxHash,
txVI.tx.Sha())
err := ruleError(ErrBadTxInput, str)
v.sendResult(err)
break out
}
@ -83,17 +85,26 @@ out:
engine, err := btcscript.NewScript(sigScript, pkScript,
txVI.txInIndex, txVI.tx.MsgTx(), v.flags)
if err != nil {
str := fmt.Sprintf("failed to parse input "+
"%s:%d which references output %s:%d - "+
"%v (input script bytes %x, prev output "+
"script bytes %x)", txVI.tx.Sha(),
txVI.txInIndex, originTxHash,
originTxIndex, err, sigScript, pkScript)
err := ruleError(ErrScriptMalformed, str)
v.sendResult(err)
break out
}
// Execute the script pair.
if err := engine.Execute(); err != nil {
err := fmt.Errorf("validate of input "+
"%d from transaction %s failed: %v "+
"(input script bytes %x, prev output "+
"script bytes %x)", txVI.txInIndex,
txInHash, err, sigScript, pkScript)
str := fmt.Sprintf("failed to validate input "+
"%s:%d which references output %s:%d - "+
"%v (input script bytes %x, prev output "+
"script bytes %x)", txVI.tx.Sha(),
txVI.txInIndex, originTxHash,
originTxIndex, err, sigScript, pkScript)
err := ruleError(ErrScriptValidation, str)
v.sendResult(err)
break out
}