Hush Full Node software. We were censored from Github, this is where all development happens now. https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1502 lines
51 KiB

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2019-2020 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. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#ifndef BITCOIN_WALLET_WALLET_H
#define BITCOIN_WALLET_WALLET_H
#include "amount.h"
#include "asyncrpcoperation.h"
#include "coins.h"
#include "key.h"
#include "keystore.h"
#include "main.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "tinyformat.h"
#include "ui_interface.h"
#include "util.h"
#include "utilstrencodings.h"
#include "validationinterface.h"
#include "wallet/crypter.h"
#include "wallet/wallet_ismine.h"
#include "wallet/walletdb.h"
#include "wallet/rpcwallet.h"
#include "zcash/Address.hpp"
#include "zcash/zip32.h"
#include "base58.h"
#include <algorithm>
#include <map>
#include <set>
#include <stdexcept>
#include <stdint.h>
#include <string>
#include <utility>
#include <vector>
/**
* Settings
*/
extern CFeeRate payTxFee;
extern CAmount maxTxFee;
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
static const CAmount DEFAULT_TRANSACTION_FEE = 0;
//! -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB
static const CAmount nHighTransactionFeeWarning = 0.01 * COIN;
//! -maxtxfee default
static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
//! -txconfirmtarget default
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning;
//! Largest (in bytes) free transaction we're willing to create
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
//! Size of witness cache
// Should be large enough that we can expect not to reorg beyond our cache
// unless there is some exceptional network disruption.
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 Retention 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;
extern const char * DEFAULT_WALLET_DAT;
class CBlockIndex;
class CCoinControl;
class COutput;
class CReserveKey;
class CScript;
class CTxMemPool;
class CWalletTx;
/** (client) version numbers for particular wallet features */
enum WalletFeature
{
FEATURE_BASE = 10500, // the earliest version new wallets supports (only useful for getinfo's clientversion output)
FEATURE_WALLETCRYPT = 40000, // wallet encryption
FEATURE_COMPRPUBKEY = 60000, // compressed public keys
FEATURE_LATEST = 60000
};
/** A key pool entry */
class CKeyPool
{
public:
int64_t nTime;
CPubKey vchPubKey;
CKeyPool();
CKeyPool(const CPubKey& vchPubKeyIn);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(nTime);
READWRITE(vchPubKey);
}
};
/** Address book data */
class CAddressBookData
{
public:
std::string name;
std::string purpose;
CAddressBookData()
{
purpose = "unknown";
}
typedef std::map<std::string, std::string> StringMap;
StringMap destdata;
};
struct CRecipient
{
CScript scriptPubKey;
CAmount nAmount;
bool fSubtractFeeFromAmount;
};
typedef std::map<std::string, std::string> mapValue_t;
static void ReadOrderPos(int64_t& nOrderPos, mapValue_t& mapValue)
{
if (!mapValue.count("n"))
{
nOrderPos = -1; // TODO: calculate elsewhere
return;
}
nOrderPos = atoi64(mapValue["n"].c_str());
}
static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue)
{
if (nOrderPos == -1)
return;
mapValue["n"] = i64tostr(nOrderPos);
}
struct COutputEntry
{
CTxDestination destination;
CAmount amount;
int vout;
};
/** A note outpoint */
class JSOutPoint
{
public:
// Transaction hash
uint256 hash;
// Index into CTransaction.vjoinsplit
uint64_t js;
// Index into JSDescription fields of length ZC_NUM_JS_OUTPUTS
uint8_t n;
JSOutPoint() { SetNull(); }
JSOutPoint(uint256 h, uint64_t js, uint8_t n) : hash {h}, js {js}, n {n} { }
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(hash);
READWRITE(js);
READWRITE(n);
}
void SetNull() { hash.SetNull(); }
bool IsNull() const { return hash.IsNull(); }
friend bool operator<(const JSOutPoint& a, const JSOutPoint& b) {
return (a.hash < b.hash ||
(a.hash == b.hash && a.js < b.js) ||
(a.hash == b.hash && a.js == b.js && a.n < b.n));
}
friend bool operator==(const JSOutPoint& a, const JSOutPoint& b) {
return (a.hash == b.hash && a.js == b.js && a.n == b.n);
}
friend bool operator!=(const JSOutPoint& a, const JSOutPoint& b) {
return !(a == b);
}
std::string ToString() const;
};
// NOTE: wallet.dat format depends on this data structure :(
class SproutNoteData
{
public:
libzcash::SproutPaymentAddress address;
/**
* Cached note nullifier. May not be set if the wallet was not unlocked when
* this was SproutNoteData was created. If not set, we always assume that the
* note has not been spent.
*
* It's okay to cache the nullifier in the wallet, because we are storing
* the spending key there too, which could be used to derive this.
* If the wallet is encrypted, this means that someone with access to the
* locked wallet cannot spend notes, but can connect received notes to the
* transactions they are spent in. This is the same security semantics as
* for transparent addresses.
*/
boost::optional<uint256> nullifier;
/**
* Cached incremental witnesses for spendable Notes.
* Beginning of the list is the most recent witness.
*/
std::list<SproutWitness> witnesses;
/**
* Block height corresponding to the most current witness.
*
* When we first create a SaplingNoteData in CWallet::FindMySaplingNotes, this is set to
* -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::BuildWitnessCache and CWallet::DecrementNoteWitnesses.
*/
int witnessHeight;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(address);
READWRITE(nullifier);
READWRITE(witnesses);
READWRITE(witnessHeight);
}
};
class SaplingNoteData
{
public:
/**
* Block height corresponding to the most current witness.
*
* When we first create a SaplingNoteData in CWallet::FindMySaplingNotes, this is set to
* -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::BuildWitnessCache and CWallet::DecrementNoteWitnesses.
*/
SaplingNoteData() : witnessHeight {-1}, nullifier() { }
SaplingNoteData(libzcash::SaplingIncomingViewingKey ivk) : ivk {ivk}, witnessHeight {-1}, nullifier() { }
SaplingNoteData(libzcash::SaplingIncomingViewingKey ivk, uint256 n) : ivk {ivk}, witnessHeight {-1}, nullifier(n) { }
std::list<SaplingWitness> witnesses;
int witnessHeight;
libzcash::SaplingIncomingViewingKey ivk;
boost::optional<uint256> nullifier;
//In Memory Only
bool witnessRootValidated;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH)) {
READWRITE(nVersion);
}
READWRITE(ivk);
READWRITE(nullifier);
READWRITE(witnesses);
READWRITE(witnessHeight);
}
friend bool operator==(const SaplingNoteData& a, const SaplingNoteData& b) {
return (a.ivk == b.ivk && a.nullifier == b.nullifier && a.witnessHeight == b.witnessHeight);
}
friend bool operator!=(const SaplingNoteData& a, const SaplingNoteData& b) {
return !(a == b);
}
};
// NOTE: this sprout structure is serialized into wallet.dat, removing it would change wallet.dat format on disk :(
typedef std::map<JSOutPoint, SproutNoteData> mapSproutNoteData_t;
typedef std::map<SaplingOutPoint, SaplingNoteData> mapSaplingNoteData_t;
/** Sapling note, its location in a transaction, and number of confirmations. */
struct SaplingNoteEntry
{
SaplingOutPoint op;
libzcash::SaplingPaymentAddress address;
libzcash::SaplingNote note;
std::array<unsigned char, ZC_MEMO_SIZE> memo;
int confirmations;
};
/** A transaction with a merkle branch linking it to the block chain. */
class CMerkleTx : public CTransaction
{
private:
int GetDepthInMainChainINTERNAL(const CBlockIndex* &pindexRet) const;
public:
uint256 hashBlock;
std::vector<uint256> vMerkleBranch;
int nIndex;
// memory only
mutable bool fMerkleVerified;
CMerkleTx()
{
Init();
}
CMerkleTx(const CTransaction& txIn) : CTransaction(txIn)
{
Init();
}
void Init()
{
hashBlock = uint256();
nIndex = -1;
fMerkleVerified = false;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CTransaction*)this);
READWRITE(hashBlock);
READWRITE(vMerkleBranch);
READWRITE(nIndex);
}
void SetMerkleBranch(const CBlock& block);
/**
* Return depth of transaction in blockchain:
* -1 : not in blockchain, and not in memory pool (conflicted transaction)
* 0 : in memory pool, waiting to be included in a block
* >=1 : this many blocks deep in the main chain
*/
int GetDepthInMainChain(const CBlockIndex* &pindexRet) const;
int GetDepthInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChain(pindexRet); }
bool IsInMainChain() const { const CBlockIndex *pindexRet; return GetDepthInMainChainINTERNAL(pindexRet) > 0; }
int GetBlocksToMaturity() const;
bool AcceptToMemoryPool(bool fLimitFree=true, bool fRejectAbsurdFee=true);
};
/**
* A transaction with a bunch of additional info that only the owner cares about.
* It includes any unrecorded transactions needed to link it back to the block chain.
*/
class CWalletTx : public CMerkleTx
{
private:
const CWallet* pwallet;
public:
mapValue_t mapValue;
mapSproutNoteData_t mapSproutNoteData;
mapSaplingNoteData_t mapSaplingNoteData;
std::vector<std::pair<std::string, std::string> > vOrderForm;
unsigned int fTimeReceivedIsTxTime;
unsigned int nTimeReceived; //! time received by this node
unsigned int nTimeSmart;
char fFromMe;
std::string strFromAccount;
int64_t nOrderPos; //! position in ordered transaction list
// memory only
mutable bool fDebitCached;
mutable bool fCreditCached;
mutable bool fImmatureCreditCached;
mutable bool fAvailableCreditCached;
mutable bool fWatchDebitCached;
mutable bool fWatchCreditCached;
mutable bool fImmatureWatchCreditCached;
mutable bool fAvailableWatchCreditCached;
mutable bool fChangeCached;
mutable CAmount nDebitCached;
mutable CAmount nCreditCached;
mutable CAmount nImmatureCreditCached;
mutable CAmount nAvailableCreditCached;
mutable CAmount nWatchDebitCached;
mutable CAmount nWatchCreditCached;
mutable CAmount nImmatureWatchCreditCached;
mutable CAmount nAvailableWatchCreditCached;
mutable CAmount nChangeCached;
CWalletTx()
{
Init(NULL);
}
CWalletTx(const CWallet* pwalletIn)
{
Init(pwalletIn);
}
CWalletTx(const CWallet* pwalletIn, const CMerkleTx& txIn) : CMerkleTx(txIn)
{
Init(pwalletIn);
}
CWalletTx(const CWallet* pwalletIn, const CTransaction& txIn) : CMerkleTx(txIn)
{
Init(pwalletIn);
}
void Init(const CWallet* pwalletIn)
{
pwallet = pwalletIn;
mapValue.clear();
mapSproutNoteData.clear();
mapSaplingNoteData.clear();
vOrderForm.clear();
fTimeReceivedIsTxTime = false;
nTimeReceived = 0;
nTimeSmart = 0;
fFromMe = false;
strFromAccount.clear();
fDebitCached = false;
fCreditCached = false;
fImmatureCreditCached = false;
fAvailableCreditCached = false;
fWatchDebitCached = false;
fWatchCreditCached = false;
fImmatureWatchCreditCached = false;
fAvailableWatchCreditCached = false;
fChangeCached = false;
nDebitCached = 0;
nCreditCached = 0;
nImmatureCreditCached = 0;
nAvailableCreditCached = 0;
nWatchDebitCached = 0;
nWatchCreditCached = 0;
nAvailableWatchCreditCached = 0;
nImmatureWatchCreditCached = 0;
nChangeCached = 0;
nOrderPos = -1;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
if (ser_action.ForRead())
Init(NULL);
char fSpent = false;
if (!ser_action.ForRead())
{
mapValue["fromaccount"] = strFromAccount;
WriteOrderPos(nOrderPos, mapValue);
if (nTimeSmart)
mapValue["timesmart"] = strprintf("%u", nTimeSmart);
}
READWRITE(*(CMerkleTx*)this);
std::vector<CMerkleTx> vUnused; //! Used to be vtxPrev
READWRITE(vUnused);
READWRITE(mapValue);
READWRITE(mapSproutNoteData);
READWRITE(vOrderForm);
READWRITE(fTimeReceivedIsTxTime);
READWRITE(nTimeReceived);
READWRITE(fFromMe);
READWRITE(fSpent);
if (fOverwintered && nVersion >= SAPLING_TX_VERSION) {
READWRITE(mapSaplingNoteData);
}
if (ser_action.ForRead())
{
strFromAccount = mapValue["fromaccount"];
ReadOrderPos(nOrderPos, mapValue);
nTimeSmart = mapValue.count("timesmart") ? (unsigned int)atoi64(mapValue["timesmart"]) : 0;
}
mapValue.erase("fromaccount");
mapValue.erase("version");
mapValue.erase("spent");
mapValue.erase("n");
mapValue.erase("timesmart");
}
//! make sure balances are recalculated
void MarkDirty()
{
fCreditCached = false;
fAvailableCreditCached = false;
fWatchDebitCached = false;
fWatchCreditCached = false;
fAvailableWatchCreditCached = false;
fImmatureWatchCreditCached = false;
fDebitCached = false;
fChangeCached = false;
}
void BindWallet(CWallet *pwalletIn)
{
pwallet = pwalletIn;
MarkDirty();
}
void SetSaplingNoteData(mapSaplingNoteData_t &noteData);
boost::optional<std::pair<
libzcash::SaplingNotePlaintext,
libzcash::SaplingPaymentAddress>> DecryptSaplingNote(SaplingOutPoint op) const;
boost::optional<std::pair<
libzcash::SaplingNotePlaintext,
libzcash::SaplingPaymentAddress>> RecoverSaplingNote(
SaplingOutPoint op, std::set<uint256>& ovks) const;
//! filter decides which addresses will count towards the debit
CAmount GetDebit(const isminefilter& filter) const;
CAmount GetCredit(const isminefilter& filter) const;
CAmount GetImmatureCredit(bool fUseCache=true) const;
CAmount GetAvailableCredit(bool fUseCache=true) const;
CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const;
CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const;
CAmount GetChange() const;
void GetAmounts(std::list<COutputEntry>& listReceived,
std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const;
void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived,
CAmount& nSent, CAmount& nFee, const isminefilter& filter) const;
bool IsFromMe(const isminefilter& filter) const
{
return (GetDebit(filter) > 0);
}
bool IsTrusted() const;
bool WriteToDisk(CWalletDB *pwalletdb);
int64_t GetTxTime() const;
int GetRequestCount() const;
bool RelayWalletTransaction();
std::set<uint256> GetConflicts() const;
};
class COutput
{
public:
const CWalletTx *tx;
int i;
int nDepth;
bool fSpendable;
COutput(const CWalletTx *txIn, int iIn, int nDepthIn, bool fSpendableIn)
{
tx = txIn; i = iIn; nDepth = nDepthIn; fSpendable = fSpendableIn;
}
std::string ToString() const;
};
/** Private key that includes an expiration date in case it never gets used. */
class CWalletKey
{
public:
CPrivKey vchPrivKey;
int64_t nTimeCreated;
int64_t nTimeExpires;
std::string strComment;
//! todo: add something to note what created it (user, getnewaddress, change)
//! maybe should have a map<string, string> property map
CWalletKey(int64_t nExpires=0);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vchPrivKey);
READWRITE(nTimeCreated);
READWRITE(nTimeExpires);
READWRITE(LIMITED_STRING(strComment, 65536));
}
};
/**
* Internal transfers.
* Database key is acentry<account><counter>.
*/
class CAccountingEntry
{
public:
std::string strAccount;
CAmount nCreditDebit;
int64_t nTime;
std::string strOtherAccount;
std::string strComment;
mapValue_t mapValue;
int64_t nOrderPos; //! position in ordered transaction list
uint64_t nEntryNo;
CAccountingEntry()
{
SetNull();
}
void SetNull()
{
nCreditDebit = 0;
nTime = 0;
strAccount.clear();
strOtherAccount.clear();
strComment.clear();
nOrderPos = -1;
nEntryNo = 0;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
//! Note: strAccount is serialized as part of the key, not here.
READWRITE(nCreditDebit);
READWRITE(nTime);
READWRITE(LIMITED_STRING(strOtherAccount, 65536));
if (!ser_action.ForRead())
{
WriteOrderPos(nOrderPos, mapValue);
if (!(mapValue.empty() && _ssExtra.empty()))
{
CDataStream ss(s.GetType(), s.GetVersion());
ss.insert(ss.begin(), '\0');
ss << mapValue;
ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
strComment.append(ss.str());
}
}
READWRITE(LIMITED_STRING(strComment, 65536));
size_t nSepPos = strComment.find("\0", 0, 1);
if (ser_action.ForRead())
{
mapValue.clear();
if (std::string::npos != nSepPos)
{
CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), s.GetType(), s.GetVersion());
ss >> mapValue;
_ssExtra = std::vector<char>(ss.begin(), ss.end());
}
ReadOrderPos(nOrderPos, mapValue);
}
if (std::string::npos != nSepPos)
strComment.erase(nSepPos);
mapValue.erase("n");
}
private:
std::vector<char> _ssExtra;
};
/**
* A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,
* and provides the ability to create new transactions.
*/
class CWallet : public CCryptoKeyStore, public CValidationInterface
{
private:
bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool& fOnlyCoinbaseCoinsRet, bool& fNeedCoinbaseCoinsRet, const CCoinControl *coinControl = NULL) const;
CWalletDB *pwalletdbEncryption;
//! the current wallet version: clients below this version are not able to load the wallet
int nWalletVersion;
//! the maximum wallet format version: memory-only variable that specifies to what version this wallet may be upgraded
int nWalletMaxVersion;
int64_t nNextResend;
int64_t nLastResend;
bool fBroadcastTransactions;
template <class T>
using TxSpendMap = std::multimap<T, uint256>;
/**
* Used to keep track of spent outpoints, and
* detect and report conflicts (double-spends or
* mutated transactions where the mutant gets mined).
*/
typedef TxSpendMap<COutPoint> TxSpends;
TxSpends mapTxSpends;
/**
* Used to keep track of spent Notes, and
* detect and report conflicts (double-spends).
*/
typedef TxSpendMap<uint256> TxNullifiers;
TxNullifiers mapTxSaplingNullifiers;
std::vector<CTransaction> pendingSaplingConsolidationTxs;
AsyncRPCOperationId saplingConsolidationOperationId;
void AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid);
void AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid);
void AddToSpends(const uint256& wtxid);
public:
/*
* Size of the incremental witness cache for the notes in our wallet.
* This will always be greater than or equal to the size of the largest
* incremental witness cache in any transaction in mapWallet.
*/
int64_t nWitnessCacheSize;
bool needsRescan = false;
bool fSaplingConsolidationEnabled = false;
void ClearNoteWitnessCache();
int64_t NullifierCount();
std::set<uint256> GetNullifiers();
protected:
int SaplingWitnessMinimumHeight(const uint256& nullifier, int nWitnessHeight, int nMinimumHeight);
/**
* pindex is the new tip being connected.
*/
int VerifyAndSetInitialWitness(const CBlockIndex* pindex, bool witnessOnly);
void BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly);
/**
* pindex is the old tip being disconnected.
*/
void DecrementNoteWitnesses(const CBlockIndex* pindex);
template <typename WalletDB>
void SetBestChainINTERNAL(WalletDB& walletdb, const CBlockLocator& loc) {
if (!walletdb.TxnBegin()) {
// This needs to be done atomically, so don't do it at all
LogPrintf("SetBestChain(): Couldn't start atomic write\n");
return;
}
try {
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
auto wtx = wtxItem.second;
// We skip transactions for which mapSaplingNoteData
// is empty. This covers transactions that have no Sapling data
// (i.e. are purely transparent), as well as shielding and unshielding
// transactions in which we only have transparent addresses involved.
if (!(wtx.mapSaplingNoteData.empty())) {
if (!walletdb.WriteTx(wtxItem.first, wtx)) {
LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n");
walletdb.TxnAbort();
return;
}
}
}
if (!walletdb.WriteWitnessCacheSize(nWitnessCacheSize)) {
LogPrintf("SetBestChain(): Failed to write nWitnessCacheSize, aborting atomic write\n");
walletdb.TxnAbort();
return;
}
if (!walletdb.WriteBestBlock(loc)) {
LogPrintf("SetBestChain(): Failed to write best block, aborting atomic write\n");
walletdb.TxnAbort();
return;
}
} catch (const std::exception &exc) {
// Unexpected failure
LogPrintf("SetBestChain(): Unexpected error during atomic write:\n");
LogPrintf("%s\n", exc.what());
walletdb.TxnAbort();
return;
}
if (!walletdb.TxnCommit()) {
// Couldn't commit all to db, but in-memory state is fine
LogPrintf("SetBestChain(): Couldn't commit atomic write\n");
return;
}
}
private:
template <class T>
void SyncMetaData(std::pair<typename TxSpendMap<T>::iterator, typename TxSpendMap<T>::iterator>);
protected:
bool UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx);
void MarkAffectedTransactionsDirty(const CTransaction& tx);
/* the hd chain data model (chain counters) */
CHDChain hdChain;
public:
/*
* Main wallet lock.
* This lock protects all the fields added by CWallet
* except for:
* fFileBacked (immutable after instantiation)
* strWalletFile (immutable after instantiation)
*/
mutable CCriticalSection cs_wallet;
bool fFileBacked;
std::string strWalletFile;
std::set<int64_t> setKeyPool;
std::map<CKeyID, CKeyMetadata> mapKeyMetadata;
std::map<libzcash::SaplingIncomingViewingKey, CKeyMetadata> mapSaplingZKeyMetadata;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
unsigned int nMasterKeyMaxID;
CWallet()
{
SetNull();
}
CWallet(const std::string& strWalletFileIn)
{
SetNull();
strWalletFile = strWalletFileIn;
fFileBacked = true;
}
~CWallet()
{
delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
}
void SetNull()
{
nWalletVersion = FEATURE_BASE;
nWalletMaxVersion = FEATURE_BASE;
fFileBacked = false;
nMasterKeyMaxID = 0;
pwalletdbEncryption = NULL;
nOrderPosNext = 0;
nNextResend = 0;
nLastResend = 0;
nTimeFirstKey = 0;
fBroadcastTransactions = false;
nWitnessCacheSize = 0;
}
/**
* The reverse mapping of nullifiers to notes.
*
* The mapping cannot be updated while an encrypted wallet is locked,
* because we need the SpendingKey to create the nullifier (#1502). This has
* several implications for transactions added to the wallet while locked:
*
* - Parent transactions can't be marked dirty when a child transaction that
* spends their output notes is updated.
*
* - We currently don't cache any note values, so this is not a problem,
* yet.
*
* - GetFilteredNotes can't filter out spent notes.
*
* - Per the comment in SproutNoteData, we assume that if we don't have a
* cached nullifier, the note is not spent.
*
* Another more problematic implication is that the wallet can fail to
* detect transactions on the blockchain that spend our notes. There are two
* possible cases in which this could happen:
*
* - We receive a note when the wallet is locked, and then spend it using a
* different wallet client.
*
* - We spend from a PaymentAddress we control, then we export the
* SpendingKey and import it into a new wallet, and reindex/rescan to find
* the old transactions.
*
* The wallet will only miss "pure" spends - transactions that are only
* linked to us by the fact that they contain notes we spent. If it also
* sends notes to us, or interacts with our transparent addresses, we will
* detect the transaction and add it to the wallet (again without caching
* nullifiers for new notes). As by default JoinSplits send change back to
* the origin PaymentAddress, the wallet should rarely miss transactions.
*
* To work around these issues, whenever the wallet is unlocked, we scan all
* cached notes, and cache any missing nullifiers. Since the wallet must be
* unlocked in order to spend notes, this means that GetFilteredNotes will
* always behave correctly within that context (and any other uses will give
* correct responses afterwards), for the transactions that the wallet was
* able to detect. Any missing transactions can be rediscovered by:
*
* - Unlocking the wallet (to fill all nullifier caches).
*
* - Restarting the node with -reindex (which operates on a locked wallet
* but with the now-cached nullifiers).
*/
std::map<uint256, JSOutPoint> mapSproutNullifiersToNotes;
std::map<uint256, SaplingOutPoint> mapSaplingNullifiersToNotes;
std::map<uint256, CWalletTx> mapWallet;
int64_t nOrderPosNext;
std::map<uint256, int> mapRequestCount;
std::map<CTxDestination, CAddressBookData> mapAddressBook;
CPubKey vchDefaultKey;
std::set<COutPoint> setLockedCoins;
std::set<JSOutPoint> setLockedSproutNotes;
std::set<SaplingOutPoint> setLockedSaplingNotes;
int64_t nTimeFirstKey;
const CWalletTx* GetWalletTx(const uint256& hash) const;
//! check whether we are allowed to upgrade (or already support) to the named feature
bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL, bool fIncludeZeroValue=false, bool fIncludeCoinBase=true) const;
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 IsSaplingSpent(const uint256& nullifier) const;
unsigned int GetSaplingSpendDepth(const uint256& nullifier) const;
bool IsLockedCoin(uint256 hash, unsigned int n) const;
void LockCoin(COutPoint& output);
void UnlockCoin(COutPoint& output);
void UnlockAllCoins();
void ListLockedCoins(std::vector<COutPoint>& vOutpts);
bool IsLockedNote(const JSOutPoint& outpt) const;
void LockNote(const JSOutPoint& output);
void UnlockNote(const JSOutPoint& output);
bool IsLockedNote(const SaplingOutPoint& output) const;
void LockNote(const SaplingOutPoint& output);
void UnlockNote(const SaplingOutPoint& output);
void UnlockAllSaplingNotes();
std::vector<SaplingOutPoint> ListLockedSaplingNotes();
/**
* keystore implementation
* Generate a new key
*/
CPubKey GenerateNewKey();
//! Adds a key to the store, and saves it to disk.
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
//! Adds a key to the store, without saving it to disk (used by LoadWallet)
bool LoadKey(const CKey& key, const CPubKey &pubkey) { return CCryptoKeyStore::AddKeyPubKey(key, pubkey); }
//! Load metadata (used by LoadWallet)
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);
bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
//! Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
bool AddCScript(const CScript& redeemScript);
bool LoadCScript(const CScript& redeemScript);
//! Adds a destination data tuple to the store, and saves it to disk
bool AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value);
//! Erases a destination data tuple in the store and on disk
bool EraseDestData(const CTxDestination &dest, const std::string &key);
//! Adds a destination data tuple to the store, without saving it to disk
bool LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value);
//! Look up a destination data tuple in the store, return true if found false otherwise
bool GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const;
//! Adds a watch-only address to the store, and saves it to disk.
bool AddWatchOnly(const CScript &dest);
bool RemoveWatchOnly(const CScript &dest);
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CScript &dest);
bool Unlock(const SecureString& strWalletPassphrase);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase);
void GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const;
/**
* Sapling ZKeys
*/
//! Generates new Sapling key
// Sietch uses addToWallet=false
libzcash::SaplingPaymentAddress GenerateNewSaplingZKey(bool addToWallet=true);
//! Adds Sapling spending key to the store, and saves it to disk
bool AddSaplingZKey(
const libzcash::SaplingExtendedSpendingKey &key,
const libzcash::SaplingPaymentAddress &defaultAddr);
bool AddSaplingIncomingViewingKey(
const libzcash::SaplingIncomingViewingKey &ivk,
const libzcash::SaplingPaymentAddress &addr);
bool AddCryptedSaplingSpendingKey(
const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::vector<unsigned char> &vchCryptedSecret,
const libzcash::SaplingPaymentAddress &defaultAddr);
//! Adds spending key to the store, without saving it to disk (used by LoadWallet)
bool LoadSaplingZKey(const libzcash::SaplingExtendedSpendingKey &key);
//! Load spending key metadata (used by LoadWallet)
bool LoadSaplingZKeyMetadata(const libzcash::SaplingIncomingViewingKey &ivk, const CKeyMetadata &meta);
//! Adds a Sapling payment address -> incoming viewing key map entry,
//! without saving it to disk (used by LoadWallet)
bool LoadSaplingPaymentAddress(
const libzcash::SaplingPaymentAddress &addr,
const libzcash::SaplingIncomingViewingKey &ivk);
//! Adds an encrypted spending key to the store, without saving it to disk (used by LoadWallet)
bool LoadCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk,
const std::vector<unsigned char> &vchCryptedSecret);
/**
* Increment the next transaction order id
* @return next transaction order id
*/
int64_t IncOrderPosNext(CWalletDB *pwalletdb = NULL);
typedef std::pair<CWalletTx*, CAccountingEntry*> TxPair;
typedef std::multimap<int64_t, TxPair > TxItems;
/**
* Get the wallet's activity log
* @return multimap of ordered transactions and accounting entries
* @warning Returned pointers are *only* valid within the scope of passed acentries
*/
TxItems OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount = "");
void MarkDirty();
bool UpdateNullifierNoteMap();
void UpdateNullifierNoteMapWithTx(const CWalletTx& wtx);
void UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx);
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);
void RescanWallet();
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
void WitnessNoteCommitment(
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);
std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime);
CAmount GetBalance() const;
CAmount GetUnconfirmedBalance() const;
CAmount GetImmatureBalance() const;
CAmount GetWatchOnlyBalance() const;
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason);
bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet,
std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
static CFeeRate minTxFee;
static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool);
bool NewKeyPool();
bool TopUpKeyPool(unsigned int kpSize = 0);
void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool);
void KeepKey(int64_t nIndex);
void ReturnKey(int64_t nIndex);
bool GetKeyFromPool(CPubKey &key);
int64_t GetOldestKeyPoolTime();
void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
std::pair<mapSaplingNoteData_t, SaplingIncomingViewingKeyMap> FindMySaplingNotes(const CTransaction& tx) const;
bool IsSaplingNullifierFromMe(const uint256& nullifier) const;
void GetSaplingNoteWitnesses(
std::vector<SaplingOutPoint> notes,
std::vector<boost::optional<SaplingWitness>>& witnesses,
uint256 &final_anchor);
isminetype IsMine(const CTxIn& txin) const;
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
isminetype IsMine(const CTxOut& txout) const;
isminetype IsMine(const CTransaction& tx, uint32_t voutNum);
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
bool IsChange(const CTxOut& txout) const;
CAmount GetChange(const CTxOut& txout) const;
bool IsMine(const CTransaction& tx);
/** should probably be renamed to IsRelevantToMe */
bool IsFromMe(const CTransaction& tx) const;
CAmount GetDebit(const CTransaction& tx, 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 GetChange(const CTransaction& tx) const;
void ChainTip(
const CBlockIndex *pindex,
const CBlock *pblock,
boost::optional<std::pair<SproutMerkleTree, SaplingMerkleTree>> added);
void RunSaplingConsolidation(int blockHeight);
bool 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);
bool IsNoteSproutChange(const std::set<std::pair<libzcash::PaymentAddress, uint256>> & nullifierSet, const libzcash::PaymentAddress & address, const JSOutPoint & entry);
bool IsNoteSaplingChange(const std::set<std::pair<libzcash::PaymentAddress, uint256>> & nullifierSet, const libzcash::PaymentAddress & address, const SaplingOutPoint & entry);
DBErrors LoadWallet(bool& fFirstRunRet);
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose);
bool DelAddressBook(const CTxDestination& address);
void UpdatedTransaction(const uint256 &hashTx);
void Inventory(const uint256 &hash)
{
{
LOCK(cs_wallet);
std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
if (mi != mapRequestCount.end())
(*mi).second++;
}
}
//void GetScriptForMining(boost::shared_ptr<CReserveScript> &script);
void ResetRequestCount(const uint256 &hash)
{
LOCK(cs_wallet);
mapRequestCount[hash] = 0;
};
unsigned int GetKeyPoolSize()
{
AssertLockHeld(cs_wallet); // setKeyPool
return setKeyPool.size();
}
bool SetDefaultKey(const CPubKey &vchPubKey);
//! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = NULL, bool fExplicit = false);
//! change which version we're allowed to upgrade to (note that this does not immediately imply upgrading to that format)
bool SetMaxVersion(int nVersion);
//! get the current wallet format (the oldest client version guaranteed to understand this wallet)
int GetVersion() { LOCK(cs_wallet); return nWalletVersion; }
//! Get wallet transactions that conflict with given transaction (spend same outputs)
std::set<uint256> GetConflicts(const uint256& txid) const;
//! Flush wallet (bitdb flush)
void Flush(bool shutdown=false);
//! Verify the wallet database and perform salvage if required
static bool Verify(const std::string& walletFile, std::string& warningString, std::string& errorString);
/**
* Address book entry changed.
* @note called with lock cs_wallet held.
*/
boost::signals2::signal<void (CWallet *wallet, const CTxDestination
&address, const std::string &label, bool isMine,
const std::string &purpose,
ChangeType status)> NotifyAddressBookChanged;
/**
* Wallet transaction added, removed or updated.
* @note called with lock cs_wallet held.
*/
boost::signals2::signal<void (CWallet *wallet, const uint256 &hashTx,
ChangeType status)> NotifyTransactionChanged;
/** Show progress e.g. for rescan */
boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;
/** Watch-only address added */
boost::signals2::signal<void (bool fHaveWatchOnly)> NotifyWatchonlyChanged;
/** Inquire whether this wallet broadcasts transactions. */
bool GetBroadcastTransactions() const { return fBroadcastTransactions; }
/** Set whether this wallet broadcasts transactions. */
void SetBroadcastTransactions(bool broadcast) { fBroadcastTransactions = broadcast; }
/* Returns true if HD is enabled for all address types, false if only for Sapling */
bool IsHDFullyEnabled() const;
/* Generates a new HD seed (will reset the chain child index counters)
Sets the seed's version based on the current wallet version (so the
caller must ensure the current wallet version is correct before calling
this function). */
void GenerateNewSeed();
bool SetHDSeed(const HDSeed& seed);
bool SetCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char> &vchCryptedSecret);
/* Set the HD chain model (chain child index counters) */
void SetHDChain(const CHDChain& chain, bool memonly);
const CHDChain& GetHDChain() const { return hdChain; }
/* Set the current HD seed, without saving it to disk (used by LoadWallet) */
bool LoadHDSeed(const HDSeed& key);
/* Set the current encrypted HD seed, without saving it to disk (used by LoadWallet) */
bool LoadCryptedHDSeed(const uint256& seedFp, const std::vector<unsigned char>& seed);
/* Find notes filtered by payment address, min depth, ability to spend */
void GetFilteredNotes(std::vector<SaplingNoteEntry>& saplingEntries,
std::string address,
int minDepth=1,
bool ignoreSpent=true,
bool requireSpendingKey=true);
/* Find notes filtered by payment addresses, min depth, max depth, if they are spent,
if a spending key is required, and if they are locked */
void GetFilteredNotes(std::vector<SaplingNoteEntry>& saplingEntries,
std::set<libzcash::PaymentAddress>& filterAddresses,
int minDepth=1,
int maxDepth=INT_MAX,
bool ignoreSpent=true,
bool requireSpendingKey=true,
bool ignoreLocked=true);
};
/** A key allocated from the key pool. */
class CReserveKey
{
protected:
CWallet* pwallet;
int64_t nIndex;
CPubKey vchPubKey;
public:
CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn;
}
~CReserveKey()
{
ReturnKey();
}
void ReturnKey();
virtual bool GetReservedKey(CPubKey &pubkey);
void KeepKey();
};
/**
* Account information.
* Stored in wallet with key "acc"+string account name.
*/
class CAccount
{
public:
CPubKey vchPubKey;
CAccount()
{
SetNull();
}
void SetNull()
{
vchPubKey = CPubKey();
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vchPubKey);
}
};
/** Error status printout */
#define ERR_RESULT(x) result.push_back(Pair("result", "error")) , result.push_back(Pair("error", x));
//
// Shielded key and address generalizations
//
class PaymentAddressBelongsToWallet : public boost::static_visitor<bool>
{
private:
CWallet *m_wallet;
public:
PaymentAddressBelongsToWallet(CWallet *wallet) : m_wallet(wallet) {}
bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
bool operator()(const libzcash::InvalidEncoding& no) const;
};
class IncomingViewingKeyBelongsToWallet : public boost::static_visitor<bool>
{
private:
CWallet *m_wallet;
public:
IncomingViewingKeyBelongsToWallet(CWallet *wallet) : m_wallet(wallet) {}
bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
bool operator()(const libzcash::InvalidEncoding& no) const;
};
class HaveSpendingKeyForPaymentAddress : public boost::static_visitor<bool>
{
private:
CWallet *m_wallet;
public:
HaveSpendingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
bool operator()(const libzcash::InvalidEncoding& no) const;
};
class GetSpendingKeyForPaymentAddress : public boost::static_visitor<boost::optional<libzcash::SpendingKey>>
{
private:
CWallet *m_wallet;
public:
GetSpendingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {}
boost::optional<libzcash::SpendingKey> operator()(const libzcash::SaplingPaymentAddress &zaddr) const;
boost::optional<libzcash::SpendingKey> operator()(const libzcash::InvalidEncoding& no) const;
};
class GetPubKeyForPubKey : public boost::static_visitor<CPubKey> {
public:
GetPubKeyForPubKey() {}
CPubKey operator()(const CKeyID &id) const {
return CPubKey();
}
CPubKey operator()(const CPubKey &key) const {
return key;
}
CPubKey operator()(const CScriptID &sid) const {
return CPubKey();
}
CPubKey operator()(const CNoDestination &no) const {
return CPubKey();
}
};
class AddressVisitorString : public boost::static_visitor<std::string>
{
public:
std::string operator()(const CNoDestination &dest) const { return ""; }
std::string operator()(const CKeyID &keyID) const {
return "key hash: " + keyID.ToString();
}
std::string operator()(const CPubKey &key) const {
return "public key: " + HexStr(key);
}
std::string operator()(const CScriptID &scriptID) const {
return "script hash: " + scriptID.ToString();
}
};
enum SpendingKeyAddResult {
KeyAlreadyExists,
KeyAdded,
KeyNotAdded,
};
class AddSpendingKeyToWallet : public boost::static_visitor<SpendingKeyAddResult>
{
private:
CWallet *m_wallet;
const Consensus::Params &params;
int64_t nTime;
boost::optional<std::string> hdKeypath; // currently sapling only
boost::optional<std::string> seedFpStr; // currently sapling only
bool log;
public:
AddSpendingKeyToWallet(CWallet *wallet, const Consensus::Params &params) :
m_wallet(wallet), params(params), nTime(1), hdKeypath(boost::none), seedFpStr(boost::none), log(false) {}
AddSpendingKeyToWallet(
CWallet *wallet,
const Consensus::Params &params,
int64_t _nTime,
boost::optional<std::string> _hdKeypath,
boost::optional<std::string> _seedFp,
bool _log
) : m_wallet(wallet), params(params), nTime(_nTime), hdKeypath(_hdKeypath), seedFpStr(_seedFp), log(_log) {}
SpendingKeyAddResult operator()(const libzcash::SaplingExtendedSpendingKey &sk) const;
SpendingKeyAddResult operator()(const libzcash::InvalidEncoding& no) const;
};
#define RETURN_IF_ERROR(CCerror) if ( CCerror != "" ) { ERR_RESULT(CCerror); return(result); }
#endif // BITCOIN_WALLET_WALLET_H