Hush witness rework, many thanks to @CryptoForge for this awesome code https://github.com/Cryptoforge-alt/pirate/tree/pirate_witness_rework
This commit is contained in:
@@ -248,6 +248,7 @@ BITCOIN_CORE_H = \
|
||||
validationinterface.h \
|
||||
version.h \
|
||||
wallet/asyncrpcoperation_mergetoaddress.h \
|
||||
wallet/asyncrpcoperation_saplingconsolidation.h \
|
||||
wallet/asyncrpcoperation_sendmany.h \
|
||||
wallet/asyncrpcoperation_shieldcoinbase.h \
|
||||
wallet/crypter.h \
|
||||
@@ -368,6 +369,7 @@ libbitcoin_wallet_a_SOURCES = \
|
||||
zcbenchmarks.cpp \
|
||||
zcbenchmarks.h \
|
||||
wallet/asyncrpcoperation_mergetoaddress.cpp \
|
||||
wallet/asyncrpcoperation_saplingconsolidation.cpp \
|
||||
wallet/asyncrpcoperation_sendmany.cpp \
|
||||
wallet/asyncrpcoperation_shieldcoinbase.cpp \
|
||||
wallet/crypter.cpp \
|
||||
|
||||
46
src/init.cpp
46
src/init.cpp
@@ -57,6 +57,7 @@
|
||||
#ifdef ENABLE_WALLET
|
||||
#include "wallet/wallet.h"
|
||||
#include "wallet/walletdb.h"
|
||||
#include "wallet/asyncrpcoperation_saplingconsolidation.h"
|
||||
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
@@ -449,6 +450,13 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageGroup(_("Wallet options:"));
|
||||
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
|
||||
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
|
||||
strUsage += HelpMessageOpt("-consolidation", _("Enable auto Sapling note consolidation"));
|
||||
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("-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("-keeptxnum", strprintf(_("Keep the last <n> transactions (default: %i)"), DEFAULT_TX_RETENTION_LASTTX));
|
||||
strUsage += HelpMessageOpt("-keeptxfornblocks", strprintf(_("Keep transactions for at least <n> blocks (default: %i)"), DEFAULT_TX_RETENTION_BLOCKS));
|
||||
if (showDebug)
|
||||
strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
|
||||
CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
|
||||
@@ -500,7 +508,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
||||
strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
|
||||
strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)");
|
||||
}
|
||||
string debugCategories = "addrman, alert, bench, coindb, db, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, "
|
||||
string debugCategories = "addrman, alert, bench, coindb, db, deletetx, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, "
|
||||
"rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these
|
||||
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
|
||||
_("If <category> is not supplied or if <category> = 1, output all debugging information.") + " " + _("<category> can be:") + " " + debugCategories + ".");
|
||||
@@ -1953,6 +1961,42 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
||||
pwalletMain->GenerateNewSeed();
|
||||
}
|
||||
|
||||
//Set Sapling Consolidation
|
||||
pwalletMain->fSaplingConsolidationEnabled = GetBoolArg("-consolidation", false);
|
||||
fConsolidationTxFee = GetArg("-consolidationtxfee", DEFAULT_CONSOLIDATION_FEE);
|
||||
fConsolidationMapUsed = !mapMultiArgs["-consolidatesaplingaddress"].empty();
|
||||
|
||||
//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 Transaction Deletion Options
|
||||
fTxDeleteEnabled = GetBoolArg("-deletetx", false);
|
||||
fTxConflictDeleteEnabled = GetBoolArg("-deleteconflicttx", true);
|
||||
|
||||
fDeleteInterval = GetArg("-deleteinterval", DEFAULT_TX_DELETE_INTERVAL);
|
||||
if (fDeleteInterval < 1)
|
||||
return InitError("deleteinterval must be greater than 0");
|
||||
|
||||
fKeepLastNTransactions = GetArg("-keeptxnum", DEFAULT_TX_RETENTION_LASTTX);
|
||||
if (fKeepLastNTransactions < 1)
|
||||
return InitError("keeptxnum must be greater than 0");
|
||||
|
||||
fDeleteTransactionsAfterNBlocks = GetArg("-keeptxfornblocks", DEFAULT_TX_RETENTION_BLOCKS);
|
||||
if (fDeleteTransactionsAfterNBlocks < 1)
|
||||
return InitError("keeptxfornblocks must be greater than 0");
|
||||
|
||||
if (fDeleteTransactionsAfterNBlocks < MAX_REORG_LENGTH + 1 ) {
|
||||
LogPrintf("keeptxfornblock is less the MAX_REORG_LENGTH, Setting to %i\n", MAX_REORG_LENGTH + 1);
|
||||
fDeleteTransactionsAfterNBlocks = MAX_REORG_LENGTH + 1;
|
||||
}
|
||||
|
||||
if (fFirstRun)
|
||||
{
|
||||
// Create new keyUser and set as default key
|
||||
|
||||
221
src/wallet/asyncrpcoperation_saplingconsolidation.cpp
Normal file
221
src/wallet/asyncrpcoperation_saplingconsolidation.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
#include "assert.h"
|
||||
#include "boost/variant/static_visitor.hpp"
|
||||
#include "asyncrpcoperation_saplingconsolidation.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"
|
||||
|
||||
CAmount fConsolidationTxFee = DEFAULT_CONSOLIDATION_FEE;
|
||||
bool fConsolidationMapUsed = false;
|
||||
const int CONSOLIDATION_EXPIRY_DELTA = 15;
|
||||
|
||||
|
||||
AsyncRPCOperation_saplingconsolidation::AsyncRPCOperation_saplingconsolidation(int targetHeight) : targetHeight_(targetHeight) {}
|
||||
|
||||
AsyncRPCOperation_saplingconsolidation::~AsyncRPCOperation_saplingconsolidation() {}
|
||||
|
||||
void AsyncRPCOperation_saplingconsolidation::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: Sapling Consolidation transaction created. (status=%s", getId(), getStateAsString());
|
||||
if (success) {
|
||||
s += strprintf(", success)\n");
|
||||
} else {
|
||||
s += strprintf(", error=%s)\n", getErrorMessage());
|
||||
}
|
||||
|
||||
LogPrintf("%s", s);
|
||||
}
|
||||
|
||||
bool AsyncRPCOperation_saplingconsolidation::main_impl() {
|
||||
LogPrint("zrpcunsafe", "%s: Beginning AsyncRPCOperation_saplingconsolidation.\n", getId());
|
||||
auto consensusParams = Params().GetConsensus();
|
||||
auto nextActivationHeight = NextActivationHeight(targetHeight_, consensusParams);
|
||||
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", getId());
|
||||
setConsolidationResult(0, 0, std::vector<std::string>());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<CSproutNotePlaintextEntry> sproutEntries;
|
||||
std::vector<SaplingNoteEntry> saplingEntries;
|
||||
std::set<libzcash::SaplingPaymentAddress> addresses;
|
||||
{
|
||||
LOCK2(cs_main, pwalletMain->cs_wallet);
|
||||
// We set minDepth to 11 to avoid unconfirmed notes and in anticipation of specifying
|
||||
// an anchor at height N-10 for each Sprout JoinSplit description
|
||||
// Consider, should notes be sorted?
|
||||
pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, "", 11);
|
||||
if (fConsolidationMapUsed) {
|
||||
const vector<string>& v = mapMultiArgs["-consolidatesaplingaddress"];
|
||||
for(int i = 0; i < v.size(); i++) {
|
||||
auto zAddress = DecodePaymentAddress(v[i]);
|
||||
if (boost::get<libzcash::SaplingPaymentAddress>(&zAddress) != nullptr) {
|
||||
libzcash::SaplingPaymentAddress saplingAddress = boost::get<libzcash::SaplingPaymentAddress>(zAddress);
|
||||
addresses.insert(saplingAddress );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pwalletMain->GetSaplingPaymentAddresses(addresses);
|
||||
}
|
||||
}
|
||||
|
||||
int numTxCreated = 0;
|
||||
std::vector<std::string> consolidationTxIds;
|
||||
CAmount amountConsolidated = 0;
|
||||
CCoinsViewCache coinsView(pcoinsTip);
|
||||
|
||||
for (auto addr : addresses) {
|
||||
libzcash::SaplingExtendedSpendingKey extsk;
|
||||
if (pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk)) {
|
||||
|
||||
std::vector<SaplingNoteEntry> fromNotes;
|
||||
CAmount amountToSend = 0;
|
||||
int maxQuantity = rand() % 35 + 10;
|
||||
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()) {
|
||||
amountToSend += CAmount(saplingEntry.note.value());
|
||||
fromNotes.push_back(saplingEntry);
|
||||
}
|
||||
|
||||
//Only use a randomly determined number of notes between 10 and 45
|
||||
if (fromNotes.size() >= maxQuantity)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
//random minimum 2 - 12 required
|
||||
int minQuantity = rand() % 10 + 2;
|
||||
if (fromNotes.size() < minQuantity)
|
||||
continue;
|
||||
|
||||
amountConsolidated += amountToSend;
|
||||
auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain);
|
||||
//builder.SetExpiryHeight(targetHeight_ + CONSOLIDATION_EXPIRY_DELTA);
|
||||
LogPrint("zrpcunsafe", "%s: Beginning creating transaction with Sapling output amount=%s\n", getId(), FormatMoney(amountToSend - fConsolidationTxFee));
|
||||
|
||||
// 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]) {
|
||||
LogPrint("zrpcunsafe", "%s: Missing Witnesses. Stopping.\n", getId());
|
||||
break;
|
||||
}
|
||||
builder.AddSaplingSpend(extsk.expsk, notes[i], anchor, witnesses[i].get());
|
||||
}
|
||||
|
||||
builder.SetFee(fConsolidationTxFee);
|
||||
builder.AddSaplingOutput(extsk.expsk.ovk, addr, amountToSend - fConsolidationTxFee);
|
||||
//CTransaction tx = builder.Build();
|
||||
|
||||
auto maybe_tx = builder.Build();
|
||||
if (!maybe_tx) {
|
||||
LogPrint("zrpcunsafe", "%s: Failed to build transaction.", getId());
|
||||
break;
|
||||
}
|
||||
CTransaction tx = maybe_tx.get();
|
||||
|
||||
if (isCancelled()) {
|
||||
LogPrint("zrpcunsafe", "%s: Canceled. Stopping.\n", getId());
|
||||
break;
|
||||
}
|
||||
|
||||
pwalletMain->CommitConsolidationTx(tx);
|
||||
LogPrint("zrpcunsafe", "%s: Committed consolidation transaction with txid=%s\n", getId(), tx.GetHash().ToString());
|
||||
amountConsolidated += amountToSend - fConsolidationTxFee;
|
||||
consolidationTxIds.push_back(tx.GetHash().ToString());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
LogPrint("zrpcunsafe", "%s: Created %d transactions with total Sapling output amount=%s\n", getId(), numTxCreated, FormatMoney(amountConsolidated));
|
||||
setConsolidationResult(numTxCreated, amountConsolidated, consolidationTxIds);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void AsyncRPCOperation_saplingconsolidation::setConsolidationResult(int numTxCreated, const CAmount& amountConsolidated, const std::vector<std::string>& consolidationTxIds) {
|
||||
UniValue res(UniValue::VOBJ);
|
||||
res.push_back(Pair("num_tx_created", numTxCreated));
|
||||
res.push_back(Pair("amount_consolidated", FormatMoney(amountConsolidated)));
|
||||
UniValue txIds(UniValue::VARR);
|
||||
for (const std::string& txId : consolidationTxIds) {
|
||||
txIds.push_back(txId);
|
||||
}
|
||||
res.push_back(Pair("consolidation_txids", txIds));
|
||||
set_result(res);
|
||||
}
|
||||
|
||||
void AsyncRPCOperation_saplingconsolidation::cancel() {
|
||||
set_state(OperationStatus::CANCELLED);
|
||||
}
|
||||
|
||||
UniValue AsyncRPCOperation_saplingconsolidation::getStatus() const {
|
||||
UniValue v = AsyncRPCOperation::getStatus();
|
||||
UniValue obj = v.get_obj();
|
||||
obj.push_back(Pair("method", "saplingconsolidation"));
|
||||
obj.push_back(Pair("target_height", targetHeight_));
|
||||
return obj;
|
||||
}
|
||||
37
src/wallet/asyncrpcoperation_saplingconsolidation.h
Normal file
37
src/wallet/asyncrpcoperation_saplingconsolidation.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "amount.h"
|
||||
#include "asyncrpcoperation.h"
|
||||
#include "univalue.h"
|
||||
#include "zcash/Address.hpp"
|
||||
#include "zcash/zip32.h"
|
||||
|
||||
//Default fee used for consolidation transactions
|
||||
static const CAmount DEFAULT_CONSOLIDATION_FEE = 0;
|
||||
extern CAmount fConsolidationTxFee;
|
||||
extern bool fConsolidationMapUsed;
|
||||
|
||||
class AsyncRPCOperation_saplingconsolidation : public AsyncRPCOperation
|
||||
{
|
||||
public:
|
||||
AsyncRPCOperation_saplingconsolidation(int targetHeight);
|
||||
virtual ~AsyncRPCOperation_saplingconsolidation();
|
||||
|
||||
// We don't want to be copied or moved around
|
||||
AsyncRPCOperation_saplingconsolidation(AsyncRPCOperation_saplingconsolidation const&) = delete; // Copy construct
|
||||
AsyncRPCOperation_saplingconsolidation(AsyncRPCOperation_saplingconsolidation&&) = delete; // Move construct
|
||||
AsyncRPCOperation_saplingconsolidation& operator=(AsyncRPCOperation_saplingconsolidation const&) = delete; // Copy assign
|
||||
AsyncRPCOperation_saplingconsolidation& operator=(AsyncRPCOperation_saplingconsolidation&&) = delete; // Move assign
|
||||
|
||||
virtual void main();
|
||||
|
||||
virtual void cancel();
|
||||
|
||||
virtual UniValue getStatus() const;
|
||||
|
||||
private:
|
||||
int targetHeight_;
|
||||
|
||||
bool main_impl();
|
||||
|
||||
void setConsolidationResult(int numTxCreated, const CAmount& amountConsolidated, const std::vector<std::string>& consolidationTxIds);
|
||||
|
||||
};
|
||||
@@ -105,7 +105,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
|
||||
nEnvFlags |= DB_PRIVATE;
|
||||
|
||||
dbenv->set_lg_dir(pathLogDir.string().c_str());
|
||||
dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet
|
||||
dbenv->set_cachesize(1, 0x100000, 1); // 1 MiB should be enough for just the wallet, Increased by 1 GB
|
||||
dbenv->set_lg_bsize(0x10000);
|
||||
dbenv->set_lg_max(1048576);
|
||||
dbenv->set_lk_max_locks(40000);
|
||||
@@ -181,6 +181,55 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFu
|
||||
return (fRecovered ? RECOVER_OK : RECOVER_FAIL);
|
||||
}
|
||||
|
||||
bool CDBEnv::Compact(const std::string& strFile)
|
||||
{
|
||||
LOCK(cs_db);
|
||||
|
||||
DB_COMPACT dbcompact;
|
||||
dbcompact.compact_fillpercent = 80;
|
||||
dbcompact.compact_pages = DB_MAX_PAGES;
|
||||
dbcompact.compact_timeout = 0;
|
||||
|
||||
DB_COMPACT *pdbcompact;
|
||||
pdbcompact = &dbcompact;
|
||||
|
||||
int result = 1;
|
||||
if (mapDb[strFile] != NULL) {
|
||||
Db* pdb = mapDb[strFile];
|
||||
result = pdb->compact(NULL, NULL, NULL, pdbcompact, DB_FREE_SPACE, NULL);
|
||||
delete pdb;
|
||||
mapDb[strFile] = NULL;
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case DB_LOCK_DEADLOCK:
|
||||
LogPrint("db","Deadlock %i\n", result);
|
||||
break;
|
||||
case DB_LOCK_NOTGRANTED:
|
||||
LogPrint("db","Lock Not Granted %i\n", result);
|
||||
break;
|
||||
case DB_REP_HANDLE_DEAD:
|
||||
LogPrint("db","Handle Dead %i\n", result);
|
||||
break;
|
||||
case DB_REP_LOCKOUT:
|
||||
LogPrint("db","Rep Lockout %i\n", result);
|
||||
break;
|
||||
case EACCES:
|
||||
LogPrint("db","Eacces %i\n", result);
|
||||
break;
|
||||
case EINVAL:
|
||||
LogPrint("db","Error Invalid %i\n", result);
|
||||
break;
|
||||
case 0:
|
||||
LogPrint("db","Wallet Compact Sucessful\n");
|
||||
break;
|
||||
default:
|
||||
LogPrint("db","Compact result int %i\n", result);
|
||||
}
|
||||
}
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult)
|
||||
{
|
||||
LOCK(cs_db);
|
||||
|
||||
@@ -88,6 +88,7 @@ public:
|
||||
* NOTE: reads the entire database into memory, so cannot be used
|
||||
* for huge databases.
|
||||
*/
|
||||
bool Compact(const std::string& strFile);
|
||||
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
|
||||
bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult);
|
||||
|
||||
|
||||
@@ -53,12 +53,10 @@ public:
|
||||
return CCryptoKeyStore::Unlock(vMasterKeyIn);
|
||||
}
|
||||
|
||||
void IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
const CBlock* pblock,
|
||||
SproutMerkleTree& sproutTree,
|
||||
SaplingMerkleTree& saplingTree) {
|
||||
CWallet::IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree);
|
||||
void BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly) {
|
||||
CWallet::BuildWitnessCache(pindex, witnessOnly);
|
||||
}
|
||||
|
||||
void DecrementNoteWitnesses(const CBlockIndex* pindex) {
|
||||
CWallet::DecrementNoteWitnesses(pindex);
|
||||
}
|
||||
@@ -116,7 +114,7 @@ std::pair<JSOutPoint, SaplingOutPoint> CreateValidBlock(TestWallet& wallet,
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
block.vtx.push_back(wtx);
|
||||
wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree);
|
||||
wallet.BuildWitnessCache(&index, false);
|
||||
|
||||
return std::make_pair(jsoutpt, saplingNotes[0]);
|
||||
}
|
||||
@@ -724,8 +722,8 @@ TEST(WalletTests, GetConflictedSaplingNotes) {
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
// Simulate receiving new block and ChainTip signal
|
||||
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
|
||||
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
|
||||
wallet.BuildWitnessCache(&fakeIndex, false);
|
||||
wallet.UpdateNullifierNoteMapForBlock(&block);
|
||||
|
||||
// Retrieve the updated wtx from wallet
|
||||
uint256 hash = wtx.GetHash();
|
||||
@@ -1008,8 +1006,8 @@ TEST(WalletTests, NavigateFromSaplingNullifierToNote) {
|
||||
}
|
||||
|
||||
// Simulate receiving new block and ChainTip signal
|
||||
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
|
||||
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
|
||||
wallet.BuildWitnessCache(&fakeIndex, false);
|
||||
wallet.UpdateNullifierNoteMapForBlock(&block);
|
||||
|
||||
// Retrieve the updated wtx from wallet
|
||||
uint256 hash = wtx.GetHash();
|
||||
@@ -1126,8 +1124,8 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) {
|
||||
// Simulate receiving new block and ChainTip signal.
|
||||
// This triggers calculation of nullifiers for notes belonging to this wallet
|
||||
// in the output descriptions of wtx.
|
||||
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
|
||||
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
|
||||
wallet.BuildWitnessCache(&fakeIndex, false);
|
||||
wallet.UpdateNullifierNoteMapForBlock(&block);
|
||||
|
||||
// Retrieve the updated wtx from wallet
|
||||
wtx = wallet.mapWallet[wtx.GetHash()];
|
||||
@@ -1263,7 +1261,7 @@ TEST(WalletTests, CachedWitnessesEmptyChain) {
|
||||
CBlockIndex index(block);
|
||||
SproutMerkleTree sproutTree;
|
||||
SaplingMerkleTree saplingTree;
|
||||
wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree);
|
||||
wallet.BuildWitnessCache(&index, false);
|
||||
|
||||
::GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
|
||||
|
||||
@@ -1354,7 +1352,7 @@ TEST(WalletTests, CachedWitnessesChainTip) {
|
||||
EXPECT_NE(anchors1.second, anchors3.second);
|
||||
|
||||
// Re-incrementing with the same block should give the same result
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
|
||||
wallet.BuildWitnessCache(&index2, false);
|
||||
auto anchors4 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
|
||||
EXPECT_NE(anchors4.first, anchors4.second);
|
||||
|
||||
@@ -1364,7 +1362,7 @@ TEST(WalletTests, CachedWitnessesChainTip) {
|
||||
EXPECT_EQ(anchors2.second, anchors4.second);
|
||||
|
||||
// Incrementing with the same block again should not change the cache
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
|
||||
wallet.BuildWitnessCache(&index2, false);
|
||||
std::vector<boost::optional<SproutWitness>> sproutWitnesses5;
|
||||
std::vector<boost::optional<SaplingWitness>> saplingWitnesses5;
|
||||
|
||||
@@ -1447,7 +1445,7 @@ TEST(WalletTests, CachedWitnessesDecrementFirst) {
|
||||
EXPECT_NE(anchors2.second, anchors4.second);
|
||||
|
||||
// Re-incrementing with the same block should give the same result
|
||||
wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree);
|
||||
wallet.BuildWitnessCache(&index2, false);
|
||||
|
||||
auto anchors5 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
|
||||
|
||||
@@ -1504,7 +1502,7 @@ TEST(WalletTests, CachedWitnessesCleanIndex) {
|
||||
for (size_t i = 0; i < numBlocks; i++) {
|
||||
SproutMerkleTree sproutRiPrevTree {sproutRiTree};
|
||||
SaplingMerkleTree saplingRiPrevTree {saplingRiTree};
|
||||
wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiTree, saplingRiTree);
|
||||
wallet.BuildWitnessCache(&indices[i], false);
|
||||
|
||||
auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
|
||||
for (size_t j = 0; j < numBlocks; j++) {
|
||||
@@ -1531,7 +1529,7 @@ TEST(WalletTests, CachedWitnessesCleanIndex) {
|
||||
}
|
||||
|
||||
{
|
||||
wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiPrevTree, saplingRiPrevTree);
|
||||
wallet.BuildWitnessCache(&indices[i], false);
|
||||
auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses);
|
||||
for (size_t j = 0; j < numBlocks; j++) {
|
||||
EXPECT_TRUE((bool) sproutWitnesses[j]);
|
||||
@@ -1886,8 +1884,8 @@ TEST(WalletTests, UpdatedSaplingNoteData) {
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
// Simulate receiving new block and ChainTip signal
|
||||
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
|
||||
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
|
||||
wallet.BuildWitnessCache(&fakeIndex, false);
|
||||
wallet.UpdateNullifierNoteMapForBlock(&block);
|
||||
|
||||
// Retrieve the updated wtx from wallet
|
||||
uint256 hash = wtx.GetHash();
|
||||
@@ -1915,7 +1913,7 @@ TEST(WalletTests, UpdatedSaplingNoteData) {
|
||||
|
||||
EXPECT_EQ(2, wtx2.mapSaplingNoteData.size());
|
||||
EXPECT_EQ(1, wtx2.mapSaplingNoteData[sop0].witnesses.size()); // wtx2 has fake witness for payment output
|
||||
EXPECT_EQ(0, wtx2.mapSaplingNoteData[sop1].witnesses.size()); // wtx2 never had incrementnotewitness called
|
||||
EXPECT_EQ(0, wtx2.mapSaplingNoteData[sop1].witnesses.size()); // wtx2 never had BuildWitnessCache called
|
||||
|
||||
// After updating, they should be the same
|
||||
EXPECT_TRUE(wallet.UpdatedNoteData(wtx2, wtx));
|
||||
@@ -2040,8 +2038,8 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) {
|
||||
wallet.AddToWallet(wtx, true, NULL);
|
||||
|
||||
// Simulate receiving new block and ChainTip signal
|
||||
wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree);
|
||||
wallet.UpdateSaplingNullifierNoteMapForBlock(&block);
|
||||
wallet.BuildWitnessCache(&fakeIndex, false);
|
||||
wallet.UpdateNullifierNoteMapForBlock(&block);
|
||||
|
||||
// Retrieve the updated wtx from wallet
|
||||
uint256 hash = wtx.GetHash();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@
|
||||
#define BITCOIN_WALLET_WALLET_H
|
||||
|
||||
#include "amount.h"
|
||||
#include "asyncrpcoperation.h"
|
||||
#include "coins.h"
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
@@ -60,6 +61,11 @@ extern unsigned int nTxConfirmTarget;
|
||||
extern bool bSpendZeroConfChange;
|
||||
extern bool fSendFreeTransactions;
|
||||
extern bool fPayAtLeastCustomFee;
|
||||
extern bool fTxDeleteEnabled;
|
||||
extern bool fTxConflictDeleteEnabled;
|
||||
extern int fDeleteInterval;
|
||||
extern unsigned int fDeleteTransactionsAfterNBlocks;
|
||||
extern unsigned int fKeepLastNTransactions;
|
||||
|
||||
|
||||
//! -paytxfee default
|
||||
@@ -82,6 +88,18 @@ extern unsigned int WITNESS_CACHE_SIZE;
|
||||
//! Size of HD seed in bytes
|
||||
static const size_t HD_WALLET_SEED_LENGTH = 32;
|
||||
|
||||
//Default Transaction Rentention N-BLOCKS
|
||||
static const int DEFAULT_TX_DELETE_INTERVAL = 1000;
|
||||
|
||||
//Default Transaction Rentention N-BLOCKS
|
||||
static const unsigned int DEFAULT_TX_RETENTION_BLOCKS = 10000;
|
||||
|
||||
//Default Retenion Last N-Transactions
|
||||
static const unsigned int DEFAULT_TX_RETENTION_LASTTX = 200;
|
||||
|
||||
//Amount of transactions to delete per run while syncing
|
||||
static const int MAX_DELETE_TX_SIZE = 50000;
|
||||
|
||||
class CBlockIndex;
|
||||
class CCoinControl;
|
||||
class COutput;
|
||||
@@ -250,15 +268,18 @@ public:
|
||||
* -1 as a placeholder. The next time CWallet::ChainTip is called, we can
|
||||
* determine what height the witness cache for this note is valid for (even
|
||||
* if no witnesses were cached), and so can set the correct value in
|
||||
* CWallet::IncrementNoteWitnesses and CWallet::DecrementNoteWitnesses.
|
||||
* CWallet::BuildWitnessCache and CWallet::DecrementNoteWitnesses.
|
||||
*/
|
||||
int witnessHeight;
|
||||
|
||||
SproutNoteData() : address(), nullifier(), witnessHeight {-1} { }
|
||||
//In Memory Only
|
||||
bool witnessRootValidated;
|
||||
|
||||
SproutNoteData() : address(), nullifier(), witnessHeight {-1}, witnessRootValidated {false} { }
|
||||
SproutNoteData(libzcash::SproutPaymentAddress a) :
|
||||
address {a}, nullifier(), witnessHeight {-1} { }
|
||||
address {a}, nullifier(), witnessHeight {-1}, witnessRootValidated {false} { }
|
||||
SproutNoteData(libzcash::SproutPaymentAddress a, uint256 n) :
|
||||
address {a}, nullifier {n}, witnessHeight {-1} { }
|
||||
address {a}, nullifier {n}, witnessHeight {-1}, witnessRootValidated {false} { }
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
@@ -300,6 +321,9 @@ public:
|
||||
libzcash::SaplingIncomingViewingKey ivk;
|
||||
boost::optional<uint256> nullifier;
|
||||
|
||||
//In Memory Only
|
||||
bool witnessRootValidated;
|
||||
|
||||
ADD_SERIALIZE_METHODS;
|
||||
|
||||
template <typename Stream, typename Operation>
|
||||
@@ -779,6 +803,9 @@ private:
|
||||
typedef TxSpendMap<uint256> TxNullifiers;
|
||||
TxNullifiers mapTxSproutNullifiers;
|
||||
TxNullifiers mapTxSaplingNullifiers;
|
||||
|
||||
std::vector<CTransaction> pendingSaplingConsolidationTxs;
|
||||
AsyncRPCOperationId saplingConsolidationOperationId;
|
||||
|
||||
void AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid);
|
||||
void AddToSproutSpends(const uint256& nullifier, const uint256& wtxid);
|
||||
@@ -793,6 +820,7 @@ public:
|
||||
*/
|
||||
int64_t nWitnessCacheSize;
|
||||
bool needsRescan = false;
|
||||
bool fSaplingConsolidationEnabled = false;
|
||||
|
||||
void ClearNoteWitnessCache();
|
||||
|
||||
@@ -800,13 +828,16 @@ public:
|
||||
std::set<uint256> GetNullifiers();
|
||||
|
||||
protected:
|
||||
|
||||
int SproutWitnessMinimumHeight(const uint256& nullifier, int nWitnessHeight, int nMinimumHeight);
|
||||
int SaplingWitnessMinimumHeight(const uint256& nullifier, int nWitnessHeight, int nMinimumHeight);
|
||||
|
||||
/**
|
||||
* pindex is the new tip being connected.
|
||||
*/
|
||||
void IncrementNoteWitnesses(const CBlockIndex* pindex,
|
||||
const CBlock* pblock,
|
||||
SproutMerkleTree& sproutTree,
|
||||
SaplingMerkleTree& saplingTree);
|
||||
int VerifyAndSetInitialWitness(const CBlockIndex* pindex, bool witnessOnly);
|
||||
void BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly);
|
||||
|
||||
/**
|
||||
* pindex is the old tip being disconnected.
|
||||
*/
|
||||
@@ -1001,8 +1032,11 @@ public:
|
||||
bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const;
|
||||
|
||||
bool IsSpent(const uint256& hash, unsigned int n) const;
|
||||
unsigned int GetSpendDepth(const uint256& hash, unsigned int n) const;
|
||||
bool IsSproutSpent(const uint256& nullifier) const;
|
||||
unsigned int GetSproutSpendDepth(const uint256& nullifier) const;
|
||||
bool IsSaplingSpent(const uint256& nullifier) const;
|
||||
unsigned int GetSaplingSpendDepth(const uint256& nullifier) const;
|
||||
|
||||
bool IsLockedCoin(uint256 hash, unsigned int n) const;
|
||||
void LockCoin(COutPoint& output);
|
||||
@@ -1137,8 +1171,9 @@ public:
|
||||
void MarkDirty();
|
||||
bool UpdateNullifierNoteMap();
|
||||
void UpdateNullifierNoteMapWithTx(const CWalletTx& wtx);
|
||||
void UpdateSproutNullifierNoteMapWithTx(CWalletTx& wtx);
|
||||
void UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx);
|
||||
void UpdateSaplingNullifierNoteMapForBlock(const CBlock* pblock);
|
||||
void UpdateNullifierNoteMapForBlock(const CBlock* pblock);
|
||||
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
|
||||
void EraseFromWallet(const uint256 &hash);
|
||||
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
|
||||
@@ -1148,6 +1183,10 @@ public:
|
||||
std::vector<uint256> commitments,
|
||||
std::vector<boost::optional<SproutWitness>>& witnesses,
|
||||
uint256 &final_anchor);
|
||||
void ReorderWalletTransactions(std::map<std::pair<int,int>, CWalletTx> &mapSorted, int64_t &maxOrderPos);
|
||||
void UpdateWalletTransactionOrder(std::map<std::pair<int,int>, CWalletTx> &mapSorted, bool resetOrder);
|
||||
void DeleteTransactions(std::vector<uint256> &removeTxs);
|
||||
void DeleteWalletTransactions(const CBlockIndex* pindex);
|
||||
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
|
||||
void ReacceptWalletTransactions();
|
||||
void ResendWalletTransactions(int64_t nBestBlockTime);
|
||||
@@ -1215,6 +1254,8 @@ public:
|
||||
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
||||
CAmount GetChange(const CTransaction& tx) const;
|
||||
void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added);
|
||||
void RunSaplingConsolidation(int blockHeight);
|
||||
void CommitConsolidationTx(const CTransaction& tx);
|
||||
/** Saves witness caches and best block locator to disk. */
|
||||
void SetBestChain(const CBlockLocator& loc);
|
||||
std::set<std::pair<libzcash::PaymentAddress, uint256>> GetNullifiersForAddresses(const std::set<libzcash::PaymentAddress> & addresses);
|
||||
|
||||
@@ -1208,6 +1208,12 @@ bool BackupWallet(const CWallet& wallet, const string& strDest)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CWalletDB::Compact(CDBEnv& dbenv, const std::string& strFile)
|
||||
{
|
||||
bool fSuccess = dbenv.Compact(strFile);
|
||||
return fSuccess;
|
||||
}
|
||||
|
||||
//
|
||||
// Try to (very carefully!) recover wallet.dat if there is a problem.
|
||||
//
|
||||
|
||||
@@ -189,6 +189,7 @@ public:
|
||||
DBErrors LoadWallet(CWallet* pwallet);
|
||||
DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx);
|
||||
DBErrors ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx);
|
||||
static bool Compact(CDBEnv& dbenv, const std::string& strFile);
|
||||
static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys);
|
||||
static bool Recover(CDBEnv& dbenv, const std::string& filename);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user