Remove a use of KeyIO::DecodeDestination in z_shieldcoinbase

This commit is contained in:
Kris Nuttycombe 2021-12-29 16:26:20 -07:00
parent 20266ac911
commit eb91c7869a
4 changed files with 59 additions and 58 deletions

View File

@ -26,6 +26,7 @@
#include "walletdb.h"
#include "script/interpreter.h"
#include "utiltime.h"
#include "util/match.h"
#include "zcash/IncrementalMerkleTree.hpp"
#include "miner.h"
#include "wallet/paymentdisclosuredb.h"
@ -63,7 +64,7 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
TransactionBuilder builder,
CMutableTransaction contextualTx,
std::vector<ShieldCoinbaseUTXO> inputs,
std::string toAddress,
PaymentAddress toAddress,
CAmount fee,
UniValue contextInfo) :
builder_(builder), tx_(contextualTx), inputs_(inputs), fee_(fee), contextinfo_(contextInfo)
@ -79,13 +80,23 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
}
// Check the destination address is valid for this network i.e. not testnet being used on mainnet
KeyIO keyIO(Params());
auto address = keyIO.DecodePaymentAddress(toAddress);
if (address.has_value()) {
tozaddr_ = address.value();
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid to address");
}
std::visit(match {
[&](CKeyID addr) {
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a p2pkh address.");
},
[&](CScriptID addr) {
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a p2pkh address.");
},
[&](libzcash::SaplingPaymentAddress addr) {
tozaddr_ = addr;
},
[&](libzcash::SproutPaymentAddress addr) {
tozaddr_ = addr;
},
[&](libzcash::UnifiedAddress) {
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a unified address.");
}
}, toAddress);
// Log the context info
if (LogAcceptCategory("zrpcunsafe")) {

View File

@ -45,7 +45,7 @@ public:
TransactionBuilder builder,
CMutableTransaction contextualTx,
std::vector<ShieldCoinbaseUTXO> inputs,
std::string toAddress,
PaymentAddress toAddress,
CAmount fee = DEFAULT_FEE,
UniValue contextInfo = NullUniValue);
virtual ~AsyncRPCOperation_shieldcoinbase();

View File

@ -4207,31 +4207,46 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
auto fromaddress = params[0].get_str();
bool isFromWildcard = fromaddress == "*";
KeyIO keyIO(Params());
CTxDestination taddr;
// Set of source addresses to filter utxos by
std::set<CTxDestination> sources = {};
if (!isFromWildcard) {
taddr = keyIO.DecodeDestination(fromaddress);
if (!IsValidDestination(taddr)) {
CTxDestination taddr = keyIO.DecodeDestination(fromaddress);
if (IsValidDestination(taddr)) {
sources.insert(taddr);
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
}
}
// Validate the destination address
auto destaddress = params[1].get_str();
if (!keyIO.IsValidPaymentAddressString(destaddress)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
}
int nextBlockHeight = chainActive.Height() + 1;
const bool canopyActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_CANOPY);
if (canopyActive) {
auto decodeAddr = keyIO.DecodePaymentAddress(destaddress);
if (decodeAddr.has_value()) {
libzcash::PaymentAddress addr(decodeAddr.value());
if (std::holds_alternative<libzcash::SproutPaymentAddress>(addr)) {
throw JSONRPCError(RPC_VERIFY_REJECTED, "Sprout shielding is not supported after Canopy activation");
// Validate the destination address
auto destStr = params[1].get_str();
auto destaddress = keyIO.DecodePaymentAddress(destStr);
if (destaddress.has_value()) {
std::visit(match {
[&](const CKeyID& addr) {
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a p2pkh address.");
},
[&](const CScriptID&) {
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a p2sh address.");
},
[&](const libzcash::SaplingPaymentAddress& addr) {
// OK
},
[&](const libzcash::SproutPaymentAddress& addr) {
if (canopyActive) {
throw JSONRPCError(RPC_VERIFY_REJECTED, "Sprout shielding is not supported after Canopy activation");
}
},
[&](const libzcash::UnifiedAddress& ua) {
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a unified address.");
}
}
}, destaddress.value());
} else {
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destStr);
}
// Convert fee from currency format to zatoshis
@ -4273,10 +4288,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
bool maxedOutFlag = false;
const size_t mempoolLimit = nLimit;
// Set of addresses to filter utxos by
std::set<CTxDestination> destinations = {};
if (!isFromWildcard) {
destinations.insert(taddr);
}
// Get available utxos
@ -4293,8 +4305,9 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
continue;
}
// If taddr is not wildcard "*", filter utxos
if (destinations.size() > 0 && !destinations.count(address)) {
// If from address was not the wildcard "*", filter utxos
if (sources.size() > 0 && !sources.count(address)) {
continue;
}
@ -4363,7 +4376,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
// Create operation and add to global queue
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(builder, contextualTx, inputs, destaddress, nFee, contextInfo) );
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(builder, contextualTx, inputs, destaddress.value(), nFee, contextInfo) );
q->addOperation(operation);
AsyncRPCOperationId operationId = operation->getId();

View File

@ -1770,8 +1770,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
}
// Test constructor of AsyncRPCOperation_shieldcoinbase
std::string testnetzaddr = "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP";
std::string mainnetzaddr = "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U";
KeyIO keyIO(Params());
auto testnetzaddr = std::get<libzcash::SproutPaymentAddress>(keyIO.DecodePaymentAddress("ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP").value());
try {
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, {}, testnetzaddr, -1 ));
@ -1784,15 +1784,6 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
} catch (const UniValue& objError) {
BOOST_CHECK( find_error(objError, "Empty inputs"));
}
// Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
try {
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, mainnetzaddr, 1) );
} catch (const UniValue& objError) {
BOOST_CHECK( find_error(objError, "Invalid to address"));
}
}
@ -1810,14 +1801,12 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight + 1);
// Add keys manually
KeyIO keyIO(Params());
auto pa = pwalletMain->GenerateNewSproutZKey();
std::string zaddr = keyIO.EncodePaymentAddress(pa);
// Insufficient funds
{
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, zaddr) );
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, pa) );
operation->main();
BOOST_CHECK(operation->isFailed());
std::string msg = operation->getErrorMessage();
@ -1828,7 +1817,7 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_internals)
{
// Dummy input so the operation object can be instantiated.
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,100000} };
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, zaddr) );
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, inputs, pa) );
std::shared_ptr<AsyncRPCOperation_shieldcoinbase> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_shieldcoinbase> (operation);
TEST_FRIEND_AsyncRPCOperation_shieldcoinbase proxy(ptr);
static_cast<AsyncRPCOperation_shieldcoinbase *>(operation.get())->testmode = true;
@ -1940,9 +1929,6 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
MergeToAddressRecipient testnetzaddr(
"ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP",
"testnet memo");
MergeToAddressRecipient mainnetzaddr(
"zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U",
"mainnet memo");
try {
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_mergetoaddress(std::nullopt, mtx, {}, {}, {}, testnetzaddr, -1 ));
@ -1987,15 +1973,6 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
} catch (const UniValue& objError) {
BOOST_CHECK(find_error(objError, "Sprout notes are not supported by the TransactionBuilder"));
}
// Testnet payment addresses begin with 'zt'. This test detects an incorrect prefix.
try {
std::vector<MergeToAddressInputUTXO> inputs = { MergeToAddressInputUTXO{ COutPoint{uint256(), 0}, 0, CScript()} };
std::shared_ptr<AsyncRPCOperation> operation( new AsyncRPCOperation_mergetoaddress(std::nullopt, mtx, inputs, {}, {}, mainnetzaddr, 1) );
BOOST_FAIL("Should have caused an error");
} catch (const UniValue& objError) {
BOOST_CHECK( find_error(objError, "Invalid recipient address"));
}
}