Split DecodePSBT into Base64 and Raw versions

Split up DecodePSBT, which both decodes base64 and then deserializes a
PartiallySignedTransaction, into two functions: DecodeBase64PSBT, which retains
the old behavior, and DecodeRawPSBT, which only performs the deserialization.

Add a test for base64 decoding failure.
This commit is contained in:
Glenn Willen 2019-01-29 21:32:38 -08:00
parent 162ffefd2f
commit c734aaa15d
5 changed files with 25 additions and 8 deletions

View file

@ -37,7 +37,11 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header);
*/ */
bool ParseHashStr(const std::string& strHex, uint256& result); bool ParseHashStr(const std::string& strHex, uint256& result);
std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName); std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName);
NODISCARD bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error);
//! Decode a base64ed PSBT into a PartiallySignedTransaction
NODISCARD bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
NODISCARD bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
int ParseSighashString(const UniValue& sighash); int ParseSighashString(const UniValue& sighash);
// core_write.cpp // core_write.cpp

View file

@ -176,10 +176,20 @@ bool DecodeHexBlk(CBlock& block, const std::string& strHexBlk)
return true; return true;
} }
bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error) bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
{ {
std::vector<unsigned char> tx_data = DecodeBase64(base64_tx.c_str()); bool invalid;
CDataStream ss_data(tx_data, SER_NETWORK, PROTOCOL_VERSION); std::string tx_data = DecodeBase64(base64_tx, &invalid);
if (invalid) {
error = "invalid base64";
return false;
}
return DecodeRawPSBT(psbt, tx_data, error);
}
bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error)
{
CDataStream ss_data(tx_data.data(), tx_data.data() + tx_data.size(), SER_NETWORK, PROTOCOL_VERSION);
try { try {
ss_data >> psbt; ss_data >> psbt;
if (!ss_data.empty()) { if (!ss_data.empty()) {

View file

@ -1323,7 +1323,7 @@ UniValue decodepsbt(const JSONRPCRequest& request)
// Unserialize the transactions // Unserialize the transactions
PartiallySignedTransaction psbtx; PartiallySignedTransaction psbtx;
std::string error; std::string error;
if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) { if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
} }
@ -1524,7 +1524,7 @@ UniValue combinepsbt(const JSONRPCRequest& request)
for (unsigned int i = 0; i < txs.size(); ++i) { for (unsigned int i = 0; i < txs.size(); ++i) {
PartiallySignedTransaction psbtx; PartiallySignedTransaction psbtx;
std::string error; std::string error;
if (!DecodePSBT(psbtx, txs[i].get_str(), error)) { if (!DecodeBase64PSBT(psbtx, txs[i].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
} }
psbtxs.push_back(psbtx); psbtxs.push_back(psbtx);
@ -1581,7 +1581,7 @@ UniValue finalizepsbt(const JSONRPCRequest& request)
// Unserialize the transactions // Unserialize the transactions
PartiallySignedTransaction psbtx; PartiallySignedTransaction psbtx;
std::string error; std::string error;
if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) { if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
} }

View file

@ -4046,7 +4046,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
// Unserialize the transaction // Unserialize the transaction
PartiallySignedTransaction psbtx; PartiallySignedTransaction psbtx;
std::string error; std::string error;
if (!DecodePSBT(psbtx, request.params[0].get_str(), error)) { if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error)); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
} }

View file

@ -293,5 +293,8 @@ class PSBTTest(BitcoinTestFramework):
psbt = self.nodes[1].walletcreatefundedpsbt([], [{p2pkh : 1}], 0, {"includeWatching" : True}, True) psbt = self.nodes[1].walletcreatefundedpsbt([], [{p2pkh : 1}], 0, {"includeWatching" : True}, True)
self.nodes[0].decodepsbt(psbt['psbt']) self.nodes[0].decodepsbt(psbt['psbt'])
# Test decoding error: invalid base64
assert_raises_rpc_error(-22, "TX decode failed invalid base64", self.nodes[0].decodepsbt, ";definitely not base64;")
if __name__ == '__main__': if __name__ == '__main__':
PSBTTest().main() PSBTTest().main()