desprout
This commit is contained in:
@@ -74,19 +74,17 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress(
|
|||||||
boost::optional<TransactionBuilder> builder,
|
boost::optional<TransactionBuilder> builder,
|
||||||
CMutableTransaction contextualTx,
|
CMutableTransaction contextualTx,
|
||||||
std::vector<MergeToAddressInputUTXO> utxoInputs,
|
std::vector<MergeToAddressInputUTXO> utxoInputs,
|
||||||
std::vector<MergeToAddressInputSproutNote> sproutNoteInputs,
|
|
||||||
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs,
|
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs,
|
||||||
MergeToAddressRecipient recipient,
|
MergeToAddressRecipient recipient,
|
||||||
CAmount fee,
|
CAmount fee,
|
||||||
UniValue contextInfo) :
|
UniValue contextInfo) :
|
||||||
tx_(contextualTx), utxoInputs_(utxoInputs), sproutNoteInputs_(sproutNoteInputs),
|
tx_(contextualTx), utxoInputs_(utxoInputs), saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), contextinfo_(contextInfo)
|
||||||
saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), contextinfo_(contextInfo)
|
|
||||||
{
|
{
|
||||||
if (fee < 0 || fee > MAX_MONEY) {
|
if (fee < 0 || fee > MAX_MONEY) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee is out of range");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee is out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utxoInputs.empty() && sproutNoteInputs.empty() && saplingNoteInputs.empty()) {
|
if (utxoInputs.empty() && saplingNoteInputs.empty()) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "No inputs");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "No inputs");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,14 +92,6 @@ saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), context
|
|||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Recipient parameter missing");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Recipient parameter missing");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sproutNoteInputs.size() > 0 && saplingNoteInputs.size() > 0) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sproutNoteInputs.size() > 0 && builder) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Sprout notes are not supported by the TransactionBuilder");
|
|
||||||
}
|
|
||||||
|
|
||||||
isUsingBuilder_ = false;
|
isUsingBuilder_ = false;
|
||||||
if (builder) {
|
if (builder) {
|
||||||
isUsingBuilder_ = true;
|
isUsingBuilder_ = true;
|
||||||
@@ -215,7 +205,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
|||||||
{
|
{
|
||||||
assert(isToTaddr_ != isToZaddr_);
|
assert(isToTaddr_ != isToZaddr_);
|
||||||
|
|
||||||
bool isPureTaddrOnlyTx = (sproutNoteInputs_.empty() && saplingNoteInputs_.empty() && isToTaddr_);
|
bool isPureTaddrOnlyTx = (saplingNoteInputs_.empty() && isToTaddr_);
|
||||||
CAmount minersFee = fee_;
|
CAmount minersFee = fee_;
|
||||||
|
|
||||||
size_t numInputs = utxoInputs_.size();
|
size_t numInputs = utxoInputs_.size();
|
||||||
@@ -240,9 +230,6 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
|||||||
}
|
}
|
||||||
|
|
||||||
CAmount z_inputs_total = 0;
|
CAmount z_inputs_total = 0;
|
||||||
for (const MergeToAddressInputSproutNote& t : sproutNoteInputs_) {
|
|
||||||
z_inputs_total += std::get<2>(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const MergeToAddressInputSaplingNote& t : saplingNoteInputs_) {
|
for (const MergeToAddressInputSaplingNote& t : saplingNoteInputs_) {
|
||||||
z_inputs_total += std::get<2>(t);
|
z_inputs_total += std::get<2>(t);
|
||||||
@@ -293,7 +280,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl()
|
|||||||
/**
|
/**
|
||||||
* SCENARIO #0
|
* SCENARIO #0
|
||||||
*
|
*
|
||||||
* Sprout not involved, so we just use the TransactionBuilder and we're done.
|
* Only sapling involved, so we just use the TransactionBuilder and we're done.
|
||||||
*
|
*
|
||||||
* This is based on code from AsyncRPCOperation_sendmany::main_impl() and should be refactored.
|
* This is based on code from AsyncRPCOperation_sendmany::main_impl() and should be refactored.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ public:
|
|||||||
boost::optional<TransactionBuilder> builder,
|
boost::optional<TransactionBuilder> builder,
|
||||||
CMutableTransaction contextualTx,
|
CMutableTransaction contextualTx,
|
||||||
std::vector<MergeToAddressInputUTXO> utxoInputs,
|
std::vector<MergeToAddressInputUTXO> utxoInputs,
|
||||||
std::vector<MergeToAddressInputSproutNote> sproutNoteInputs,
|
|
||||||
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs,
|
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs,
|
||||||
MergeToAddressRecipient recipient,
|
MergeToAddressRecipient recipient,
|
||||||
CAmount fee = MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE,
|
CAmount fee = MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE,
|
||||||
@@ -94,9 +93,6 @@ private:
|
|||||||
uint256 joinSplitPubKey_;
|
uint256 joinSplitPubKey_;
|
||||||
unsigned char joinSplitPrivKey_[crypto_sign_SECRETKEYBYTES];
|
unsigned char joinSplitPrivKey_[crypto_sign_SECRETKEYBYTES];
|
||||||
|
|
||||||
// The key is the result string from calling JSOutPoint::ToString()
|
|
||||||
std::unordered_map<std::string, MergeToAddressWitnessAnchorData> jsopWitnessAnchorMap;
|
|
||||||
|
|
||||||
std::vector<MergeToAddressInputUTXO> utxoInputs_;
|
std::vector<MergeToAddressInputUTXO> utxoInputs_;
|
||||||
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs_;
|
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs_;
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CSproutNotePlaintextEntry> sproutEntries;
|
|
||||||
std::vector<SaplingNoteEntry> saplingEntries;
|
std::vector<SaplingNoteEntry> saplingEntries;
|
||||||
std::set<libzcash::SaplingPaymentAddress> addresses;
|
std::set<libzcash::SaplingPaymentAddress> addresses;
|
||||||
{
|
{
|
||||||
@@ -95,7 +94,7 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
|||||||
// We set minDepth to 11 to avoid unconfirmed notes and in anticipation of specifying
|
// We set minDepth to 11 to avoid unconfirmed notes and in anticipation of specifying
|
||||||
// an anchor at height N-10 for each SpendDescription
|
// an anchor at height N-10 for each SpendDescription
|
||||||
// Consider, should notes be sorted?
|
// Consider, should notes be sorted?
|
||||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 11);
|
pwalletMain->GetFilteredNotes(saplingEntries, "", 11);
|
||||||
if (fConsolidationMapUsed) {
|
if (fConsolidationMapUsed) {
|
||||||
const vector<string>& v = mapMultiArgs["-consolidatesaplingaddress"];
|
const vector<string>& v = mapMultiArgs["-consolidatesaplingaddress"];
|
||||||
for(int i = 0; i < v.size(); i++) {
|
for(int i = 0; i < v.size(); i++) {
|
||||||
|
|||||||
@@ -248,18 +248,12 @@ bool AsyncRPCOperation_sendmany::main_impl() {
|
|||||||
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds, no unspent notes found for zaddr from address.");
|
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds, no unspent notes found for zaddr from address.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// At least one of z_sprout_inputs_ and z_sapling_inputs_ must be empty by design
|
|
||||||
assert(z_sprout_inputs_.empty() || z_sapling_inputs_.empty());
|
|
||||||
|
|
||||||
CAmount t_inputs_total = 0;
|
CAmount t_inputs_total = 0;
|
||||||
for (SendManyInputUTXO & t : t_inputs_) {
|
for (SendManyInputUTXO & t : t_inputs_) {
|
||||||
t_inputs_total += std::get<2>(t);
|
t_inputs_total += std::get<2>(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
CAmount z_inputs_total = 0;
|
CAmount z_inputs_total = 0;
|
||||||
for (SendManyInputJSOP & t : z_sprout_inputs_) {
|
|
||||||
z_inputs_total += std::get<2>(t);
|
|
||||||
}
|
|
||||||
for (auto t : z_sapling_inputs_) {
|
for (auto t : z_sapling_inputs_) {
|
||||||
z_inputs_total += t.note.value();
|
z_inputs_total += t.note.value();
|
||||||
}
|
}
|
||||||
@@ -687,20 +681,10 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) {
|
|||||||
|
|
||||||
|
|
||||||
bool AsyncRPCOperation_sendmany::find_unspent_notes() {
|
bool AsyncRPCOperation_sendmany::find_unspent_notes() {
|
||||||
std::vector<CSproutNotePlaintextEntry> sproutEntries;
|
|
||||||
std::vector<SaplingNoteEntry> saplingEntries;
|
std::vector<SaplingNoteEntry> saplingEntries;
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress_, mindepth_);
|
pwalletMain->GetFilteredNotes(saplingEntries, fromaddress_, mindepth_);
|
||||||
}
|
|
||||||
|
|
||||||
// If using the TransactionBuilder, we only want Sapling notes.
|
|
||||||
// If not using it, we only want Sprout notes.
|
|
||||||
// TODO: Refactor `GetFilteredNotes()` so we only fetch what we need.
|
|
||||||
if (isUsingBuilder_) {
|
|
||||||
sproutEntries.clear();
|
|
||||||
} else {
|
|
||||||
saplingEntries.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto entry : saplingEntries) {
|
for (auto entry : saplingEntries) {
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ using namespace libzcash;
|
|||||||
|
|
||||||
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
|
||||||
extern std::string ASSETCHAINS_OVERRIDE_PUBKEY;
|
extern std::string ASSETCHAINS_OVERRIDE_PUBKEY;
|
||||||
const std::string ADDR_TYPE_SPROUT = "sprout";
|
|
||||||
const std::string ADDR_TYPE_SAPLING = "sapling";
|
const std::string ADDR_TYPE_SAPLING = "sapling";
|
||||||
extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
|
extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
|
||||||
extern int32_t KOMODO_INSYNC;
|
extern int32_t KOMODO_INSYNC;
|
||||||
@@ -3787,9 +3786,8 @@ UniValue z_listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
UniValue results(UniValue::VARR);
|
UniValue results(UniValue::VARR);
|
||||||
|
|
||||||
if (zaddrs.size() > 0) {
|
if (zaddrs.size() > 0) {
|
||||||
std::vector<CSproutNotePlaintextEntry> sproutEntries;
|
|
||||||
std::vector<SaplingNoteEntry> saplingEntries;
|
std::vector<SaplingNoteEntry> saplingEntries;
|
||||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
|
pwalletMain->GetFilteredNotes(saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false);
|
||||||
std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
|
std::set<std::pair<PaymentAddress, uint256>> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs);
|
||||||
|
|
||||||
for (auto & entry : saplingEntries) {
|
for (auto & entry : saplingEntries) {
|
||||||
@@ -4047,10 +4045,9 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ign
|
|||||||
|
|
||||||
CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
|
CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) {
|
||||||
CAmount balance = 0;
|
CAmount balance = 0;
|
||||||
std::vector<CSproutNotePlaintextEntry> sproutEntries;
|
|
||||||
std::vector<SaplingNoteEntry> saplingEntries;
|
std::vector<SaplingNoteEntry> saplingEntries;
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, address, minDepth, true, ignoreUnspendable);
|
pwalletMain->GetFilteredNotes(saplingEntries, address, minDepth, true, ignoreUnspendable);
|
||||||
for (auto & entry : saplingEntries) {
|
for (auto & entry : saplingEntries) {
|
||||||
balance += CAmount(entry.note.value());
|
balance += CAmount(entry.note.value());
|
||||||
}
|
}
|
||||||
@@ -4102,16 +4099,14 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK
|
|||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visitor to support Sprout and Sapling addrs
|
|
||||||
if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), zaddr) &&
|
if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), zaddr) &&
|
||||||
!boost::apply_visitor(IncomingViewingKeyBelongsToWallet(pwalletMain), zaddr)) {
|
!boost::apply_visitor(IncomingViewingKeyBelongsToWallet(pwalletMain), zaddr)) {
|
||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue result(UniValue::VARR);
|
UniValue result(UniValue::VARR);
|
||||||
std::vector<CSproutNotePlaintextEntry> sproutEntries;
|
|
||||||
std::vector<SaplingNoteEntry> saplingEntries;
|
std::vector<SaplingNoteEntry> saplingEntries;
|
||||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress, nMinDepth, false, false);
|
pwalletMain->GetFilteredNotes(saplingEntries, fromaddress, nMinDepth, false, false);
|
||||||
|
|
||||||
std::set<std::pair<PaymentAddress, uint256>> nullifierSet;
|
std::set<std::pair<PaymentAddress, uint256>> nullifierSet;
|
||||||
auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
|
auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr);
|
||||||
@@ -4223,7 +4218,7 @@ UniValue z_getnotescount(const UniValue& params, bool fHelp,const CPubKey& mypk)
|
|||||||
"z_getnotescount\n"
|
"z_getnotescount\n"
|
||||||
"\nArguments:\n"
|
"\nArguments:\n"
|
||||||
"1. minconf (numeric, optional, default=1) Only include notes in transactions confirmed at least this many times.\n"
|
"1. minconf (numeric, optional, default=1) Only include notes in transactions confirmed at least this many times.\n"
|
||||||
"\nReturns the number of sprout and sapling notes available in the wallet.\n"
|
"\nReturns the number of sapling notes available in the wallet.\n"
|
||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" \"sapling\" (numeric) the number of sapling notes in the wallet\n"
|
" \"sapling\" (numeric) the number of sapling notes in the wallet\n"
|
||||||
@@ -4268,7 +4263,7 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& my
|
|||||||
"\nResult:\n"
|
"\nResult:\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
|
" \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n"
|
||||||
" \"private\": xxxxx, (numeric) the total balance of private funds (in both Sprout and Sapling addresses)\n"
|
" \"private\": xxxxx, (numeric) the total balance of private funds\n"
|
||||||
" \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
|
" \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\nExamples:\n"
|
"\nExamples:\n"
|
||||||
@@ -4650,14 +4645,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
|
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember whether this is a Sprout or Sapling address
|
// Remember whether this is a Sapling address
|
||||||
fromSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
|
fromSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
|
||||||
}
|
}
|
||||||
// This logic will need to be updated if we add a new shielded pool
|
|
||||||
bool fromSprout = !(fromTaddr || fromSapling);
|
|
||||||
|
|
||||||
if (fromSprout)
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot send from a Sprout zaddr, only Sapling zaddrs supported.");
|
|
||||||
|
|
||||||
UniValue outputs = params[1].get_array();
|
UniValue outputs = params[1].get_array();
|
||||||
|
|
||||||
@@ -4667,15 +4657,11 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
// Keep track of addresses to spot duplicates
|
// Keep track of addresses to spot duplicates
|
||||||
set<std::string> setAddress;
|
set<std::string> setAddress;
|
||||||
|
|
||||||
// Track whether we see any Sprout addresses
|
|
||||||
bool noSproutAddrs = !fromSprout;
|
|
||||||
|
|
||||||
// Recipients
|
// Recipients
|
||||||
std::vector<SendManyRecipient> taddrRecipients;
|
std::vector<SendManyRecipient> taddrRecipients;
|
||||||
std::vector<SendManyRecipient> zaddrRecipients;
|
std::vector<SendManyRecipient> zaddrRecipients;
|
||||||
CAmount nTotalOut = 0;
|
CAmount nTotalOut = 0;
|
||||||
|
|
||||||
bool containsSproutOutput = false;
|
|
||||||
bool containsSaplingOutput = false;
|
bool containsSaplingOutput = false;
|
||||||
|
|
||||||
for (const UniValue& o : outputs.getValues()) {
|
for (const UniValue& o : outputs.getValues()) {
|
||||||
@@ -4696,35 +4682,6 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
auto res = DecodePaymentAddress(address);
|
auto res = DecodePaymentAddress(address);
|
||||||
if (IsValidPaymentAddress(res, branchId)) {
|
if (IsValidPaymentAddress(res, branchId)) {
|
||||||
isZaddr = true;
|
isZaddr = true;
|
||||||
|
|
||||||
bool toSapling = boost::get<libzcash::SaplingPaymentAddress>(&res) != nullptr;
|
|
||||||
bool toSprout = !toSapling;
|
|
||||||
noSproutAddrs = noSproutAddrs && toSapling;
|
|
||||||
|
|
||||||
containsSproutOutput |= toSprout;
|
|
||||||
containsSaplingOutput |= toSapling;
|
|
||||||
|
|
||||||
// Sending to both Sprout and Sapling is currently unsupported using z_sendmany
|
|
||||||
if (containsSproutOutput && containsSaplingOutput) {
|
|
||||||
throw JSONRPCError(
|
|
||||||
RPC_INVALID_PARAMETER,
|
|
||||||
"Cannot send to both Sprout and Sapling addresses using z_sendmany");
|
|
||||||
}
|
|
||||||
if ( GetTime() > KOMODO_SAPLING_DEADLINE )
|
|
||||||
{
|
|
||||||
if ( fromSprout || toSprout )
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER,"Sprout usage has expired");
|
|
||||||
}
|
|
||||||
if ( toSapling && ASSETCHAINS_SYMBOL[0] == 0 )
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER,"Sprout usage will expire soon");
|
|
||||||
|
|
||||||
// If we are sending from a shielded address, all recipient
|
|
||||||
// shielded addresses must be of the same type.
|
|
||||||
if ((fromSprout && toSapling) || (fromSapling && toSprout)) {
|
|
||||||
throw JSONRPCError(
|
|
||||||
RPC_INVALID_PARAMETER,
|
|
||||||
"Cannot send between Sprout and Sapling addresses using z_sendmany");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
|
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address );
|
||||||
}
|
}
|
||||||
@@ -4915,9 +4872,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
|||||||
|
|
||||||
// Builder (used if Sapling addresses are involved)
|
// Builder (used if Sapling addresses are involved)
|
||||||
boost::optional<TransactionBuilder> builder;
|
boost::optional<TransactionBuilder> builder;
|
||||||
if (noSproutAddrs) {
|
builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
|
||||||
builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contextual transaction we will build on
|
// Contextual transaction we will build on
|
||||||
// (used if no Sapling addresses are involved)
|
// (used if no Sapling addresses are involved)
|
||||||
@@ -5190,11 +5145,11 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
|
|
||||||
string enableArg = "zmergetoaddress";
|
string enableArg = "zmergetoaddress";
|
||||||
auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, true);
|
//auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, true);
|
||||||
std::string strDisabledMsg = "";
|
//std::string strDisabledMsg = "";
|
||||||
if (!fEnableMergeToAddress) {
|
//if (!fEnableMergeToAddress) {
|
||||||
strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg);
|
// strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg);
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (fHelp || params.size() < 2 || params.size() > 7)
|
if (fHelp || params.size() < 2 || params.size() > 7)
|
||||||
throw runtime_error(
|
throw runtime_error(
|
||||||
@@ -5256,7 +5211,6 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
THROW_IF_SYNCING(KOMODO_INSYNC);
|
THROW_IF_SYNCING(KOMODO_INSYNC);
|
||||||
|
|
||||||
bool useAnyUTXO = false;
|
bool useAnyUTXO = false;
|
||||||
bool useAnySprout = false;
|
|
||||||
bool useAnySapling = false;
|
bool useAnySapling = false;
|
||||||
std::set<CTxDestination> taddrs = {};
|
std::set<CTxDestination> taddrs = {};
|
||||||
std::set<libzcash::PaymentAddress> zaddrs = {};
|
std::set<libzcash::PaymentAddress> zaddrs = {};
|
||||||
@@ -5277,8 +5231,6 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
|
|
||||||
if (address == "ANY_TADDR") {
|
if (address == "ANY_TADDR") {
|
||||||
useAnyUTXO = true;
|
useAnyUTXO = true;
|
||||||
} else if (address == "ANY_SPROUT") {
|
|
||||||
useAnySprout = true;
|
|
||||||
} else if (address == "ANY_SAPLING") {
|
} else if (address == "ANY_SAPLING") {
|
||||||
useAnySapling = true;
|
useAnySapling = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -5303,8 +5255,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
if (useAnyUTXO && taddrs.size() > 0) {
|
if (useAnyUTXO && taddrs.size() > 0) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific t-addrs when using \"ANY_TADDR\"");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific t-addrs when using \"ANY_TADDR\"");
|
||||||
}
|
}
|
||||||
if ((useAnySprout || useAnySapling) && zaddrs.size() > 0) {
|
if ((useAnySapling) && zaddrs.size() > 0) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific z-addrs when using \"ANY_SPROUT\" or \"ANY_SAPLING\"");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific z-addrs when using \"ANY_SAPLING\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
const int nextBlockHeight = chainActive.Height() + 1;
|
const int nextBlockHeight = chainActive.Height() + 1;
|
||||||
@@ -5313,7 +5265,6 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
|
|
||||||
// Validate the destination address
|
// Validate the destination address
|
||||||
auto destaddress = params[1].get_str();
|
auto destaddress = params[1].get_str();
|
||||||
bool isToSproutZaddr = false;
|
|
||||||
bool isToSaplingZaddr = false;
|
bool isToSaplingZaddr = false;
|
||||||
CTxDestination taddr = DecodeDestination(destaddress);
|
CTxDestination taddr = DecodeDestination(destaddress);
|
||||||
if (!IsValidDestination(taddr)) {
|
if (!IsValidDestination(taddr)) {
|
||||||
@@ -5326,7 +5277,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
isToSproutZaddr = true;
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Only Sapling zaddrs allowed!");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
|
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress );
|
||||||
@@ -5351,14 +5302,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sproutNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT;
|
|
||||||
int saplingNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT;
|
int saplingNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT;
|
||||||
if (params.size() > 4) {
|
if (params.size() > 4) {
|
||||||
int nNoteLimit = params[4].get_int();
|
int nNoteLimit = params[4].get_int();
|
||||||
if (nNoteLimit < 0) {
|
if (nNoteLimit < 0) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative");
|
||||||
}
|
}
|
||||||
sproutNoteLimit = nNoteLimit;
|
|
||||||
saplingNoteLimit = nNoteLimit;
|
saplingNoteLimit = nNoteLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5375,7 +5324,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
std::string memo;
|
std::string memo;
|
||||||
if (params.size() > 6) {
|
if (params.size() > 6) {
|
||||||
memo = params[6].get_str();
|
memo = params[6].get_str();
|
||||||
if (!(isToSproutZaddr || isToSaplingZaddr)) {
|
if (!isToSaplingZaddr) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr.");
|
||||||
} else if (!IsHex(memo)) {
|
} else if (!IsHex(memo)) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format.");
|
||||||
@@ -5389,7 +5338,6 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
|
|
||||||
// Prepare to get UTXOs and notes
|
// Prepare to get UTXOs and notes
|
||||||
std::vector<MergeToAddressInputUTXO> utxoInputs;
|
std::vector<MergeToAddressInputUTXO> utxoInputs;
|
||||||
std::vector<MergeToAddressInputSproutNote> sproutNoteInputs;
|
|
||||||
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs;
|
std::vector<MergeToAddressInputSaplingNote> saplingNoteInputs;
|
||||||
CAmount mergedUTXOValue = 0;
|
CAmount mergedUTXOValue = 0;
|
||||||
CAmount mergedNoteValue = 0;
|
CAmount mergedNoteValue = 0;
|
||||||
@@ -5403,9 +5351,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
|
|
||||||
unsigned int max_tx_size = saplingActive ? MAX_TX_SIZE_AFTER_SAPLING : MAX_TX_SIZE_BEFORE_SAPLING;
|
unsigned int max_tx_size = saplingActive ? MAX_TX_SIZE_AFTER_SAPLING : MAX_TX_SIZE_BEFORE_SAPLING;
|
||||||
size_t estimatedTxSize = 200; // tx overhead + wiggle room
|
size_t estimatedTxSize = 200; // tx overhead + wiggle room
|
||||||
if (isToSproutZaddr) {
|
|
||||||
estimatedTxSize += JOINSPLIT_SIZE;
|
if (isToSaplingZaddr) {
|
||||||
} else if (isToSaplingZaddr) {
|
|
||||||
estimatedTxSize += OUTPUTDESCRIPTION_SIZE;
|
estimatedTxSize += OUTPUTDESCRIPTION_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5463,29 +5410,10 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useAnySprout || useAnySapling || zaddrs.size() > 0) {
|
if (useAnySapling || zaddrs.size() > 0) {
|
||||||
// Get available notes
|
// Get available notes
|
||||||
std::vector<CSproutNotePlaintextEntry> sproutEntries;
|
std::vector<SaplingNoteEntry> saplingEntries;
|
||||||
//std::vector<SaplingNoteEntry> saplingEntries;
|
pwalletMain->GetFilteredNotes(saplingEntries, zaddrs);
|
||||||
//pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs);
|
|
||||||
std::vector<SaplingNoteEntry> saplingEntries,skipsapling;
|
|
||||||
pwalletMain->GetFilteredNotes(sproutEntries, useAnySprout == 0 ? saplingEntries : skipsapling, zaddrs);
|
|
||||||
// If Sapling is not active, do not allow sending from a sapling addresses.
|
|
||||||
if (!saplingActive && saplingEntries.size() > 0) {
|
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
|
|
||||||
}
|
|
||||||
// Sending from both Sprout and Sapling is currently unsupported using z_mergetoaddress
|
|
||||||
if (sproutEntries.size() > 0 && saplingEntries.size() > 0) {
|
|
||||||
throw JSONRPCError(
|
|
||||||
RPC_INVALID_PARAMETER,
|
|
||||||
"Cannot send from both Sprout and Sapling addresses using z_mergetoaddress");
|
|
||||||
}
|
|
||||||
// If sending between shielded addresses, they must be the same type
|
|
||||||
if ((saplingEntries.size() > 0 && isToSproutZaddr) || (sproutEntries.size() > 0 && isToSaplingZaddr)) {
|
|
||||||
throw JSONRPCError(
|
|
||||||
RPC_INVALID_PARAMETER,
|
|
||||||
"Cannot send between Sprout and Sapling addresses using z_mergetoaddress");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const SaplingNoteEntry& entry : saplingEntries) {
|
for (const SaplingNoteEntry& entry : saplingEntries) {
|
||||||
noteCounter++;
|
noteCounter++;
|
||||||
@@ -5514,7 +5442,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t numUtxos = utxoInputs.size();
|
size_t numUtxos = utxoInputs.size();
|
||||||
size_t numNotes = sproutNoteInputs.size() + saplingNoteInputs.size();
|
size_t numNotes = saplingNoteInputs.size();
|
||||||
|
|
||||||
//fprintf(stderr, "num utxos.%li\n", numUtxos);
|
//fprintf(stderr, "num utxos.%li\n", numUtxos);
|
||||||
if (numUtxos < 2 && numNotes == 0) {
|
if (numUtxos < 2 && numNotes == 0) {
|
||||||
@@ -5552,22 +5480,19 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp
|
|||||||
CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
|
CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction(
|
||||||
Params().GetConsensus(),
|
Params().GetConsensus(),
|
||||||
nextBlockHeight);
|
nextBlockHeight);
|
||||||
bool isSproutShielded = sproutNoteInputs.size() > 0 || isToSproutZaddr;
|
|
||||||
if (contextualTx.nVersion == 1 && isSproutShielded) {
|
|
||||||
contextualTx.nVersion = 2; // Tx format should support vjoinsplit
|
|
||||||
}
|
|
||||||
|
|
||||||
// Builder (used if Sapling addresses are involved)
|
// Builder (used if Sapling addresses are involved)
|
||||||
boost::optional<TransactionBuilder> builder;
|
boost::optional<TransactionBuilder> builder;
|
||||||
if (isToSaplingZaddr || saplingNoteInputs.size() > 0) {
|
if (isToSaplingZaddr || saplingNoteInputs.size() > 0) {
|
||||||
builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
|
builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain);
|
||||||
} else
|
} else {
|
||||||
contextualTx.nExpiryHeight = 0; // set non z-tx to have no expiry height.
|
contextualTx.nExpiryHeight = 0; // set non z-tx to have no expiry height.
|
||||||
|
}
|
||||||
|
|
||||||
// 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(
|
std::shared_ptr<AsyncRPCOperation> operation(
|
||||||
new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, sproutNoteInputs, saplingNoteInputs, recipient, nFee, contextInfo) );
|
new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, saplingNoteInputs, recipient, nFee, contextInfo) );
|
||||||
q->addOperation(operation);
|
q->addOperation(operation);
|
||||||
AsyncRPCOperationId operationId = operation->getId();
|
AsyncRPCOperationId operationId = operation->getId();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user