diff --git a/error.go b/error.go index 26071c97..94a5e8ae 100644 --- a/error.go +++ b/error.go @@ -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. diff --git a/error_test.go b/error_test.go index d1801d8f..37bfade8 100644 --- a/error_test.go +++ b/error_test.go @@ -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)"}, } diff --git a/scriptval.go b/scriptval.go index f3badf19..1e300eba 100644 --- a/scriptval.go +++ b/scriptval.go @@ -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 }