Merge pull request 'Implement zsweep' (#195) from zsweep into dev
Reviewed-on: https://git.hush.is/hush/hush3/pulls/195
This commit is contained in:
@@ -225,6 +225,7 @@ BITCOIN_CORE_H = \
|
|||||||
version.h \
|
version.h \
|
||||||
wallet/asyncrpcoperation_mergetoaddress.h \
|
wallet/asyncrpcoperation_mergetoaddress.h \
|
||||||
wallet/asyncrpcoperation_saplingconsolidation.h \
|
wallet/asyncrpcoperation_saplingconsolidation.h \
|
||||||
|
wallet/asyncrpcoperation_sweep.h \
|
||||||
wallet/asyncrpcoperation_sendmany.h \
|
wallet/asyncrpcoperation_sendmany.h \
|
||||||
wallet/asyncrpcoperation_shieldcoinbase.h \
|
wallet/asyncrpcoperation_shieldcoinbase.h \
|
||||||
wallet/crypter.h \
|
wallet/crypter.h \
|
||||||
@@ -323,6 +324,7 @@ libbitcoin_wallet_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
|
|||||||
libbitcoin_wallet_a_SOURCES = \
|
libbitcoin_wallet_a_SOURCES = \
|
||||||
wallet/asyncrpcoperation_mergetoaddress.cpp \
|
wallet/asyncrpcoperation_mergetoaddress.cpp \
|
||||||
wallet/asyncrpcoperation_saplingconsolidation.cpp \
|
wallet/asyncrpcoperation_saplingconsolidation.cpp \
|
||||||
|
wallet/asyncrpcoperation_sweep.cpp \
|
||||||
wallet/asyncrpcoperation_sendmany.cpp \
|
wallet/asyncrpcoperation_sendmany.cpp \
|
||||||
wallet/asyncrpcoperation_shieldcoinbase.cpp \
|
wallet/asyncrpcoperation_shieldcoinbase.cpp \
|
||||||
wallet/crypter.cpp \
|
wallet/crypter.cpp \
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2014 The Bitcoin Core developers
|
// Copyright (c) 2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2022 The Hush developers
|
||||||
// Copyright (c) 2018 The Zcash developers
|
// Copyright (c) 2018 The Zcash developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
@@ -17,8 +18,8 @@
|
|||||||
* *
|
* *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifndef ZCASH_CONSENSUS_UPGRADES_H
|
#ifndef HUSH_CONSENSUS_UPGRADES_H
|
||||||
#define ZCASH_CONSENSUS_UPGRADES_H
|
#define HUSH_CONSENSUS_UPGRADES_H
|
||||||
|
|
||||||
#include "consensus/params.h"
|
#include "consensus/params.h"
|
||||||
|
|
||||||
@@ -114,4 +115,4 @@ boost::optional<int> NextActivationHeight(
|
|||||||
int nHeight,
|
int nHeight,
|
||||||
const Consensus::Params& params);
|
const Consensus::Params& params);
|
||||||
|
|
||||||
#endif // ZCASH_CONSENSUS_UPGRADES_H
|
#endif // HUSH_CONSENSUS_UPGRADES_H
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2022 The Hush developers
|
||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
|
|
||||||
namespace fsbridge {
|
namespace fsbridge {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright © 2014-2019 The SuperNET Developers. *
|
* Copyright © 2014-2019 The SuperNET Developers. *
|
||||||
* *
|
* *
|
||||||
|
|||||||
115
src/init.cpp
115
src/init.cpp
@@ -59,6 +59,7 @@
|
|||||||
#include "wallet/wallet.h"
|
#include "wallet/wallet.h"
|
||||||
#include "wallet/walletdb.h"
|
#include "wallet/walletdb.h"
|
||||||
#include "wallet/asyncrpcoperation_saplingconsolidation.h"
|
#include "wallet/asyncrpcoperation_saplingconsolidation.h"
|
||||||
|
#include "wallet/asyncrpcoperation_sweep.h"
|
||||||
#endif
|
#endif
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -444,6 +445,17 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||||||
strUsage += HelpMessageOpt("-consolidation", _("Enable auto Sapling note consolidation (default: false)"));
|
strUsage += HelpMessageOpt("-consolidation", _("Enable auto Sapling note consolidation (default: false)"));
|
||||||
strUsage += HelpMessageOpt("-consolidatesaplingaddress=<zaddr>", _("Specify Sapling Address to Consolidate. (default: all)"));
|
strUsage += HelpMessageOpt("-consolidatesaplingaddress=<zaddr>", _("Specify Sapling Address to Consolidate. (default: all)"));
|
||||||
strUsage += HelpMessageOpt("-consolidationtxfee", strprintf(_("Fee amount in Puposhis used send consolidation transactions. (default %i)"), DEFAULT_CONSOLIDATION_FEE));
|
strUsage += HelpMessageOpt("-consolidationtxfee", strprintf(_("Fee amount in Puposhis used send consolidation transactions. (default %i)"), DEFAULT_CONSOLIDATION_FEE));
|
||||||
|
|
||||||
|
strUsage += HelpMessageOpt("-zsweep", _("Enable zaddr sweeping, automatically move all shielded funds to a one address once per X blocks"));
|
||||||
|
strUsage += HelpMessageOpt("-zsweepaddress=<zaddr>", _("Specify the shielded address where swept funds will be sent)"));
|
||||||
|
strUsage += HelpMessageOpt("-zsweepfee", strprintf(_("Fee amount in puposhis used send sweep transactions. (default %i)"), DEFAULT_SWEEP_FEE));
|
||||||
|
strUsage += HelpMessageOpt("-zsweepinterval", strprintf(_("Sweep shielded funds every X blocks (default %i)"), 5));
|
||||||
|
strUsage += HelpMessageOpt("-zsweepmaxinputs", strprintf(_("Maximum number of shielded inputs to sweep per transaction (default %i)"), 8));
|
||||||
|
// By default we only allow sweeping to the current wallet which must have the spending key of the sweep zaddr
|
||||||
|
// This hopefully will make it harder for people to accidentally sweep funds to a wrong zaddr and lose funds
|
||||||
|
strUsage += HelpMessageOpt("-zsweepexternal", _("Enable sweeping to an external wallet (default false)"));
|
||||||
|
strUsage += HelpMessageOpt("-zsweepexclude", _("Addresses to exclude from sweeping (default none)"));
|
||||||
|
|
||||||
strUsage += HelpMessageOpt("-deletetx", _("Enable Old Transaction Deletion"));
|
strUsage += HelpMessageOpt("-deletetx", _("Enable Old Transaction Deletion"));
|
||||||
strUsage += HelpMessageOpt("-deleteinterval", strprintf(_("Delete transaction every <n> blocks during inital block download (default: %i)"), DEFAULT_TX_DELETE_INTERVAL));
|
strUsage += HelpMessageOpt("-deleteinterval", strprintf(_("Delete transaction every <n> blocks during inital block download (default: %i)"), DEFAULT_TX_DELETE_INTERVAL));
|
||||||
strUsage += HelpMessageOpt("-keeptxnum", strprintf(_("Keep the last <n> transactions (default: %i)"), DEFAULT_TX_RETENTION_LASTTX));
|
strUsage += HelpMessageOpt("-keeptxnum", strprintf(_("Keep the last <n> transactions (default: %i)"), DEFAULT_TX_RETENTION_LASTTX));
|
||||||
@@ -2008,16 +2020,101 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
|
|
||||||
//Set Sapling Consolidation
|
//Set Sapling Consolidation
|
||||||
pwalletMain->fSaplingConsolidationEnabled = GetBoolArg("-consolidation", false);
|
pwalletMain->fSaplingConsolidationEnabled = GetBoolArg("-consolidation", false);
|
||||||
fConsolidationTxFee = GetArg("-consolidationtxfee", DEFAULT_CONSOLIDATION_FEE);
|
if(pwalletMain->fSaplingConsolidationEnabled) {
|
||||||
fConsolidationMapUsed = !mapMultiArgs["-consolidatesaplingaddress"].empty();
|
fConsolidationTxFee = GetArg("-consolidationtxfee", DEFAULT_CONSOLIDATION_FEE);
|
||||||
|
fConsolidationMapUsed = !mapMultiArgs["-consolidatesaplingaddress"].empty();
|
||||||
|
|
||||||
//Validate Sapling Addresses
|
int consolidationInterval = GetArg("-consolidationinterval", 25);
|
||||||
vector<string>& vaddresses = mapMultiArgs["-consolidatesaplingaddress"];
|
if (consolidationInterval < 5) {
|
||||||
for (int i = 0; i < vaddresses.size(); i++) {
|
fprintf(stderr,"%s: Invalid consolidation interval of %d < 5, setting to default of 25\n", __func__, consolidationInterval);
|
||||||
LogPrintf("Consolidating Sapling Address: %s\n", vaddresses[i]);
|
consolidationInterval = 25;
|
||||||
auto zAddress = DecodePaymentAddress(vaddresses[i]);
|
}
|
||||||
if (!IsValidPaymentAddress(zAddress)) {
|
|
||||||
return InitError("Invalid consolidation address");
|
pwalletMain->consolidationInterval = consolidationInterval;
|
||||||
|
pwalletMain->nextConsolidation = pwalletMain->consolidationInterval + chainActive.Tip()->GetHeight();
|
||||||
|
LogPrintf("%s: set nextConsolidation=%d\n", __func__, pwalletMain->nextConsolidation );
|
||||||
|
|
||||||
|
//Validate Sapling Addresses
|
||||||
|
vector<string>& vaddresses = mapMultiArgs["-consolidatesaplingaddress"];
|
||||||
|
for (int i = 0; i < vaddresses.size(); i++) {
|
||||||
|
LogPrintf("Consolidating Sapling Address: %s\n", vaddresses[i]);
|
||||||
|
auto zAddress = DecodePaymentAddress(vaddresses[i]);
|
||||||
|
if (!IsValidPaymentAddress(zAddress)) {
|
||||||
|
return InitError("Invalid consolidation address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set Sweep
|
||||||
|
pwalletMain->fSweepEnabled = GetBoolArg("-zsweep", false);
|
||||||
|
|
||||||
|
if (pwalletMain->fSweepEnabled) {
|
||||||
|
int sweepInterval = GetArg("-zsweepinterval", 10);
|
||||||
|
if (sweepInterval < 5) {
|
||||||
|
fprintf(stderr,"%s: Invalid sweep interval of %d, setting to default of 10\n", __func__, sweepInterval);
|
||||||
|
sweepInterval = 10;
|
||||||
|
}
|
||||||
|
pwalletMain->sweepInterval = sweepInterval;
|
||||||
|
pwalletMain->nextSweep = pwalletMain->sweepInterval + chainActive.Tip()->GetHeight();
|
||||||
|
LogPrintf("%s: set nextSweep=%d with sweepInterval=%d\n", __func__, pwalletMain->nextSweep, pwalletMain->sweepInterval );
|
||||||
|
fSweepTxFee = GetArg("-zsweepfee", DEFAULT_SWEEP_FEE);
|
||||||
|
fSweepMapUsed = !mapMultiArgs["-zsweepaddress"].empty();
|
||||||
|
|
||||||
|
//Validate Sapling Addresses
|
||||||
|
vector<string>& vSweep = mapMultiArgs["-zsweepaddress"];
|
||||||
|
vector<string>& vSweepExclude = mapMultiArgs["-zsweepexclude"];
|
||||||
|
if (vSweep.size() != 1) {
|
||||||
|
return InitError("A single zsweep address must be specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < vSweep.size(); i++) {
|
||||||
|
// LogPrintf("Sweep Address: %s\n", vSweep[i]);
|
||||||
|
auto zSweep = DecodePaymentAddress(vSweep[i]);
|
||||||
|
if (!IsValidPaymentAddress(zSweep)) {
|
||||||
|
return InitError("Invalid zsweep address");
|
||||||
|
}
|
||||||
|
auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zSweep);
|
||||||
|
auto allowSweepToExternalWallet = GetArg("-zsweepexternal", false);
|
||||||
|
pwalletMain->sweepAddress = vSweep[i];
|
||||||
|
|
||||||
|
if (!hasSpendingKey) {
|
||||||
|
if (allowSweepToExternalWallet) {
|
||||||
|
LogPrintf("%s: sweeping funds to a zaddr in an external wallet\n", __func__);
|
||||||
|
} else {
|
||||||
|
return InitError("Wallet must have the spending key of zsweep address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < vSweepExclude.size(); i++) {
|
||||||
|
LogPrintf("Sweep Excluded Address: %s\n", vSweepExclude[i]);
|
||||||
|
auto zSweepExcluded = DecodePaymentAddress(vSweepExclude[i]);
|
||||||
|
if (!IsValidPaymentAddress(zSweepExcluded)) {
|
||||||
|
return InitError("Invalid zsweepexclude address");
|
||||||
|
}
|
||||||
|
auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zSweepExcluded);
|
||||||
|
|
||||||
|
if (!hasSpendingKey) {
|
||||||
|
return InitError("Wallet must have the spending key of zsweepexclude address");
|
||||||
|
}
|
||||||
|
// Add this validated zaddr to the list of excluded sweep zaddrs
|
||||||
|
pwalletMain->sweepExcludeAddresses.push_back( vSweepExclude[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwalletMain->fSaplingConsolidationEnabled) {
|
||||||
|
//Validate 1 Consolidation address only that matches the sweep address
|
||||||
|
vector<string>& vaddresses = mapMultiArgs["-consolidatesaplingaddress"];
|
||||||
|
if (vaddresses.size() == 0) {
|
||||||
|
fConsolidationMapUsed = true;
|
||||||
|
mapMultiArgs["-consolidatesaplingaddress"] = vSweep;
|
||||||
|
} else {
|
||||||
|
pwalletMain->consolidationAddress = vaddresses[0];
|
||||||
|
for (int i = 0; i < vaddresses.size(); i++) {
|
||||||
|
if (vSweep[0] != vaddresses[i]) {
|
||||||
|
return InitError("Consolidation can only be used on the sweep address when sweep is enabled.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Copyright (c) 2017 The Zcash developers
|
// Copyright (c) 2017 The Zcash developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
@@ -1304,10 +1304,12 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde
|
|||||||
// Check that all transactions are unexpired
|
// Check that all transactions are unexpired
|
||||||
if (IsExpiredTx(tx, nHeight)) {
|
if (IsExpiredTx(tx, nHeight)) {
|
||||||
// Don't increase banscore if the transaction only just expired
|
// Don't increase banscore if the transaction only just expired
|
||||||
int expiredDosLevel = IsExpiredTx(tx, nHeight - 1) ? (dosLevel > 10 ? dosLevel : 10) : 0;
|
//int expiredDosLevel = IsExpiredTx(tx, nHeight - 1) ? (dosLevel > 10 ? dosLevel : 10) : 0;
|
||||||
//string strHex = EncodeHexTx(tx);
|
//string strHex = EncodeHexTx(tx);
|
||||||
//fprintf(stderr, "transaction exipred.%s\n",strHex.c_str());
|
//fprintf(stderr, "transaction expired.%s\n",strHex.c_str());
|
||||||
return state.DoS(expiredDosLevel, error("ContextualCheckTransaction(): transaction %s is expired, expiry block %i vs current block %i\n",tx.GetHash().ToString(),tx.nExpiryHeight,nHeight), REJECT_INVALID, "tx-overwinter-expired");
|
|
||||||
|
// Do not ban nodes which relay expired tx's, it's a bug not an attack
|
||||||
|
return state.DoS(0, error("ContextualCheckTransaction(): transaction %s is expired, expiry block %i vs current block %i\n",tx.GetHash().ToString(),tx.nExpiryHeight,nHeight), REJECT_INVALID, "tx-overwinter-expired");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
10
src/net.cpp
10
src/net.cpp
@@ -2109,6 +2109,12 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
|
|||||||
|
|
||||||
auto vRelayNodes = vNodes;
|
auto vRelayNodes = vNodes;
|
||||||
|
|
||||||
|
// If we have no nodes to relay to, there is nothing to do
|
||||||
|
if(vNodes.size() == 0) {
|
||||||
|
fprintf(stderr, "%s: No nodes to relay to!\n", __func__ );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We always round down, except when we have only 1 connection
|
// We always round down, except when we have only 1 connection
|
||||||
auto newSize = (vNodes.size() / 2) == 0 ? 1 : (vNodes.size() / 2);
|
auto newSize = (vNodes.size() / 2) == 0 ? 1 : (vNodes.size() / 2);
|
||||||
|
|
||||||
@@ -2125,6 +2131,10 @@ void RelayTransaction(const CTransaction& tx, const CDataStream& ss)
|
|||||||
// Only relay to randomly chosen 50% of peers
|
// Only relay to randomly chosen 50% of peers
|
||||||
BOOST_FOREACH(CNode* pnode, vRelayNodes)
|
BOOST_FOREACH(CNode* pnode, vRelayNodes)
|
||||||
{
|
{
|
||||||
|
//TODO: correct fix is to correctly LOCK vRelayNodes
|
||||||
|
if(!pnode)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(!pnode->fRelayTxes)
|
if(!pnode->fRelayTxes)
|
||||||
continue;
|
continue;
|
||||||
LOCK(pnode->cs_filter);
|
LOCK(pnode->cs_filter);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2010 Satoshi Nakamoto
|
// Copyright (c) 2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
@@ -472,6 +472,8 @@ extern UniValue z_getbalance(const UniValue& params, bool fHelp, const CPubKey&
|
|||||||
extern UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
extern UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||||
extern UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
extern UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||||
extern UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
extern UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_sweepstatus(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||||
|
extern UniValue z_consolidationstatus(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||||
extern UniValue z_shieldcoinbase(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
extern UniValue z_shieldcoinbase(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||||
extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||||
extern UniValue z_getoperationresult(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
extern UniValue z_getoperationresult(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2015 The Bitcoin Core developers
|
// Copyright (c) 2015 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ bool TransactionBuilder::AddOpRetLast()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TransactionBuilder::SetExpiryHeight(int nHeight)
|
||||||
|
{
|
||||||
|
this->mtx.nExpiryHeight = nHeight;
|
||||||
|
}
|
||||||
|
|
||||||
void TransactionBuilder::AddOpRet(CScript &s)
|
void TransactionBuilder::AddOpRet(CScript &s)
|
||||||
{
|
{
|
||||||
opReturn.emplace(CScript(s));
|
opReturn.emplace(CScript(s));
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ public:
|
|||||||
TransactionBuilder(const Consensus::Params& consensusParams, int nHeight, CKeyStore* keyStore = nullptr);
|
TransactionBuilder(const Consensus::Params& consensusParams, int nHeight, CKeyStore* keyStore = nullptr);
|
||||||
|
|
||||||
void SetFee(CAmount fee);
|
void SetFee(CAmount fee);
|
||||||
|
void SetExpiryHeight(int nHeight);
|
||||||
|
|
||||||
// Returns false if the anchor does not match the anchor used by
|
// Returns false if the anchor does not match the anchor used by
|
||||||
// previously-added Sapling spends.
|
// previously-added Sapling spends.
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
@@ -19,9 +20,7 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include "uint256.h"
|
#include "uint256.h"
|
||||||
|
|
||||||
#include "utilstrencodings.h"
|
#include "utilstrencodings.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Copyright (c) 2016-2021 The Hush developers
|
||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||||
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
|||||||
@@ -16,6 +16,12 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "utilmoneystr.h"
|
#include "utilmoneystr.h"
|
||||||
#include "wallet.h"
|
#include "wallet.h"
|
||||||
|
#include <boost/stacktrace.hpp>
|
||||||
|
#include <boost/exception/all.hpp>
|
||||||
|
|
||||||
|
// enable function names and line numbers in backtraces
|
||||||
|
#define BOOST_STACKTRACE_LINK
|
||||||
|
#define BOOST_STACKTRACE_USE_ADDR2LINE
|
||||||
|
|
||||||
CAmount fConsolidationTxFee = DEFAULT_CONSOLIDATION_FEE;
|
CAmount fConsolidationTxFee = DEFAULT_CONSOLIDATION_FEE;
|
||||||
bool fConsolidationMapUsed = false;
|
bool fConsolidationMapUsed = false;
|
||||||
@@ -44,6 +50,8 @@ void AsyncRPCOperation_saplingconsolidation::main() {
|
|||||||
set_error_code(code);
|
set_error_code(code);
|
||||||
set_error_message(message);
|
set_error_message(message);
|
||||||
} catch (const runtime_error& e) {
|
} catch (const runtime_error& e) {
|
||||||
|
std::cerr << "Consolidation stacktrace:" << '\n' << boost::stacktrace::stacktrace() << '\n';
|
||||||
|
set_error_code(-1);
|
||||||
set_error_code(-1);
|
set_error_code(-1);
|
||||||
set_error_message("runtime error: " + string(e.what()));
|
set_error_message("runtime error: " + string(e.what()));
|
||||||
} catch (const logic_error& e) {
|
} catch (const logic_error& e) {
|
||||||
@@ -65,7 +73,7 @@ void AsyncRPCOperation_saplingconsolidation::main() {
|
|||||||
set_state(OperationStatus::FAILED);
|
set_state(OperationStatus::FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string s = strprintf("%s: Sapling Consolidation transaction created. (status=%s", getId(), getStateAsString());
|
std::string s = strprintf("%s: Sapling Consolidation operation complete. (status=%s", getId(), getStateAsString());
|
||||||
if (success) {
|
if (success) {
|
||||||
s += strprintf(", success)\n");
|
s += strprintf(", success)\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -78,11 +86,11 @@ void AsyncRPCOperation_saplingconsolidation::main() {
|
|||||||
bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
||||||
bool status=true;
|
bool status=true;
|
||||||
auto opid=getId();
|
auto opid=getId();
|
||||||
LogPrintf("%s: Beginning AsyncRPCOperation_saplingconsolidation.\n", __func__, opid);
|
LogPrintf("%s: Beginning AsyncRPCOperation_saplingconsolidation\n", opid);
|
||||||
auto consensusParams = Params().GetConsensus();
|
auto consensusParams = Params().GetConsensus();
|
||||||
auto nextActivationHeight = NextActivationHeight(targetHeight_, consensusParams);
|
auto nextActivationHeight = NextActivationHeight(targetHeight_, consensusParams);
|
||||||
if (nextActivationHeight && targetHeight_ + CONSOLIDATION_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
if (nextActivationHeight && targetHeight_ + CONSOLIDATION_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
||||||
LogPrint("zrpcunsafe", "%s: Consolidation txs would be created before a NU activation but may expire after. Skipping this round.\n",opid);
|
LogPrintf("%s: Consolidation txs would be created before a NU activation but may expire after. Skipping this round.\n",opid);
|
||||||
setConsolidationResult(0, 0, std::vector<std::string>());
|
setConsolidationResult(0, 0, std::vector<std::string>());
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -97,7 +105,7 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
|||||||
pwalletMain->GetFilteredNotes(saplingEntries, "", 11);
|
pwalletMain->GetFilteredNotes(saplingEntries, "", 11);
|
||||||
|
|
||||||
if(saplingEntries.size() == 0) {
|
if(saplingEntries.size() == 0) {
|
||||||
LogPrint("zrpcunsafe", "%s: Nothing to consolidate, done.\n",opid);
|
LogPrintf("%s: Nothing to consolidate, done.\n",opid);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +117,7 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
|||||||
libzcash::SaplingPaymentAddress saplingAddress = boost::get<libzcash::SaplingPaymentAddress>(zAddress);
|
libzcash::SaplingPaymentAddress saplingAddress = boost::get<libzcash::SaplingPaymentAddress>(zAddress);
|
||||||
addresses.insert(saplingAddress);
|
addresses.insert(saplingAddress);
|
||||||
} else {
|
} else {
|
||||||
LogPrint("zrpcunsafe", "%s: Invalid zaddr, exiting\n", opid);
|
LogPrintf("%s: Invalid zaddr, exiting\n", opid);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,9 +165,8 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
|||||||
if (fromNotes.size() < minQuantity)
|
if (fromNotes.size() < minQuantity)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
amountConsolidated += amountToSend;
|
|
||||||
auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain);
|
auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain);
|
||||||
//builder.SetExpiryHeight(targetHeight_ + CONSOLIDATION_EXPIRY_DELTA);
|
builder.SetExpiryHeight(targetHeight_ + CONSOLIDATION_EXPIRY_DELTA);
|
||||||
auto actualAmountToSend = amountToSend < fConsolidationTxFee ? 0 : amountToSend - fConsolidationTxFee;
|
auto actualAmountToSend = amountToSend < fConsolidationTxFee ? 0 : amountToSend - fConsolidationTxFee;
|
||||||
LogPrintf("%s: %s Beginning to create transaction with Sapling output amount=%s\n", __func__, opid, FormatMoney(actualAmountToSend));
|
LogPrintf("%s: %s Beginning to create transaction with Sapling output amount=%s\n", __func__, opid, FormatMoney(actualAmountToSend));
|
||||||
|
|
||||||
@@ -176,14 +183,14 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
|||||||
std::vector<boost::optional<SaplingWitness>> witnesses;
|
std::vector<boost::optional<SaplingWitness>> witnesses;
|
||||||
{
|
{
|
||||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
LogPrint("zrpcunsafe", "%s: Fetching note witnesses\n", opid);
|
// LogPrint("zrpcunsafe", "%s: Fetching note witnesses\n", opid);
|
||||||
pwalletMain->GetSaplingNoteWitnesses(ops, witnesses, anchor);
|
pwalletMain->GetSaplingNoteWitnesses(ops, witnesses, anchor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add Sapling spends
|
// Add Sapling spends
|
||||||
for (size_t i = 0; i < notes.size(); i++) {
|
for (size_t i = 0; i < notes.size(); i++) {
|
||||||
if (!witnesses[i]) {
|
if (!witnesses[i]) {
|
||||||
LogPrint("zrpcunsafe", "%s: Missing Witnesses. Stopping.\n", opid);
|
LogPrintf("%s: Missing Witnesses! Stopping.\n", opid);
|
||||||
status=false;
|
status=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -213,35 +220,33 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
|||||||
// actually add our sietch zoutput, the new way
|
// actually add our sietch zoutput, the new way
|
||||||
builder.AddSaplingOutput(extsk.expsk.ovk, sietchZoutput, amount);
|
builder.AddSaplingOutput(extsk.expsk.ovk, sietchZoutput, amount);
|
||||||
} else {
|
} else {
|
||||||
LogPrint("zrpcunsafe", "%s: Invalid payment address %s! Stopping.\n", opid, zdust);
|
LogPrintf("%s: Invalid payment address %s! Stopping.\n", opid, zdust);
|
||||||
status = false;
|
status = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LogPrint("zrpcunsafe", "%s: Done adding %d sietch zouts\n", opid, MIN_ZOUTS);
|
LogPrint("zrpcunsafe", "%s: Done adding %d sietch zouts\n", opid, MIN_ZOUTS);
|
||||||
//CTransaction tx = builder.Build();
|
|
||||||
|
|
||||||
auto maybe_tx = builder.Build();
|
auto maybe_tx = builder.Build();
|
||||||
if (!maybe_tx) {
|
if (!maybe_tx) {
|
||||||
LogPrint("zrpcunsafe", "%s: Failed to build transaction.\n",opid);
|
LogPrintf("%s: Failed to build transaction.\n",opid);
|
||||||
status=false;
|
status=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CTransaction tx = maybe_tx.get();
|
CTransaction tx = maybe_tx.get();
|
||||||
|
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
LogPrint("zrpcunsafe", "%s: Canceled. Stopping.\n", opid);
|
LogPrintf("%s: Canceled. Stopping.\n", opid);
|
||||||
status=false;
|
status=false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pwalletMain->CommitConsolidationTx(tx)) {
|
if(pwalletMain->CommitAutomatedTx(tx)) {
|
||||||
LogPrint("zrpcunsafe", "%s: Committed consolidation transaction with txid=%s\n",opid, tx.GetHash().ToString());
|
LogPrintf("%s: Committed consolidation transaction with txid=%s\n",opid, tx.GetHash().ToString());
|
||||||
amountConsolidated += actualAmountToSend;
|
amountConsolidated += actualAmountToSend;
|
||||||
consolidationTxIds.push_back(tx.GetHash().ToString());
|
consolidationTxIds.push_back(tx.GetHash().ToString());
|
||||||
numTxCreated++;
|
numTxCreated++;
|
||||||
} else {
|
} else {
|
||||||
LogPrint("zrpcunsafe", "%s: Consolidation transaction FAILED in CommitTransaction, txid=%s\n",opid , tx.GetHash().ToString());
|
LogPrintf("%s: Consolidation transaction FAILED in CommitTransaction, txid=%s\n",opid , tx.GetHash().ToString());
|
||||||
setConsolidationResult(numTxCreated, amountConsolidated, consolidationTxIds);
|
setConsolidationResult(numTxCreated, amountConsolidated, consolidationTxIds);
|
||||||
status = false;
|
status = false;
|
||||||
break;
|
break;
|
||||||
@@ -249,7 +254,7 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogPrint("zrpcunsafe", "%s: Created %d transactions with total Sapling output amount=%s,status=%d\n",opid , numTxCreated, FormatMoney(amountConsolidated), (int)status);
|
LogPrintf("%s: Created %d transactions with total Sapling output amount=%s,status=%d\n",opid , numTxCreated, FormatMoney(amountConsolidated), (int)status);
|
||||||
setConsolidationResult(numTxCreated, amountConsolidated, consolidationTxIds);
|
setConsolidationResult(numTxCreated, amountConsolidated, consolidationTxIds);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|||||||
349
src/wallet/asyncrpcoperation_sweep.cpp
Normal file
349
src/wallet/asyncrpcoperation_sweep.cpp
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
// Copyright (c) 2016-2022 The Hush developers
|
||||||
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
#include "assert.h"
|
||||||
|
#include "boost/variant/static_visitor.hpp"
|
||||||
|
#include "asyncrpcoperation_sweep.h"
|
||||||
|
#include "init.h"
|
||||||
|
#include "key_io.h"
|
||||||
|
#include "rpc/protocol.h"
|
||||||
|
#include "random.h"
|
||||||
|
#include "sync.h"
|
||||||
|
#include "tinyformat.h"
|
||||||
|
#include "transaction_builder.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "utilmoneystr.h"
|
||||||
|
#include "wallet.h"
|
||||||
|
|
||||||
|
extern string randomSietchZaddr();
|
||||||
|
|
||||||
|
CAmount fSweepTxFee = DEFAULT_SWEEP_FEE;
|
||||||
|
bool fSweepMapUsed = false;
|
||||||
|
const int SWEEP_EXPIRY_DELTA = 15;
|
||||||
|
boost::optional<libzcash::SaplingPaymentAddress> rpcSweepAddress;
|
||||||
|
|
||||||
|
AsyncRPCOperation_sweep::AsyncRPCOperation_sweep(int targetHeight, bool fromRpc) : targetHeight_(targetHeight), fromRPC_(fromRpc){}
|
||||||
|
|
||||||
|
AsyncRPCOperation_sweep::~AsyncRPCOperation_sweep() {}
|
||||||
|
|
||||||
|
void AsyncRPCOperation_sweep::main() {
|
||||||
|
if (isCancelled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
set_state(OperationStatus::EXECUTING);
|
||||||
|
start_execution_clock();
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
success = main_impl();
|
||||||
|
} catch (const UniValue& objError) {
|
||||||
|
int code = find_value(objError, "code").get_int();
|
||||||
|
std::string message = find_value(objError, "message").get_str();
|
||||||
|
set_error_code(code);
|
||||||
|
set_error_message(message);
|
||||||
|
} catch (const runtime_error& e) {
|
||||||
|
set_error_code(-1);
|
||||||
|
set_error_message("runtime error: " + string(e.what()));
|
||||||
|
} catch (const logic_error& e) {
|
||||||
|
set_error_code(-1);
|
||||||
|
set_error_message("logic error: " + string(e.what()));
|
||||||
|
} catch (const exception& e) {
|
||||||
|
set_error_code(-1);
|
||||||
|
set_error_message("general exception: " + string(e.what()));
|
||||||
|
} catch (...) {
|
||||||
|
set_error_code(-2);
|
||||||
|
set_error_message("unknown error");
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_execution_clock();
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
set_state(OperationStatus::SUCCESS);
|
||||||
|
} else {
|
||||||
|
set_state(OperationStatus::FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string s = strprintf("%s: Sweep operation finished. (status=%s", getId(), getStateAsString());
|
||||||
|
if (success) {
|
||||||
|
s += strprintf(", success)\n");
|
||||||
|
} else {
|
||||||
|
s += strprintf(", error=%s)\n", getErrorMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
LogPrintf("%s", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is this zaddr excluded from zsweep ?
|
||||||
|
bool IsExcludedAddress(libzcash::SaplingPaymentAddress zaddr) {
|
||||||
|
for( auto & sweepExcludeAddress : pwalletMain->sweepExcludeAddresses ) {
|
||||||
|
auto zAddressExclude = DecodePaymentAddress(sweepExcludeAddress);
|
||||||
|
|
||||||
|
if (boost::get<libzcash::SaplingPaymentAddress>(&zAddressExclude) != nullptr) {
|
||||||
|
auto excludeAddress = boost::get<libzcash::SaplingPaymentAddress>(zAddressExclude);
|
||||||
|
if (excludeAddress == zaddr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This is an invalid sapling zaddr
|
||||||
|
LogPrintf("%s: Invalid zsweepexclude zaddr %s, ignoring\n", sweepExcludeAddress);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AsyncRPCOperation_sweep::main_impl() {
|
||||||
|
bool status=true;
|
||||||
|
auto opid=getId();
|
||||||
|
LogPrintf("%s: Beginning asyncrpcoperation_sweep.\n", getId());
|
||||||
|
auto consensusParams = Params().GetConsensus();
|
||||||
|
auto nextActivationHeight = NextActivationHeight(targetHeight_, consensusParams);
|
||||||
|
if (nextActivationHeight && targetHeight_ + SWEEP_EXPIRY_DELTA >= nextActivationHeight.get()) {
|
||||||
|
LogPrintf("%s: Sweep txs would be created before a NU activation but may expire after. Skipping this round.\n", getId());
|
||||||
|
setSweepResult(0, 0, std::vector<std::string>());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SaplingNoteEntry> saplingEntries;
|
||||||
|
libzcash::SaplingPaymentAddress sweepAddress;
|
||||||
|
std::map<libzcash::SaplingPaymentAddress, std::vector<SaplingNoteEntry>> mapAddresses;
|
||||||
|
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
pwalletMain->GetFilteredNotes(saplingEntries, "", 11);
|
||||||
|
|
||||||
|
if (!fromRPC_) {
|
||||||
|
if (fSweepMapUsed) {
|
||||||
|
const vector<string>& v = mapMultiArgs["-zsweepaddress"];
|
||||||
|
for(int i = 0; i < v.size(); i++) {
|
||||||
|
auto zAddress = DecodePaymentAddress(v[i]);
|
||||||
|
if (boost::get<libzcash::SaplingPaymentAddress>(&zAddress) != nullptr) {
|
||||||
|
sweepAddress = boost::get<libzcash::SaplingPaymentAddress>(zAddress);
|
||||||
|
} else {
|
||||||
|
LogPrintf("%s: Invalid zsweepaddress configured, exiting\n", opid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LogPrintf("%s: No zsweepaddress configured, exiting\n", opid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (boost::get<libzcash::SaplingPaymentAddress>(&rpcSweepAddress) != nullptr) {
|
||||||
|
sweepAddress = boost::get<libzcash::SaplingPaymentAddress>(rpcSweepAddress);
|
||||||
|
} else {
|
||||||
|
LogPrintf("%s: Invalid zsweepaddress, exiting\n", opid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map all notes (zutxos) by address
|
||||||
|
for (auto & entry : saplingEntries) {
|
||||||
|
// do not need to sweep Excluded Addresses
|
||||||
|
if(IsExcludedAddress(entry.address)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do not need to sweep the sweepAddress as that is the destination
|
||||||
|
if (sweepAddress == entry.address) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
std::map<libzcash::SaplingPaymentAddress, std::vector<SaplingNoteEntry>>::iterator it;
|
||||||
|
it = mapAddresses.find(entry.address);
|
||||||
|
if (it != mapAddresses.end()) {
|
||||||
|
it->second.push_back(entry);
|
||||||
|
} else {
|
||||||
|
std::vector<SaplingNoteEntry> entries;
|
||||||
|
entries.push_back(entry);
|
||||||
|
mapAddresses[entry.address] = entries;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int numTxCreated = 0;
|
||||||
|
std::vector<std::string> sweepTxIds;
|
||||||
|
CAmount amountSwept = 0;
|
||||||
|
CCoinsViewCache coinsView(pcoinsTip);
|
||||||
|
bool sweepComplete = true;
|
||||||
|
|
||||||
|
for (std::map<libzcash::SaplingPaymentAddress, std::vector<SaplingNoteEntry>>::iterator it = mapAddresses.begin(); it != mapAddresses.end(); it++) {
|
||||||
|
auto addr = (*it).first;
|
||||||
|
auto saplingEntries = (*it).second;
|
||||||
|
|
||||||
|
libzcash::SaplingExtendedSpendingKey extsk;
|
||||||
|
if (pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk)) {
|
||||||
|
|
||||||
|
std::vector<SaplingNoteEntry> fromNotes;
|
||||||
|
CAmount amountToSend = 0;
|
||||||
|
int maxInputs = GetArg("-zsweepmaxinputs", 8);
|
||||||
|
if( maxInputs > 100 || maxInputs < 5) {
|
||||||
|
fprintf(stderr,"%s: Invalid zsweep maxinputs=%d is >100 and <5, setting to default of 8\n", __func__, maxInputs);
|
||||||
|
maxInputs = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Count Notes availiable for this address
|
||||||
|
int targetCount = 0;
|
||||||
|
int noteCount = 0;
|
||||||
|
for (const SaplingNoteEntry& saplingEntry : saplingEntries) {
|
||||||
|
|
||||||
|
libzcash::SaplingIncomingViewingKey ivk;
|
||||||
|
pwalletMain->GetSaplingIncomingViewingKey(boost::get<libzcash::SaplingPaymentAddress>(saplingEntry.address), ivk);
|
||||||
|
|
||||||
|
if (ivk == extsk.expsk.full_viewing_key().in_viewing_key() && saplingEntry.address == addr) {
|
||||||
|
noteCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Don't sweep if under the threshold
|
||||||
|
if (noteCount <= targetCount){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we make it here then we need to sweep and the routine is considered incomplete
|
||||||
|
sweepComplete = false;
|
||||||
|
|
||||||
|
for (const SaplingNoteEntry& saplingEntry : saplingEntries) {
|
||||||
|
|
||||||
|
libzcash::SaplingIncomingViewingKey ivk;
|
||||||
|
pwalletMain->GetSaplingIncomingViewingKey(boost::get<libzcash::SaplingPaymentAddress>(saplingEntry.address), ivk);
|
||||||
|
|
||||||
|
//Select Notes from that same address we will be sending to.
|
||||||
|
if (ivk == extsk.expsk.full_viewing_key().in_viewing_key() && saplingEntry.address == addr) {
|
||||||
|
amountToSend += CAmount(saplingEntry.note.value());
|
||||||
|
fromNotes.push_back(saplingEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fromNotes.size() >= maxInputs)
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int minQuantity = 1;
|
||||||
|
if (fromNotes.size() < minQuantity)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CAmount fee = fSweepTxFee;
|
||||||
|
if (amountToSend <= fSweepTxFee) {
|
||||||
|
LogPrintf("%s: Amount to send %s is <= fee, using fee=0", getId(), FormatMoney(amountToSend));
|
||||||
|
fee = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain);
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
builder.SetExpiryHeight(chainActive.Tip()->GetHeight()+ SWEEP_EXPIRY_DELTA);
|
||||||
|
}
|
||||||
|
LogPrintf("%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), FormatMoney(amountToSend - fee));
|
||||||
|
|
||||||
|
// Select Sapling notes
|
||||||
|
std::vector<SaplingOutPoint> ops;
|
||||||
|
std::vector<libzcash::SaplingNote> notes;
|
||||||
|
for (auto fromNote : fromNotes) {
|
||||||
|
ops.push_back(fromNote.op);
|
||||||
|
notes.push_back(fromNote.note);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch Sapling anchor and witnesses
|
||||||
|
uint256 anchor;
|
||||||
|
std::vector<boost::optional<SaplingWitness>> witnesses;
|
||||||
|
{
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
pwalletMain->GetSaplingNoteWitnesses(ops, witnesses, anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Sapling spends
|
||||||
|
for (size_t i = 0; i < notes.size(); i++) {
|
||||||
|
if (!witnesses[i]) {
|
||||||
|
LogPrintf("%s: Missing Witnesses! Stopping.\n", getId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
builder.AddSaplingSpend(extsk.expsk, notes[i], anchor, witnesses[i].get());
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.SetFee(fee);
|
||||||
|
builder.AddSaplingOutput(extsk.expsk.ovk, sweepAddress, amountToSend - fee);
|
||||||
|
|
||||||
|
// Add sietch zouts
|
||||||
|
int ZOUTS = 7;
|
||||||
|
for(size_t i = 0; i < ZOUTS; i++) {
|
||||||
|
// In Privacy Zdust We Trust -- Duke
|
||||||
|
string zdust = randomSietchZaddr();
|
||||||
|
auto zaddr = DecodePaymentAddress(zdust);
|
||||||
|
if (IsValidPaymentAddress(zaddr)) {
|
||||||
|
CAmount amount=0;
|
||||||
|
auto sietchZoutput = boost::get<libzcash::SaplingPaymentAddress>(zaddr);
|
||||||
|
LogPrint("zrpcunsafe", "%s: Adding Sietch zdust output %d\n", __func__, i); // %d %s amount=%li\n", __func__, i, zaddr, amount);
|
||||||
|
|
||||||
|
builder.AddSaplingOutput(extsk.expsk.ovk, sietchZoutput, amount);
|
||||||
|
} else {
|
||||||
|
LogPrintf("%s: Invalid payment address %s! Stopping.\n", __func__, zdust);
|
||||||
|
status = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LogPrint("zrpcunsafe", "%s: Done adding %d sietch zouts\n", __func__, ZOUTS);
|
||||||
|
|
||||||
|
auto maybe_tx = builder.Build();
|
||||||
|
if (!maybe_tx) {
|
||||||
|
LogPrintf("%s: Failed to build transaction %s.\n",__func__, getId());
|
||||||
|
status=false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CTransaction tx = maybe_tx.get();
|
||||||
|
|
||||||
|
if (isCancelled()) {
|
||||||
|
LogPrintf("%s: Canceled. Stopping.\n", getId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pwalletMain->CommitAutomatedTx(tx)) {
|
||||||
|
LogPrintf("%s: Committed sweep transaction with txid=%s\n", getId(), tx.GetHash().ToString());
|
||||||
|
amountSwept += amountToSend - fee;
|
||||||
|
sweepTxIds.push_back(tx.GetHash().ToString());
|
||||||
|
numTxCreated++;
|
||||||
|
} else {
|
||||||
|
LogPrintf("%s: Sweep transaction FAILED in CommitTransaction, txid=%s\n",opid , tx.GetHash().ToString());
|
||||||
|
setSweepResult(numTxCreated, amountSwept, sweepTxIds);
|
||||||
|
status = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sweepComplete) {
|
||||||
|
pwalletMain->nextSweep = pwalletMain->sweepInterval + chainActive.Tip()->GetHeight();
|
||||||
|
pwalletMain->fSweepRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogPrintf("%s: Created %d transactions with total output amount=%s, status=%d\n", getId(), numTxCreated, FormatMoney(amountSwept), (int)status);
|
||||||
|
setSweepResult(numTxCreated, amountSwept, sweepTxIds);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRPCOperation_sweep::setSweepResult(int numTxCreated, const CAmount& amountSwept, const std::vector<std::string>& sweepTxIds) {
|
||||||
|
UniValue res(UniValue::VOBJ);
|
||||||
|
res.push_back(Pair("num_tx_created", numTxCreated));
|
||||||
|
res.push_back(Pair("amount_swept", FormatMoney(amountSwept)));
|
||||||
|
UniValue txIds(UniValue::VARR);
|
||||||
|
for (const std::string& txId : sweepTxIds) {
|
||||||
|
txIds.push_back(txId);
|
||||||
|
}
|
||||||
|
res.push_back(Pair("sweep_txids", txIds));
|
||||||
|
set_result(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncRPCOperation_sweep::cancel() {
|
||||||
|
set_state(OperationStatus::CANCELLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
UniValue AsyncRPCOperation_sweep::getStatus() const {
|
||||||
|
UniValue v = AsyncRPCOperation::getStatus();
|
||||||
|
UniValue obj = v.get_obj();
|
||||||
|
obj.push_back(Pair("method", "sweep"));
|
||||||
|
obj.push_back(Pair("target_height", targetHeight_));
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
42
src/wallet/asyncrpcoperation_sweep.h
Normal file
42
src/wallet/asyncrpcoperation_sweep.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) 2016-2022 The Hush developers
|
||||||
|
// Distributed under the GPLv3 software license, see the accompanying
|
||||||
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
||||||
|
#include "amount.h"
|
||||||
|
#include "asyncrpcoperation.h"
|
||||||
|
#include "univalue.h"
|
||||||
|
#include "zcash/Address.hpp"
|
||||||
|
#include "zcash/zip32.h"
|
||||||
|
|
||||||
|
//Default fee used for sweep transactions
|
||||||
|
static const CAmount DEFAULT_SWEEP_FEE = 10000;
|
||||||
|
extern CAmount fSweepTxFee;
|
||||||
|
extern bool fSweepMapUsed;
|
||||||
|
extern boost::optional<libzcash::SaplingPaymentAddress> rpcSweepAddress;
|
||||||
|
|
||||||
|
class AsyncRPCOperation_sweep : public AsyncRPCOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AsyncRPCOperation_sweep(int targetHeight, bool fromRpc = false);
|
||||||
|
virtual ~AsyncRPCOperation_sweep();
|
||||||
|
|
||||||
|
// We don't want to be copied or moved around
|
||||||
|
AsyncRPCOperation_sweep(AsyncRPCOperation_sweep const&) = delete; // Copy construct
|
||||||
|
AsyncRPCOperation_sweep(AsyncRPCOperation_sweep&&) = delete; // Move construct
|
||||||
|
AsyncRPCOperation_sweep& operator=(AsyncRPCOperation_sweep const&) = delete; // Copy assign
|
||||||
|
AsyncRPCOperation_sweep& operator=(AsyncRPCOperation_sweep&&) = delete; // Move assign
|
||||||
|
|
||||||
|
virtual void main();
|
||||||
|
|
||||||
|
virtual void cancel();
|
||||||
|
|
||||||
|
virtual UniValue getStatus() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int targetHeight_;
|
||||||
|
bool fromRPC_;
|
||||||
|
|
||||||
|
bool main_impl();
|
||||||
|
|
||||||
|
void setSweepResult(int numTxCreated, const CAmount& amountSwept, const std::vector<std::string>& sweepTxIds);
|
||||||
|
|
||||||
|
};
|
||||||
@@ -3314,6 +3314,73 @@ UniValue getalldata(const UniValue& params, bool fHelp,const CPubKey&)
|
|||||||
return returnObj;
|
return returnObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UniValue z_consolidationstatus(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return NullUniValue;
|
||||||
|
|
||||||
|
if (fHelp || params.size() > 0)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_consolidationstatus\n"
|
||||||
|
"\nGive details about consolidation operations since the node was started."
|
||||||
|
"}\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_consolidationstatus", "")
|
||||||
|
+ HelpExampleRpc("z_consolidationstatus", "")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
UniValue ret(UniValue::VOBJ);
|
||||||
|
ret.push_back(Pair("consolidation", pwalletMain->fSaplingConsolidationEnabled));
|
||||||
|
ret.push_back(Pair("running", pwalletMain->fConsolidationRunning));
|
||||||
|
ret.push_back(Pair("amount_consolidated", pwalletMain->amountConsolidated));
|
||||||
|
ret.push_back(Pair("next_consolidation", pwalletMain->nextConsolidation));
|
||||||
|
ret.push_back(Pair("consolidationinterval", pwalletMain->consolidationInterval));
|
||||||
|
ret.push_back(Pair("consolidationaddress", pwalletMain->consolidationAddress));
|
||||||
|
ret.push_back(Pair("consolidationtxfee",(int)fConsolidationTxFee));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniValue z_sweepstatus(const UniValue& params, bool fHelp, const CPubKey& mypk)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
|
return NullUniValue;
|
||||||
|
|
||||||
|
if (fHelp || params.size() > 0)
|
||||||
|
throw runtime_error(
|
||||||
|
"z_sweepstatus\n"
|
||||||
|
"\nGive details about zsweep operations since the node was started."
|
||||||
|
"}\n"
|
||||||
|
"\nExamples:\n"
|
||||||
|
+ HelpExampleCli("z_sweepstatus", "")
|
||||||
|
+ HelpExampleRpc("z_sweepstatus", "")
|
||||||
|
);
|
||||||
|
|
||||||
|
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||||
|
|
||||||
|
UniValue ret(UniValue::VOBJ);
|
||||||
|
ret.push_back(Pair("zsweep", pwalletMain->fSweepEnabled));
|
||||||
|
ret.push_back(Pair("running", pwalletMain->fSweepRunning));
|
||||||
|
ret.push_back(Pair("amount_swept", pwalletMain->amountSwept));
|
||||||
|
ret.push_back(Pair("next_zsweep", pwalletMain->nextSweep));
|
||||||
|
ret.push_back(Pair("zsweepinterval", pwalletMain->sweepInterval));
|
||||||
|
ret.push_back(Pair("zsweepaddress", pwalletMain->sweepAddress));
|
||||||
|
UniValue excludes(UniValue::VARR);
|
||||||
|
BOOST_FOREACH(const std::string& exclude, pwalletMain->sweepExcludeAddresses ) {
|
||||||
|
excludes.push_back(exclude);
|
||||||
|
}
|
||||||
|
ret.push_back(Pair("zsweepexclude", excludes));
|
||||||
|
ret.push_back(Pair("zsweepmaxinputs", pwalletMain->sweepMaxInputs));
|
||||||
|
ret.push_back(Pair("zsweepfee", pwalletMain->sweepFee));
|
||||||
|
ret.push_back(Pair("zsweepexternal", pwalletMain->fSweepExternalEnabled));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&)
|
UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&)
|
||||||
{
|
{
|
||||||
if (!EnsureWalletIsAvailable(fHelp))
|
if (!EnsureWalletIsAvailable(fHelp))
|
||||||
@@ -8494,6 +8561,8 @@ static const CRPCCommand commands[] =
|
|||||||
{ "wallet", "z_anonsetblockdelta", &z_anonsetblockdelta, true },
|
{ "wallet", "z_anonsetblockdelta", &z_anonsetblockdelta, true },
|
||||||
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
|
{ "wallet", "z_gettotalbalance", &z_gettotalbalance, false },
|
||||||
{ "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
|
{ "wallet", "z_mergetoaddress", &z_mergetoaddress, false },
|
||||||
|
{ "wallet", "z_sweepstatus", &z_sweepstatus, true },
|
||||||
|
{ "wallet", "z_consolidationstatus", &z_consolidationstatus, true },
|
||||||
{ "wallet", "z_sendmany", &z_sendmany, false },
|
{ "wallet", "z_sendmany", &z_sendmany, false },
|
||||||
{ "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false },
|
{ "wallet", "z_shieldcoinbase", &z_shieldcoinbase, false },
|
||||||
{ "wallet", "z_getoperationstatus", &z_getoperationstatus, true },
|
{ "wallet", "z_getoperationstatus", &z_getoperationstatus, true },
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "crypter.h"
|
#include "crypter.h"
|
||||||
#include "coins.h"
|
#include "coins.h"
|
||||||
#include "wallet/asyncrpcoperation_saplingconsolidation.h"
|
#include "wallet/asyncrpcoperation_saplingconsolidation.h"
|
||||||
|
#include "wallet/asyncrpcoperation_sweep.h"
|
||||||
#include "zcash/zip32.h"
|
#include "zcash/zip32.h"
|
||||||
#include "cc/CCinclude.h"
|
#include "cc/CCinclude.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
@@ -483,6 +484,9 @@ void CWallet::ChainTip(const CBlockIndex *pindex,
|
|||||||
if (fSaplingConsolidationEnabled) {
|
if (fSaplingConsolidationEnabled) {
|
||||||
RunSaplingConsolidation(pindex->GetHeight());
|
RunSaplingConsolidation(pindex->GetHeight());
|
||||||
}
|
}
|
||||||
|
if (fSweepEnabled) {
|
||||||
|
RunSaplingSweep(pindex->GetHeight());
|
||||||
|
}
|
||||||
if (fTxDeleteEnabled) {
|
if (fTxDeleteEnabled) {
|
||||||
DeleteWalletTransactions(pindex);
|
DeleteWalletTransactions(pindex);
|
||||||
}
|
}
|
||||||
@@ -501,36 +505,84 @@ void CWallet::ChainTip(const CBlockIndex *pindex,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::RunSaplingConsolidation(int blockHeight) {
|
void CWallet::RunSaplingSweep(int blockHeight) {
|
||||||
if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
|
// Sapling is always active since height=1 of HUSH+HSCs
|
||||||
|
// if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
AssertLockHeld(cs_wallet);
|
||||||
|
if (!fSweepEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nextSweep > blockHeight) {
|
||||||
|
LogPrintf("%s: Not time to sweep yet at blockHeight=%d nextSweep=%d\n", __func__, blockHeight, nextSweep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LogPrintf("%s: Sweep enabled at blockHeight=%d nextSweep=%d\n", __func__, blockHeight, nextSweep);
|
||||||
|
|
||||||
|
//Don't Run if consolidation will run soon.
|
||||||
|
if (fSaplingConsolidationEnabled && nextConsolidation - 5 <= blockHeight) {
|
||||||
|
LogPrintf("%s: not sweeping since next consolidation is within 5 blocks, nextConsolidation=%d , blockHeight=%d\n", __func__, nextConsolidation, blockHeight);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Don't Run While consolidation is running.
|
||||||
|
if (fConsolidationRunning) {
|
||||||
|
LogPrintf("%s: not sweeping since consolidation is currently running at height=%d\n", __func__, blockHeight);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fSweepRunning = true;
|
||||||
|
|
||||||
|
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
|
||||||
|
std::shared_ptr<AsyncRPCOperation> lastOperation = q->getOperationForId(saplingSweepOperationId);
|
||||||
|
if (lastOperation != nullptr) {
|
||||||
|
lastOperation->cancel();
|
||||||
|
}
|
||||||
|
pendingSaplingSweepTxs.clear();
|
||||||
|
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_sweep(blockHeight + 5));
|
||||||
|
saplingSweepOperationId = operation->getId();
|
||||||
|
q->addOperation(operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWallet::RunSaplingConsolidation(int blockHeight) {
|
||||||
|
// Sapling is always active on HUSH+HSCs
|
||||||
|
//if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) {
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
|
||||||
LOCK(cs_wallet);
|
LOCK(cs_wallet);
|
||||||
|
|
||||||
if (!fSaplingConsolidationEnabled) {
|
if (!fSaplingConsolidationEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int consolidateInterval = rand() % 5 + 5;
|
if (nextConsolidation > blockHeight) {
|
||||||
|
LogPrintf("%s: Not time to consolidate yet at blockHeight=%d nextConsolidation=%d\n", __func__, blockHeight, nextConsolidation);
|
||||||
if(fZdebug)
|
return;
|
||||||
fprintf(stderr,"%s: height=%d interval=%d\n", __func__, blockHeight, consolidateInterval);
|
|
||||||
|
|
||||||
if (blockHeight % consolidateInterval == 0) {
|
|
||||||
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
|
|
||||||
std::shared_ptr<AsyncRPCOperation> lastOperation = q->getOperationForId(saplingConsolidationOperationId);
|
|
||||||
if (lastOperation != nullptr) {
|
|
||||||
lastOperation->cancel();
|
|
||||||
}
|
|
||||||
pendingSaplingConsolidationTxs.clear();
|
|
||||||
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_saplingconsolidation(blockHeight + 5));
|
|
||||||
saplingConsolidationOperationId = operation->getId();
|
|
||||||
q->addOperation(operation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LogPrintf("%s: consolidation enabled at blockHeight=%d fSweepRunning=%d\n", __func__, blockHeight, fSweepRunning );
|
||||||
|
|
||||||
|
if (fSweepRunning) {
|
||||||
|
LogPrintf("%s: not consolidating since sweep is currently running at height=%d\n", __func__, blockHeight);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogPrintf("%s: creating consolidation operation at blockHeight=%d\n", __func__, blockHeight);
|
||||||
|
std::shared_ptr<AsyncRPCQueue> q = getAsyncRPCQueue();
|
||||||
|
std::shared_ptr<AsyncRPCOperation> lastOperation = q->getOperationForId(saplingConsolidationOperationId);
|
||||||
|
if (lastOperation != nullptr) {
|
||||||
|
lastOperation->cancel();
|
||||||
|
}
|
||||||
|
pendingSaplingConsolidationTxs.clear();
|
||||||
|
std::shared_ptr<AsyncRPCOperation> operation(new AsyncRPCOperation_saplingconsolidation(blockHeight + 5));
|
||||||
|
saplingConsolidationOperationId = operation->getId();
|
||||||
|
q->addOperation(operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CWallet::CommitConsolidationTx(const CTransaction& tx) {
|
bool CWallet::CommitAutomatedTx(const CTransaction& tx) {
|
||||||
CWalletTx wtx(this, tx);
|
CWalletTx wtx(this, tx);
|
||||||
CReserveKey reservekey(pwalletMain);
|
CReserveKey reservekey(pwalletMain);
|
||||||
fprintf(stderr,"%s: %s\n",__func__,tx.ToString().c_str());
|
fprintf(stderr,"%s: %s\n",__func__,tx.ToString().c_str());
|
||||||
@@ -1668,9 +1720,9 @@ void CWallet::EraseFromWallet(const uint256 &hash)
|
|||||||
if (mapWallet.erase(hash))
|
if (mapWallet.erase(hash))
|
||||||
CWalletDB(strWalletFile).EraseTx(hash);
|
CWalletDB(strWalletFile).EraseTx(hash);
|
||||||
}
|
}
|
||||||
if(fDebug) {
|
|
||||||
LogPrintf("%s: erased txid %s\n", __func__, hash.ToString().c_str() );
|
LogPrintf("%s: erased txid %s\n", __func__, hash.ToString().c_str() );
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2795,7 +2847,12 @@ void CWallet::ReacceptWalletTransactions()
|
|||||||
{
|
{
|
||||||
const uint256& wtxid = item.first;
|
const uint256& wtxid = item.first;
|
||||||
CWalletTx& wtx = item.second;
|
CWalletTx& wtx = item.second;
|
||||||
assert(wtx.GetHash() == wtxid);
|
if(wtx.GetHash() != wtxid) {
|
||||||
|
LogPrintf("%s: Something funky going on, skipping this tx. wtx.GetHash() != wtxid (%s != %s)\n", __func__, wtx.GetHash().ToString().c_str(), wtxid.ToString().c_str() );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Crashing the node because of this is lame
|
||||||
|
// assert(wtx.GetHash() == wtxid);
|
||||||
|
|
||||||
int nDepth = wtx.GetDepthInMainChain();
|
int nDepth = wtx.GetDepthInMainChain();
|
||||||
|
|
||||||
@@ -3064,6 +3121,8 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
|
|||||||
// Sort them in chronological order
|
// Sort them in chronological order
|
||||||
multimap<unsigned int, CWalletTx*> mapSorted;
|
multimap<unsigned int, CWalletTx*> mapSorted;
|
||||||
uint32_t now = (uint32_t)time(NULL);
|
uint32_t now = (uint32_t)time(NULL);
|
||||||
|
|
||||||
|
// vector of wallet transactions to delete
|
||||||
std::vector<uint256> vwtxh;
|
std::vector<uint256> vwtxh;
|
||||||
uint32_t erased = 0, skipped = 0;
|
uint32_t erased = 0, skipped = 0;
|
||||||
|
|
||||||
@@ -3074,12 +3133,23 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
|
|||||||
if (wtx.nTimeReceived > nTime)
|
if (wtx.nTimeReceived > nTime)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Do not relay expired transactions, to avoid other nodes banning us
|
||||||
|
// Current code will not ban nodes relaying expired txs but older nodes will
|
||||||
|
if (wtx.nExpiryHeight > 0 && wtx.nExpiryHeight < chainActive.LastTip()->GetHeight()) {
|
||||||
|
fprintf(stderr,"%s: ignoring expired tx %s with expiry %d at height %d\n", __func__, wtx.GetHash().ToString().c_str(), wtx.nExpiryHeight, chainActive.LastTip()->GetHeight() );
|
||||||
|
// TODO: expired detection doesn't seem to work right
|
||||||
|
// append to list of txs to delete
|
||||||
|
// vwtxh.push_back(wtx.GetHash());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ( (wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-HUSH_MAXMEMPOOLTIME) )
|
if ( (wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-HUSH_MAXMEMPOOLTIME) )
|
||||||
{
|
{
|
||||||
if(fDebug) {
|
if(fDebug) {
|
||||||
LogPrintf("%s: skip Relaying wtx %s nLockTime %u vs now.%u\n", __func__, wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now);
|
LogPrintf("%s: skip Relaying wtx %s nLockTime %u vs now.%u\n", __func__, wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now);
|
||||||
}
|
}
|
||||||
skipped++;
|
skipped++;
|
||||||
|
// TODO: this does not seem to handle rescanning+finding old coinbase txs correctly
|
||||||
//vwtxh.push_back(wtx.GetHash());
|
//vwtxh.push_back(wtx.GetHash());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -3096,10 +3166,13 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this does not seem to handle rescanning+finding old coinbase txs correctly
|
// Unless we remove these unconfirmed and/or expired txs from the wallet, they will
|
||||||
// Unless we remove these unconfirmed txs from the wallet, they will
|
|
||||||
// persist there forever. They are too old to be accepted by network
|
// persist there forever. They are too old to be accepted by network
|
||||||
// consensus rules, so we erase them.
|
// consensus rules, so we erase them.
|
||||||
|
// Expired txs are always unconfirmed, but unconfirmed tx's could be expired or not,
|
||||||
|
// i.e. expired txs are a subset of unconfirmed tx's. Expired tx's can never be included
|
||||||
|
// in a block because they are against consensus rules. Unconfirmed tx's might still be
|
||||||
|
// included in a future block.
|
||||||
for (auto hash : vwtxh)
|
for (auto hash : vwtxh)
|
||||||
{
|
{
|
||||||
EraseFromWallet(hash);
|
EraseFromWallet(hash);
|
||||||
@@ -3120,6 +3193,7 @@ void CWallet::ResendWalletTransactions(int64_t nBestBlockTime)
|
|||||||
if (GetTime() < nNextResend || !fBroadcastTransactions)
|
if (GetTime() < nNextResend || !fBroadcastTransactions)
|
||||||
return;
|
return;
|
||||||
bool fFirst = (nNextResend == 0);
|
bool fFirst = (nNextResend == 0);
|
||||||
|
// TODO: BTC Core changed this to be every 12 hours instead of every 30 mins
|
||||||
nNextResend = GetTime() + GetRand(30 * 60);
|
nNextResend = GetTime() + GetRand(30 * 60);
|
||||||
if (fFirst)
|
if (fFirst)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -785,6 +785,9 @@ private:
|
|||||||
std::vector<CTransaction> pendingSaplingConsolidationTxs;
|
std::vector<CTransaction> pendingSaplingConsolidationTxs;
|
||||||
AsyncRPCOperationId saplingConsolidationOperationId;
|
AsyncRPCOperationId saplingConsolidationOperationId;
|
||||||
|
|
||||||
|
std::vector<CTransaction> pendingSaplingSweepTxs;
|
||||||
|
AsyncRPCOperationId saplingSweepOperationId;
|
||||||
|
|
||||||
void AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid);
|
void AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid);
|
||||||
void AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid);
|
void AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid);
|
||||||
void AddToSpends(const uint256& wtxid);
|
void AddToSpends(const uint256& wtxid);
|
||||||
@@ -797,7 +800,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
int64_t nWitnessCacheSize;
|
int64_t nWitnessCacheSize;
|
||||||
bool needsRescan = false;
|
bool needsRescan = false;
|
||||||
|
int nextConsolidation = 0;
|
||||||
|
|
||||||
bool fSaplingConsolidationEnabled = false;
|
bool fSaplingConsolidationEnabled = false;
|
||||||
|
bool fConsolidationRunning = false;
|
||||||
|
bool fSweepEnabled = false;
|
||||||
|
bool fSweepExternalEnabled = false;
|
||||||
|
bool fSweepRunning = false;
|
||||||
|
int nextSweep = 0;
|
||||||
|
int amountSwept = 0;
|
||||||
|
int amountConsolidated = 0;
|
||||||
|
int sweepInterval = 10;
|
||||||
|
int consolidationInterval = 25;
|
||||||
|
int sweepFee = 10000;
|
||||||
|
int sweepMaxInputs = 200;
|
||||||
|
std::string sweepAddress = "";
|
||||||
|
std::vector<std::string> sweepExcludeAddresses;
|
||||||
|
std::string consolidationAddress = "";
|
||||||
|
|
||||||
void ClearNoteWitnessCache();
|
void ClearNoteWitnessCache();
|
||||||
|
|
||||||
@@ -1181,12 +1200,14 @@ public:
|
|||||||
CAmount GetCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const;
|
CAmount GetCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const;
|
||||||
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
||||||
CAmount GetChange(const CTransaction& tx) const;
|
CAmount GetChange(const CTransaction& tx) const;
|
||||||
|
void RunSaplingSweep(int blockHeight);
|
||||||
|
|
||||||
void ChainTip(
|
void ChainTip(
|
||||||
const CBlockIndex *pindex,
|
const CBlockIndex *pindex,
|
||||||
const CBlock *pblock,
|
const CBlock *pblock,
|
||||||
boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>> added);
|
boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>> added);
|
||||||
void RunSaplingConsolidation(int blockHeight);
|
void RunSaplingConsolidation(int blockHeight);
|
||||||
bool CommitConsolidationTx(const CTransaction& tx);
|
bool CommitAutomatedTx(const CTransaction& tx);
|
||||||
/** Saves witness caches and best block locator to disk. */
|
/** Saves witness caches and best block locator to disk. */
|
||||||
void SetBestChain(const CBlockLocator& loc);
|
void SetBestChain(const CBlockLocator& loc);
|
||||||
std::set<std::pair<libzcash::PaymentAddress, uint256>> GetNullifiersForAddresses(const std::set<libzcash::PaymentAddress> & addresses);
|
std::set<std::pair<libzcash::PaymentAddress, uint256>> GetNullifiersForAddresses(const std::set<libzcash::PaymentAddress> & addresses);
|
||||||
|
|||||||
Reference in New Issue
Block a user