diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -258,12 +258,12 @@ } // extract and validate TXID - std::string strTxid = vStrInputParts[0]; - if ((strTxid.size() != 64) || !IsHex(strTxid)) { + uint256 hash; + if (!ParseHashStr(vStrInputParts[0], hash)) { throw std::runtime_error("invalid TX input txid"); } - TxId txid(uint256S(strTxid)); + TxId txid(hash); static const unsigned int minTxOutSz = 9; static const unsigned int maxVout = MAX_TX_SIZE / minTxOutSz; @@ -631,7 +631,13 @@ throw std::runtime_error("prevtxs internal object typecheck fail"); } - TxId txid(ParseHashStr(prevOut["txid"].get_str(), "txid")); + uint256 hash; + if (!ParseHashStr(prevOut["txid"].get_str(), hash)) { + throw std::runtime_error("txid must be hexadecimal string (not '" + + prevOut["txid"].get_str() + "')"); + } + + TxId txid(hash); const int nOut = prevOut["vout"].get_int(); if (nOut < 0) { diff --git a/src/core_io.h b/src/core_io.h --- a/src/core_io.h +++ b/src/core_io.h @@ -29,7 +29,16 @@ const std::string &strHexTx); NODISCARD bool DecodeHexBlk(CBlock &, const std::string &strHexBlk); bool DecodeHexBlockHeader(CBlockHeader &, const std::string &hex_header); -uint256 ParseHashStr(const std::string &, const std::string &strName); + +/** + * Parse a hex string into 256 bits + * @param[in] strHex a hex-formatted, 64-character string + * @param[out] result the result of the parasing + * @returns true if successful, false if not + * + * @see ParseHashV for an RPC-oriented version of this + */ +bool ParseHashStr(const std::string &strHex, uint256 &result); std::vector ParseHexUV(const UniValue &v, const std::string &strName); NODISCARD bool DecodePSBT(PartiallySignedTransaction &psbt, const std::string &base64_tx, std::string &error); diff --git a/src/core_read.cpp b/src/core_read.cpp --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -245,16 +245,13 @@ return true; } -uint256 ParseHashStr(const std::string &strHex, const std::string &strName) { - if (!IsHex(strHex)) { - // Note: IsHex("") is false - throw std::runtime_error( - strName + " must be hexadecimal string (not '" + strHex + "')"); +bool ParseHashStr(const std::string &strHex, uint256 &result) { + if ((strHex.size() != 64) || !IsHex(strHex)) { + return false; } - uint256 result; result.SetHex(strHex); - return result; + return true; } std::vector ParseHexUV(const UniValue &v, const std::string &strName) { diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -110,15 +110,6 @@ return formats; } -static bool ParseHashStr(const std::string &strReq, uint256 &v) { - if (!IsHex(strReq) || (strReq.size() != 64)) { - return false; - } - - v.SetHex(strReq); - return true; -} - static bool CheckWarmup(HTTPRequest *req) { std::string statusmessage; if (RPCIsInWarmup(&statusmessage)) { diff --git a/src/test/blockfilter_tests.cpp b/src/test/blockfilter_tests.cpp --- a/src/test/blockfilter_tests.cpp +++ b/src/test/blockfilter_tests.cpp @@ -155,8 +155,8 @@ size_t pos = 0; /*int block_height =*/test[pos++].get_int(); - /*uint256 block_hash =*/ParseHashStr(test[pos++].get_str(), - "block_hash"); + uint256 block_hash; + BOOST_CHECK(ParseHashStr(test[pos++].get_str(), block_hash)); CBlock block; BOOST_REQUIRE(DecodeHexBlk(block, test[pos++].get_str())); @@ -173,11 +173,12 @@ tx_undo.vprevout.emplace_back(txout, 0, false); } - uint256 prev_filter_header_basic = - ParseHashStr(test[pos++].get_str(), "prev_filter_header_basic"); + uint256 prev_filter_header_basic; + BOOST_CHECK( + ParseHashStr(test[pos++].get_str(), prev_filter_header_basic)); std::vector filter_basic = ParseHex(test[pos++].get_str()); - uint256 filter_header_basic = - ParseHashStr(test[pos++].get_str(), "filter_header_basic"); + uint256 filter_header_basic; + BOOST_CHECK(ParseHashStr(test[pos++].get_str(), filter_header_basic)); BlockFilter computed_filter_basic(BlockFilterType::BASIC, block, block_undo); diff --git a/test/util/data/bitcoin-util-test.json b/test/util/data/bitcoin-util-test.json --- a/test/util/data/bitcoin-util-test.json +++ b/test/util/data/bitcoin-util-test.json @@ -102,6 +102,30 @@ "error_txt": "error: Invalid TX locktime requested", "description": "Tests the check for invalid locktime value" }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=Z897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid invalid hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid valid hex but too short" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f12:0"], + "return_code": 1, + "error_txt": "error: invalid TX input txid", + "description": "Tests the check for an invalid txid valid hex but too long" + }, { "exec": "./bitcoin-tx", "args": ["-create", @@ -251,6 +275,42 @@ "error_txt": "error: prevtxs internal object typecheck fail", "description": "Tests the check for invalid vout index in prevtxs for sign" }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"Zd49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59412\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not 'Zd49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59412')", + "description": "Tests the check for invalid txid due to invalid hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc594\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not '4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc594')", + "description": "Tests the check for invalid txid valid hex, but too short" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc5948512\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "return_code": 1, + "error_txt": "error: txid must be hexadecimal string (not '4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc5948512')", + "description": "Tests the check for invalid txid valid hex, but too long" + }, { "exec": "./bitcoin-tx", "args": ["-create", "outpubkey=0:02a5613bd857b7048924264d1e70e08fb2a7e6527d32b7ab1bb993ac59964ff397", "nversion=1"],