Remove a use of KeyIO::DecodeDestination in z_shieldcoinbase
This commit is contained in:
parent
20266ac911
commit
eb91c7869a
|
@ -26,6 +26,7 @@
|
||||||
#include "walletdb.h"
|
#include "walletdb.h"
|
||||||
#include "script/interpreter.h"
|
#include "script/interpreter.h"
|
||||||
#include "utiltime.h"
|
#include "utiltime.h"
|
||||||
|
#include "util/match.h"
|
||||||
#include "zcash/IncrementalMerkleTree.hpp"
|
#include "zcash/IncrementalMerkleTree.hpp"
|
||||||
#include "miner.h"
|
#include "miner.h"
|
||||||
#include "wallet/paymentdisclosuredb.h"
|
#include "wallet/paymentdisclosuredb.h"
|
||||||
|
@ -63,7 +64,7 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase(
|
||||||
TransactionBuilder builder,
|
TransactionBuilder builder,
|
||||||
CMutableTransaction contextualTx,
|
CMutableTransaction contextualTx,
|
||||||
std::vector<ShieldCoinbaseUTXO> inputs,
|
std::vector<ShieldCoinbaseUTXO> inputs,
|
||||||
std::string toAddress,
|
PaymentAddress toAddress,
|
||||||
CAmount fee,
|
CAmount fee,
|
||||||
UniValue contextInfo) :
|
UniValue contextInfo) :
|
||||||
builder_(builder), tx_(contextualTx), inputs_(inputs), fee_(fee), contextinfo_(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
|
// Check the destination address is valid for this network i.e. not testnet being used on mainnet
|
||||||
KeyIO keyIO(Params());
|
std::visit(match {
|
||||||
auto address = keyIO.DecodePaymentAddress(toAddress);
|
[&](CKeyID addr) {
|
||||||
if (address.has_value()) {
|
throw JSONRPCError(RPC_VERIFY_REJECTED, "Cannot shield coinbase output to a p2pkh address.");
|
||||||
tozaddr_ = address.value();
|
},
|
||||||
} else {
|
[&](CScriptID addr) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid to address");
|
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
|
// Log the context info
|
||||||
if (LogAcceptCategory("zrpcunsafe")) {
|
if (LogAcceptCategory("zrpcunsafe")) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
TransactionBuilder builder,
|
TransactionBuilder builder,
|
||||||
CMutableTransaction contextualTx,
|
CMutableTransaction contextualTx,
|
||||||
std::vector<ShieldCoinbaseUTXO> inputs,
|
std::vector<ShieldCoinbaseUTXO> inputs,
|
||||||
std::string toAddress,
|
PaymentAddress toAddress,
|
||||||
CAmount fee = DEFAULT_FEE,
|
CAmount fee = DEFAULT_FEE,
|
||||||
UniValue contextInfo = NullUniValue);
|
UniValue contextInfo = NullUniValue);
|
||||||
virtual ~AsyncRPCOperation_shieldcoinbase();
|
virtual ~AsyncRPCOperation_shieldcoinbase();
|
||||||
|
|
|
@ -4207,31 +4207,46 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
|
||||||
auto fromaddress = params[0].get_str();
|
auto fromaddress = params[0].get_str();
|
||||||
bool isFromWildcard = fromaddress == "*";
|
bool isFromWildcard = fromaddress == "*";
|
||||||
KeyIO keyIO(Params());
|
KeyIO keyIO(Params());
|
||||||
CTxDestination taddr;
|
|
||||||
|
// Set of source addresses to filter utxos by
|
||||||
|
std::set<CTxDestination> sources = {};
|
||||||
if (!isFromWildcard) {
|
if (!isFromWildcard) {
|
||||||
taddr = keyIO.DecodeDestination(fromaddress);
|
CTxDestination taddr = keyIO.DecodeDestination(fromaddress);
|
||||||
if (!IsValidDestination(taddr)) {
|
if (IsValidDestination(taddr)) {
|
||||||
|
sources.insert(taddr);
|
||||||
|
} else {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid from address, should be a taddr or \"*\".");
|
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;
|
int nextBlockHeight = chainActive.Height() + 1;
|
||||||
const bool canopyActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_CANOPY);
|
const bool canopyActive = Params().GetConsensus().NetworkUpgradeActive(nextBlockHeight, Consensus::UPGRADE_CANOPY);
|
||||||
|
|
||||||
if (canopyActive) {
|
// Validate the destination address
|
||||||
auto decodeAddr = keyIO.DecodePaymentAddress(destaddress);
|
auto destStr = params[1].get_str();
|
||||||
if (decodeAddr.has_value()) {
|
auto destaddress = keyIO.DecodePaymentAddress(destStr);
|
||||||
libzcash::PaymentAddress addr(decodeAddr.value());
|
if (destaddress.has_value()) {
|
||||||
if (std::holds_alternative<libzcash::SproutPaymentAddress>(addr)) {
|
std::visit(match {
|
||||||
throw JSONRPCError(RPC_VERIFY_REJECTED, "Sprout shielding is not supported after Canopy activation");
|
[&](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
|
// Convert fee from currency format to zatoshis
|
||||||
|
@ -4273,10 +4288,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
|
||||||
bool maxedOutFlag = false;
|
bool maxedOutFlag = false;
|
||||||
const size_t mempoolLimit = nLimit;
|
const size_t mempoolLimit = nLimit;
|
||||||
|
|
||||||
// Set of addresses to filter utxos by
|
|
||||||
std::set<CTxDestination> destinations = {};
|
|
||||||
if (!isFromWildcard) {
|
if (!isFromWildcard) {
|
||||||
destinations.insert(taddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get available utxos
|
// Get available utxos
|
||||||
|
@ -4293,8 +4305,9 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
|
||||||
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
|
if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) {
|
||||||
continue;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4363,7 +4376,7 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp)
|
||||||
|
|
||||||
// Create operation and add to global queue
|
// Create operation and add to global queue
|
||||||
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
|
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);
|
q->addOperation(operation);
|
||||||
AsyncRPCOperationId operationId = operation->getId();
|
AsyncRPCOperationId operationId = operation->getId();
|
||||||
|
|
||||||
|
|
|
@ -1770,8 +1770,8 @@ BOOST_AUTO_TEST_CASE(rpc_z_shieldcoinbase_parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test constructor of AsyncRPCOperation_shieldcoinbase
|
// Test constructor of AsyncRPCOperation_shieldcoinbase
|
||||||
std::string testnetzaddr = "ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP";
|
KeyIO keyIO(Params());
|
||||||
std::string mainnetzaddr = "zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U";
|
auto testnetzaddr = std::get<libzcash::SproutPaymentAddress>(keyIO.DecodePaymentAddress("ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP").value());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_shieldcoinbase(TransactionBuilder(), mtx, {}, testnetzaddr, -1 ));
|
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) {
|
} catch (const UniValue& objError) {
|
||||||
BOOST_CHECK( find_error(objError, "Empty inputs"));
|
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);
|
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(consensusParams, nHeight + 1);
|
||||||
|
|
||||||
// Add keys manually
|
// Add keys manually
|
||||||
KeyIO keyIO(Params());
|
|
||||||
auto pa = pwalletMain->GenerateNewSproutZKey();
|
auto pa = pwalletMain->GenerateNewSproutZKey();
|
||||||
std::string zaddr = keyIO.EncodePaymentAddress(pa);
|
|
||||||
|
|
||||||
// Insufficient funds
|
// Insufficient funds
|
||||||
{
|
{
|
||||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,0} };
|
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();
|
operation->main();
|
||||||
BOOST_CHECK(operation->isFailed());
|
BOOST_CHECK(operation->isFailed());
|
||||||
std::string msg = operation->getErrorMessage();
|
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.
|
// Dummy input so the operation object can be instantiated.
|
||||||
std::vector<ShieldCoinbaseUTXO> inputs = { ShieldCoinbaseUTXO{uint256(),0,100000} };
|
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);
|
std::shared_ptr<AsyncRPCOperation_shieldcoinbase> ptr = std::dynamic_pointer_cast<AsyncRPCOperation_shieldcoinbase> (operation);
|
||||||
TEST_FRIEND_AsyncRPCOperation_shieldcoinbase proxy(ptr);
|
TEST_FRIEND_AsyncRPCOperation_shieldcoinbase proxy(ptr);
|
||||||
static_cast<AsyncRPCOperation_shieldcoinbase *>(operation.get())->testmode = true;
|
static_cast<AsyncRPCOperation_shieldcoinbase *>(operation.get())->testmode = true;
|
||||||
|
@ -1940,9 +1929,6 @@ BOOST_AUTO_TEST_CASE(rpc_z_mergetoaddress_parameters)
|
||||||
MergeToAddressRecipient testnetzaddr(
|
MergeToAddressRecipient testnetzaddr(
|
||||||
"ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP",
|
"ztjiDe569DPNbyTE6TSdJTaSDhoXEHLGvYoUnBU1wfVNU52TEyT6berYtySkd21njAeEoh8fFJUT42kua9r8EnhBaEKqCpP",
|
||||||
"testnet memo");
|
"testnet memo");
|
||||||
MergeToAddressRecipient mainnetzaddr(
|
|
||||||
"zcMuhvq8sEkHALuSU2i4NbNQxshSAYrpCExec45ZjtivYPbuiFPwk6WHy4SvsbeZ4siy1WheuRGjtaJmoD1J8bFqNXhsG6U",
|
|
||||||
"mainnet memo");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_mergetoaddress(std::nullopt, mtx, {}, {}, {}, testnetzaddr, -1 ));
|
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) {
|
} catch (const UniValue& objError) {
|
||||||
BOOST_CHECK(find_error(objError, "Sprout notes are not supported by the TransactionBuilder"));
|
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"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue