From 8ac2a4e1788426329b842eea7121b8eac7875c76 Mon Sep 17 00:00:00 2001 From: dexX7 Date: Sun, 22 Mar 2015 19:07:28 +0100 Subject: [PATCH] RPC: show script verification errors in "signrawtransaction" result If there are any script verification errors, when using "signrawtransaction", they are shown in the RPC result: ``` // ... Result: { "hex" : "value", (string) The hex-encoded raw transaction with signature(s) "complete" : true|false, (boolean) If the transaction has a complete set of signatures "errors" : [ (json array of objects) Script verification errors (if there are any) { "txid" : "hash", (string) The hash of the referenced, previous transaction "vout" : n, (numeric) The index of the output to spent and used as input "scriptSig" : "hex", (string) The hex-encoded signature script "sequence" : n, (numeric) Script sequence number "error" : "text" (string) Verification or signing error related to the input } ,... ] } ``` --- src/rpcrawtransaction.cpp | 45 +++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index ca5aba875..e84d2693a 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2015 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -13,6 +13,7 @@ #include "net.h" #include "rpcserver.h" #include "script/script.h" +#include "script/script_error.h" #include "script/sign.h" #include "script/standard.h" #include "uint256.h" @@ -491,6 +492,18 @@ Value decodescript(const Array& params, bool fHelp) return r; } +/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */ +static void TxInErrorToJSON(const CTxIn& txin, Array& vErrorsRet, const std::string& strMessage) +{ + Object entry; + entry.push_back(Pair("txid", txin.prevout.hash.ToString())); + entry.push_back(Pair("vout", (uint64_t)txin.prevout.n)); + entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); + entry.push_back(Pair("sequence", (uint64_t)txin.nSequence)); + entry.push_back(Pair("error", strMessage)); + vErrorsRet.push_back(entry); +} + Value signrawtransaction(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 4) @@ -532,8 +545,18 @@ Value signrawtransaction(const Array& params, bool fHelp) "\nResult:\n" "{\n" - " \"hex\": \"value\", (string) The raw transaction with signature(s) (hex-encoded string)\n" - " \"complete\": true|false (boolean) if transaction has a complete set of signature\n" + " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" + " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" + " \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n" + " {\n" + " \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n" + " \"vout\" : n, (numeric) The index of the output to spent and used as input\n" + " \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n" + " \"sequence\" : n, (numeric) Script sequence number\n" + " \"error\" : \"text\" (string) Verification or signing error related to the input\n" + " }\n" + " ,...\n" + " ]\n" "}\n" "\nExamples:\n" @@ -568,7 +591,6 @@ Value signrawtransaction(const Array& params, bool fHelp) // mergedTx will end up with all the signatures; it // starts as a clone of the rawtx: CMutableTransaction mergedTx(txVariants[0]); - bool fComplete = true; // Fetch previous transactions (inputs): CCoinsView viewDummy; @@ -683,12 +705,15 @@ Value signrawtransaction(const Array& params, bool fHelp) bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + // Script verification errors + Array vErrors; + // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; const CCoins* coins = view.AccessCoins(txin.prevout.hash); if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) { - fComplete = false; + TxInErrorToJSON(txin, vErrors, "Input not found or already spent"); continue; } const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey; @@ -702,13 +727,19 @@ Value signrawtransaction(const Array& params, bool fHelp) BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i))) - fComplete = false; + ScriptError serror = SCRIPT_ERR_OK; + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) { + TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); + } } + bool fComplete = vErrors.empty(); Object result; result.push_back(Pair("hex", EncodeHexTx(mergedTx))); result.push_back(Pair("complete", fComplete)); + if (!vErrors.empty()) { + result.push_back(Pair("errors", vErrors)); + } return result; }