diff --git a/src/Makefile.am b/src/Makefile.am index 5d73c049f..76f99f00c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -231,6 +231,7 @@ BITCOIN_CORE_H = \ version.h \ wallet/asyncrpcoperation_mergetoaddress.h \ wallet/asyncrpcoperation_saplingconsolidation.h \ + wallet/asyncrpcoperation_sweep.h \ wallet/asyncrpcoperation_sendmany.h \ wallet/asyncrpcoperation_shieldcoinbase.h \ wallet/crypter.h \ @@ -344,6 +345,7 @@ libbitcoin_wallet_a_SOURCES = \ zcbenchmarks.h \ wallet/asyncrpcoperation_mergetoaddress.cpp \ wallet/asyncrpcoperation_saplingconsolidation.cpp \ + wallet/asyncrpcoperation_sweep.cpp \ wallet/asyncrpcoperation_sendmany.cpp \ wallet/asyncrpcoperation_shieldcoinbase.cpp \ wallet/crypter.cpp \ diff --git a/src/base58.cpp b/src/base58.cpp index d46894ea0..f1ca396ab 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html diff --git a/src/compressor.cpp b/src/compressor.cpp index ae7fe02ba..b55313486 100644 --- a/src/compressor.cpp +++ b/src/compressor.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying diff --git a/src/consensus/upgrades.h b/src/consensus/upgrades.h index 7a72e798b..278c3e462 100644 --- a/src/consensus/upgrades.h +++ b/src/consensus/upgrades.h @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2022 The Hush developers // Copyright (c) 2018 The Zcash developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html @@ -17,8 +18,8 @@ * * ******************************************************************************/ -#ifndef ZCASH_CONSENSUS_UPGRADES_H -#define ZCASH_CONSENSUS_UPGRADES_H +#ifndef HUSH_CONSENSUS_UPGRADES_H +#define HUSH_CONSENSUS_UPGRADES_H #include "consensus/params.h" @@ -114,4 +115,4 @@ boost::optional NextActivationHeight( int nHeight, const Consensus::Params& params); -#endif // ZCASH_CONSENSUS_UPGRADES_H +#endif // HUSH_CONSENSUS_UPGRADES_H diff --git a/src/consensus/validation.h b/src/consensus/validation.h index edf38e294..848018728 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2022 The Hush developers // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying diff --git a/src/core_read.cpp b/src/core_read.cpp index 679d221f4..d092f6624 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html diff --git a/src/core_write.cpp b/src/core_write.cpp index bb996c700..67953e2fa 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html diff --git a/src/fs.cpp b/src/fs.cpp index a5e12f1cf..0c6a60014 100644 --- a/src/fs.cpp +++ b/src/fs.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers #include "fs.h" namespace fsbridge { diff --git a/src/importcoin.cpp b/src/importcoin.cpp index 16a8d3c64..f6da631c7 100644 --- a/src/importcoin.cpp +++ b/src/importcoin.cpp @@ -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. * * * diff --git a/src/init.cpp b/src/init.cpp index e057282be..dd6666710 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -59,6 +59,7 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" #include "wallet/asyncrpcoperation_saplingconsolidation.h" +#include "wallet/asyncrpcoperation_sweep.h" #endif #include #include @@ -461,6 +462,16 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-consolidation", _("Enable auto Sapling note consolidation (default: false)")); strUsage += HelpMessageOpt("-consolidatesaplingaddress=", _("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("-zsweep", _("Enable zaddr sweeping, automatically move all shielded funds to a one address once per X blocks")); + strUsage += HelpMessageOpt("-zsweepaddress=", _("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("-deletetx", _("Enable Old Transaction Deletion")); strUsage += HelpMessageOpt("-deleteinterval", strprintf(_("Delete transaction every blocks during inital block download (default: %i)"), DEFAULT_TX_DELETE_INTERVAL)); strUsage += HelpMessageOpt("-keeptxnum", strprintf(_("Keep the last transactions (default: %i)"), DEFAULT_TX_RETENTION_LASTTX)); @@ -2054,6 +2065,53 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } + //Set Sweep + pwalletMain->fSweepEnabled = GetBoolArg("-zsweep", false); + + if (pwalletMain->fSweepEnabled) { + fSweepTxFee = GetArg("-zsweepfee", DEFAULT_SWEEP_FEE); + fSweepMapUsed = !mapMultiArgs["-zsweepaddress"].empty(); + + //Validate Sapling Addresses + vector& vSweep = mapMultiArgs["-zsweepaddress"]; + 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); + + 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"); + } + } + } + + if (pwalletMain->fSaplingConsolidationEnabled) { + //Validate 1 Consolidation address only that matches the sweep address + vector& vaddresses = mapMultiArgs["-consolidatesaplingaddress"]; + if (vaddresses.size() == 0) { + fConsolidationMapUsed = true; + mapMultiArgs["-consolidatesaplingaddress"] = vSweep; + } else { + 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."); + } + } + } + } + } + //Set Transaction Deletion Options fTxDeleteEnabled = GetBoolArg("-deletetx", false); fTxConflictDeleteEnabled = GetBoolArg("-deleteconflicttx", true); diff --git a/src/key.cpp b/src/key.cpp index 70ade77fb..83f831ada 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2009-2014 The Bitcoin Core developers // Copyright (c) 2017 The Zcash developers // Distributed under the GPLv3 software license, see the accompanying diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index c12552f78..86df55cac 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying diff --git a/src/noui.cpp b/src/noui.cpp index 7a838d0bd..e0bd76e4d 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying diff --git a/src/scheduler.cpp b/src/scheduler.cpp index c243ca308..9c4ebf334 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2015 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index 3ff6269b2..0dfd5a299 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -104,6 +104,11 @@ bool TransactionBuilder::AddOpRetLast() return true; } +void TransactionBuilder::SetExpiryHeight(int nHeight) +{ + this->mtx.nExpiryHeight = nHeight; +} + void TransactionBuilder::AddOpRet(CScript &s) { opReturn.emplace(CScript(s)); diff --git a/src/transaction_builder.h b/src/transaction_builder.h index 89a8d6580..6c4d20302 100644 --- a/src/transaction_builder.h +++ b/src/transaction_builder.h @@ -77,6 +77,7 @@ public: TransactionBuilder(const Consensus::Params& consensusParams, int nHeight, CKeyStore* keyStore = nullptr); void SetFee(CAmount fee); + void SetExpiryHeight(int nHeight); // Returns false if the anchor does not match the anchor used by // previously-added Sapling spends. diff --git a/src/uint256.cpp b/src/uint256.cpp index 4883ac50b..97c0cb007 100644 --- a/src/uint256.cpp +++ b/src/uint256.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying @@ -19,9 +20,7 @@ ******************************************************************************/ #include "uint256.h" - #include "utilstrencodings.h" - #include #include diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 665f9bead..4a2815968 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying diff --git a/src/utiltime.cpp b/src/utiltime.cpp index aba3823ca..bc5e3d69c 100644 --- a/src/utiltime.cpp +++ b/src/utiltime.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2016-2021 The Hush developers // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Distributed under the GPLv3 software license, see the accompanying diff --git a/src/wallet/asyncrpcoperation_saplingconsolidation.cpp b/src/wallet/asyncrpcoperation_saplingconsolidation.cpp index 2594fb4ce..361d04390 100644 --- a/src/wallet/asyncrpcoperation_saplingconsolidation.cpp +++ b/src/wallet/asyncrpcoperation_saplingconsolidation.cpp @@ -159,7 +159,7 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() { amountConsolidated += amountToSend; 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; LogPrintf("%s: %s Beginning to create transaction with Sapling output amount=%s\n", __func__, opid, FormatMoney(actualAmountToSend)); @@ -235,7 +235,7 @@ bool AsyncRPCOperation_saplingconsolidation::main_impl() { break; } - if(pwalletMain->CommitConsolidationTx(tx)) { + if(pwalletMain->CommitAutomatedTx(tx)) { LogPrint("zrpcunsafe", "%s: Committed consolidation transaction with txid=%s\n",opid, tx.GetHash().ToString()); amountConsolidated += actualAmountToSend; consolidationTxIds.push_back(tx.GetHash().ToString()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index bda0140f0..83f95cbb3 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -38,6 +38,7 @@ #include "crypter.h" #include "coins.h" #include "wallet/asyncrpcoperation_saplingconsolidation.h" +#include "wallet/asyncrpcoperation_sweep.h" #include "zcash/zip32.h" #include "cc/CCinclude.h" #include @@ -483,6 +484,9 @@ void CWallet::ChainTip(const CBlockIndex *pindex, if (fSaplingConsolidationEnabled) { RunSaplingConsolidation(pindex->GetHeight()); } + if (fSweepEnabled) { + RunSaplingSweep(pindex->GetHeight()); + } if (fTxDeleteEnabled) { DeleteWalletTransactions(pindex); } @@ -501,6 +505,43 @@ void CWallet::ChainTip(const CBlockIndex *pindex, } } +void CWallet::RunSaplingSweep(int blockHeight) { + // 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; + } + + if (nextSweep > blockHeight) { + return; + } + + //Don't Run if consolidation will run soon. + if (fSaplingConsolidationEnabled && nextConsolidation - 15 <= blockHeight) { + return; + } + + //Don't Run While consolidation is running. + if (fConsolidationRunning) { + return; + } + + fSweepRunning = true; + + std::shared_ptr q = getAsyncRPCQueue(); + std::shared_ptr lastOperation = q->getOperationForId(saplingSweepOperationId); + if (lastOperation != nullptr) { + lastOperation->cancel(); + } + pendingSaplingSweepTxs.clear(); + std::shared_ptr operation(new AsyncRPCOperation_sweep(blockHeight + 5)); + saplingSweepOperationId = operation->getId(); + q->addOperation(operation); +} + void CWallet::RunSaplingConsolidation(int blockHeight) { if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { return; @@ -512,6 +553,10 @@ void CWallet::RunSaplingConsolidation(int blockHeight) { return; } + if (fSweepRunning) { + return; + } + int consolidateInterval = rand() % 5 + 5; if(fZdebug) @@ -530,7 +575,7 @@ void CWallet::RunSaplingConsolidation(int blockHeight) { } } -bool CWallet::CommitConsolidationTx(const CTransaction& tx) { +bool CWallet::CommitAutomatedTx(const CTransaction& tx) { CWalletTx wtx(this, tx); CReserveKey reservekey(pwalletMain); fprintf(stderr,"%s: %s\n",__func__,tx.ToString().c_str()); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 15be2072d..f633f2564 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -785,6 +785,9 @@ private: std::vector pendingSaplingConsolidationTxs; AsyncRPCOperationId saplingConsolidationOperationId; + std::vector pendingSaplingSweepTxs; + AsyncRPCOperationId saplingSweepOperationId; + void AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid); void AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid); void AddToSpends(const uint256& wtxid); @@ -797,7 +800,13 @@ public: */ int64_t nWitnessCacheSize; bool needsRescan = false; + int nextConsolidation = 0; + bool fSaplingConsolidationEnabled = false; + bool fConsolidationRunning = false; + bool fSweepEnabled = false; + bool fSweepRunning = false; + int nextSweep = 0; void ClearNoteWitnessCache(); @@ -1181,12 +1190,14 @@ public: CAmount GetCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const; CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetChange(const CTransaction& tx) const; + void RunSaplingSweep(int blockHeight); + void ChainTip( const CBlockIndex *pindex, const CBlock *pblock, boost::optional> added); void RunSaplingConsolidation(int blockHeight); - bool CommitConsolidationTx(const CTransaction& tx); + bool CommitAutomatedTx(const CTransaction& tx); /** Saves witness caches and best block locator to disk. */ void SetBestChain(const CBlockLocator& loc); std::set> GetNullifiersForAddresses(const std::set & addresses);