Consolidate redundant implementations of ParseHashStr

This change:
* adds a length check to ParseHashStr, appropriate given its use to populate
  a 256-bit number from a hex str.
* allows the caller to handle the failure, which allows for the more
  appropriate JSONRPCError on failure in prioritisetransaction rpc
This commit is contained in:
Ben Woosley 2018-09-24 10:59:17 -04:00
parent 990fc0de1a
commit 9c5af58d51
No known key found for this signature in database
GPG key ID: 4D8CA4BA18040906
6 changed files with 87 additions and 22 deletions

View file

@ -240,10 +240,10 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
throw std::runtime_error("TX input missing separator");
// extract and validate TXID
std::string strTxid = vStrInputParts[0];
if ((strTxid.size() != 64) || !IsHex(strTxid))
uint256 txid;
if (!ParseHashStr(vStrInputParts[0], txid)) {
throw std::runtime_error("invalid TX input txid");
uint256 txid(uint256S(strTxid));
}
static const unsigned int minTxOutSz = 9;
static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
@ -590,7 +590,10 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
if (!prevOut.checkObject(types))
throw std::runtime_error("prevtxs internal object typecheck fail");
uint256 txid = ParseHashStr(prevOut["txid"].get_str(), "txid");
uint256 txid;
if (!ParseHashStr(prevOut["txid"].get_str(), txid)) {
throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')");
}
const int nOut = prevOut["vout"].get_int();
if (nOut < 0)

View file

@ -25,7 +25,16 @@ std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDeco
bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true);
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<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error);
int ParseSighashString(const UniValue& sighash);

View file

@ -193,14 +193,13 @@ bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx,
return true;
}
uint256 ParseHashStr(const std::string& strHex, const std::string& strName)
bool ParseHashStr(const std::string& strHex, uint256& result)
{
if (!IsHex(strHex)) // Note: IsHex("") is false
throw std::runtime_error(strName + " must be hexadecimal string (not '" + strHex + "')");
if ((strHex.size() != 64) || !IsHex(strHex))
return false;
uint256 result;
result.SetHex(strHex);
return result;
return true;
}
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName)

View file

@ -105,15 +105,6 @@ static std::string AvailableDataFormatsString()
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;

View file

@ -114,7 +114,8 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test)
unsigned int 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()));
@ -129,9 +130,11 @@ BOOST_AUTO_TEST_CASE(blockfilters_json_test)
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<unsigned char> 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);
BOOST_CHECK(computed_filter_basic.GetFilter().GetEncoded() == filter_basic);

View file

@ -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",
@ -280,6 +304,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"],