aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcwallet.cpp4
-rw-r--r--src/wallet/rpcwallet.h2
-rw-r--r--src/wallet/wallet.cpp211
-rw-r--r--src/wallet/wallet.h19
-rw-r--r--src/wallet/walletdb.cpp16
5 files changed, 135 insertions, 117 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index f983a61a9f..ee8c7548fc 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -740,9 +740,9 @@ UniValue getbalance(const JSONRPCRequest& request)
"\nResult:\n"
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
"\nExamples:\n"
- "\nThe total amount in the wallet\n"
+ "\nThe total amount in the wallet with 1 or more confirmations\n"
+ HelpExampleCli("getbalance", "") +
- "\nThe total amount in the wallet at least 5 blocks confirmed\n"
+ "\nThe total amount in the wallet at least 6 blocks confirmed\n"
+ HelpExampleCli("getbalance", "\"*\" 6") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("getbalance", "\"*\", 6")
diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h
index bd5dad18ca..31e2f6a699 100644
--- a/src/wallet/rpcwallet.h
+++ b/src/wallet/rpcwallet.h
@@ -16,7 +16,7 @@ void RegisterWalletRPCCommands(CRPCTable &t);
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return NULL if no wallet should be used, or a pointer to the CWallet
*/
-CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest&);
+CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
std::string HelpRequiringPassphrase(CWallet *);
void EnsureWalletIsUnlocked(CWallet *);
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 8c4f637306..13da7bb2c2 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -2991,7 +2991,8 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
if (dbw->Rewrite("\x04pool"))
{
LOCK(cs_wallet);
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@@ -3019,7 +3020,8 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
{
if (dbw->Rewrite("\x04pool"))
{
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@@ -3044,7 +3046,8 @@ DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
if (dbw->Rewrite("\x04pool"))
{
LOCK(cs_wallet);
- setKeyPool.clear();
+ setInternalKeyPool.clear();
+ setExternalKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation
// that requires a new key.
@@ -3128,9 +3131,16 @@ bool CWallet::NewKeyPool()
{
LOCK(cs_wallet);
CWalletDB walletdb(*dbw);
- for (int64_t nIndex : setKeyPool)
+
+ for (int64_t nIndex : setInternalKeyPool) {
+ walletdb.ErasePool(nIndex);
+ }
+ setInternalKeyPool.clear();
+
+ for (int64_t nIndex : setExternalKeyPool) {
walletdb.ErasePool(nIndex);
- setKeyPool.clear();
+ }
+ setExternalKeyPool.clear();
if (!TopUpKeyPool()) {
return false;
@@ -3142,25 +3152,8 @@ bool CWallet::NewKeyPool()
size_t CWallet::KeypoolCountExternalKeys()
{
- AssertLockHeld(cs_wallet); // setKeyPool
-
- // immediately return setKeyPool's size if HD or HD_SPLIT is disabled or not supported
- if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT))
- return setKeyPool.size();
-
- CWalletDB walletdb(*dbw);
-
- // count amount of external keys
- size_t amountE = 0;
- for(const int64_t& id : setKeyPool)
- {
- CKeyPool tmpKeypool;
- if (!walletdb.ReadPool(id, tmpKeypool))
- throw std::runtime_error(std::string(__func__) + ": read failed");
- amountE += !tmpKeypool.fInternal;
- }
-
- return amountE;
+ AssertLockHeld(cs_wallet); // setExternalKeyPool
+ return setExternalKeyPool.size();
}
bool CWallet::TopUpKeyPool(unsigned int kpSize)
@@ -3180,10 +3173,8 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
// count amount of available keys (internal, external)
// make sure the keypool of external and internal keys fits the user selected target (-keypool)
- int64_t amountExternal = KeypoolCountExternalKeys();
- int64_t amountInternal = setKeyPool.size() - amountExternal;
- int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - amountExternal, (int64_t) 0);
- int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - amountInternal, (int64_t) 0);
+ int64_t missingExternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setExternalKeyPool.size(), (int64_t) 0);
+ int64_t missingInternal = std::max(std::max((int64_t) nTargetSize, (int64_t) 1) - (int64_t)setInternalKeyPool.size(), (int64_t) 0);
if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT))
{
@@ -3195,20 +3186,32 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
for (int64_t i = missingInternal + missingExternal; i--;)
{
int64_t nEnd = 1;
- if (i < missingInternal)
+ if (i < missingInternal) {
internal = true;
- if (!setKeyPool.empty())
- nEnd = *(--setKeyPool.end()) + 1;
+ }
+
+ if (!setInternalKeyPool.empty()) {
+ nEnd = *(setInternalKeyPool.rbegin()) + 1;
+ }
+ if (!setExternalKeyPool.empty()) {
+ nEnd = std::max(nEnd, *(setExternalKeyPool.rbegin()) + 1);
+ }
+
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey(internal), internal)))
throw std::runtime_error(std::string(__func__) + ": writing generated key failed");
- setKeyPool.insert(nEnd);
- LogPrintf("keypool added key %d, size=%u, internal=%d\n", nEnd, setKeyPool.size(), internal);
+
+ if (internal) {
+ setInternalKeyPool.insert(nEnd);
+ } else {
+ setExternalKeyPool.insert(nEnd);
+ }
+ LogPrintf("keypool added key %d, size=%u (%u internal), new key is %s\n", nEnd, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size(), internal ? "internal" : "external");
}
}
return true;
}
-void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool internal)
+void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal)
{
nIndex = -1;
keypool.vchPubKey = CPubKey();
@@ -3218,30 +3221,30 @@ void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool int
if (!IsLocked())
TopUpKeyPool();
+ bool fReturningInternal = IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT) && fRequestedInternal;
+ std::set<int64_t>& setKeyPool = fReturningInternal ? setInternalKeyPool : setExternalKeyPool;
+
// Get the oldest key
if(setKeyPool.empty())
return;
CWalletDB walletdb(*dbw);
- // try to find a key that matches the internal/external filter
- for(const int64_t& id : setKeyPool)
- {
- CKeyPool tmpKeypool;
- if (!walletdb.ReadPool(id, tmpKeypool))
- throw std::runtime_error(std::string(__func__) + ": read failed");
- if (!HaveKey(tmpKeypool.vchPubKey.GetID()))
- throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
- if (!IsHDEnabled() || !CanSupportFeature(FEATURE_HD_SPLIT) || tmpKeypool.fInternal == internal)
- {
- nIndex = id;
- keypool = tmpKeypool;
- setKeyPool.erase(id);
- assert(keypool.vchPubKey.IsValid());
- LogPrintf("keypool reserve %d\n", nIndex);
- return;
- }
+ auto it = setKeyPool.begin();
+ nIndex = *it;
+ setKeyPool.erase(it);
+ if (!walletdb.ReadPool(nIndex, keypool)) {
+ throw std::runtime_error(std::string(__func__) + ": read failed");
+ }
+ if (!HaveKey(keypool.vchPubKey.GetID())) {
+ throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
}
+ if (keypool.fInternal != fReturningInternal) {
+ throw std::runtime_error(std::string(__func__) + ": keypool entry misclassified");
+ }
+
+ assert(keypool.vchPubKey.IsValid());
+ LogPrintf("keypool reserve %d\n", nIndex);
}
}
@@ -3253,12 +3256,16 @@ void CWallet::KeepKey(int64_t nIndex)
LogPrintf("keypool keep %d\n", nIndex);
}
-void CWallet::ReturnKey(int64_t nIndex)
+void CWallet::ReturnKey(int64_t nIndex, bool fInternal)
{
// Return to key pool
{
LOCK(cs_wallet);
- setKeyPool.insert(nIndex);
+ if (fInternal) {
+ setInternalKeyPool.insert(nIndex);
+ } else {
+ setExternalKeyPool.insert(nIndex);
+ }
}
LogPrintf("keypool return %d\n", nIndex);
}
@@ -3282,48 +3289,35 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool internal)
return true;
}
-int64_t CWallet::GetOldestKeyPoolTime()
-{
- LOCK(cs_wallet);
-
- // if the keypool is empty, return <NOW>
- if (setKeyPool.empty())
+static int64_t GetOldestKeyTimeInPool(const std::set<int64_t>& setKeyPool, CWalletDB& walletdb) {
+ if (setKeyPool.empty()) {
return GetTime();
+ }
CKeyPool keypool;
- CWalletDB walletdb(*dbw);
-
- if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT))
- {
- // if HD & HD Chain Split is enabled, response max(oldest-internal-key, oldest-external-key)
- int64_t now = GetTime();
- int64_t oldest_external = now, oldest_internal = now;
-
- for(const int64_t& id : setKeyPool)
- {
- if (!walletdb.ReadPool(id, keypool)) {
- throw std::runtime_error(std::string(__func__) + ": read failed");
- }
- if (keypool.fInternal && keypool.nTime < oldest_internal) {
- oldest_internal = keypool.nTime;
- }
- else if (!keypool.fInternal && keypool.nTime < oldest_external) {
- oldest_external = keypool.nTime;
- }
- if (oldest_internal != now && oldest_external != now) {
- break;
- }
- }
- return std::max(oldest_internal, oldest_external);
- }
- // load oldest key from keypool, get time and return
int64_t nIndex = *(setKeyPool.begin());
- if (!walletdb.ReadPool(nIndex, keypool))
+ if (!walletdb.ReadPool(nIndex, keypool)) {
throw std::runtime_error(std::string(__func__) + ": read oldest key in keypool failed");
+ }
assert(keypool.vchPubKey.IsValid());
return keypool.nTime;
}
+int64_t CWallet::GetOldestKeyPoolTime()
+{
+ LOCK(cs_wallet);
+
+ CWalletDB walletdb(*dbw);
+
+ // load oldest key from keypool, get time and return
+ int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, walletdb);
+ if (IsHDEnabled() && CanSupportFeature(FEATURE_HD_SPLIT)) {
+ oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, walletdb), oldestKey);
+ }
+
+ return oldestKey;
+}
+
std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
std::map<CTxDestination, CAmount> balances;
@@ -3482,6 +3476,7 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey, bool internal)
else {
return false;
}
+ fInternal = keypool.fInternal;
}
assert(vchPubKey.IsValid());
pubkey = vchPubKey;
@@ -3498,19 +3493,14 @@ void CReserveKey::KeepKey()
void CReserveKey::ReturnKey()
{
- if (nIndex != -1)
- pwallet->ReturnKey(nIndex);
+ if (nIndex != -1) {
+ pwallet->ReturnKey(nIndex, fInternal);
+ }
nIndex = -1;
vchPubKey = CPubKey();
}
-void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
-{
- setAddress.clear();
-
- CWalletDB walletdb(*dbw);
-
- LOCK2(cs_main, cs_wallet);
+static void LoadReserveKeysToSet(std::set<CKeyID>& setAddress, const std::set<int64_t>& setKeyPool, CWalletDB& walletdb) {
for (const int64_t& id : setKeyPool)
{
CKeyPool keypool;
@@ -3518,12 +3508,27 @@ void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
throw std::runtime_error(std::string(__func__) + ": read failed");
assert(keypool.vchPubKey.IsValid());
CKeyID keyID = keypool.vchPubKey.GetID();
- if (!HaveKey(keyID))
- throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
setAddress.insert(keyID);
}
}
+void CWallet::GetAllReserveKeys(std::set<CKeyID>& setAddress) const
+{
+ setAddress.clear();
+
+ CWalletDB walletdb(*dbw);
+
+ LOCK2(cs_main, cs_wallet);
+ LoadReserveKeysToSet(setAddress, setInternalKeyPool, walletdb);
+ LoadReserveKeysToSet(setAddress, setExternalKeyPool, walletdb);
+
+ for (const CKeyID& keyID : setAddress) {
+ if (!HaveKey(keyID)) {
+ throw std::runtime_error(std::string(__func__) + ": unknown key in key pool");
+ }
+ }
+}
+
void CWallet::GetScriptForMining(std::shared_ptr<CReserveScript> &script)
{
std::shared_ptr<CReserveKey> rKey = std::make_shared<CReserveKey>(this);
@@ -4057,13 +4062,19 @@ bool CWallet::ParameterInteraction()
}
}
- // -zapwallettx implies a rescan
- if (GetBoolArg("-zapwallettxes", false)) {
+ int zapwallettxes = GetArg("-zapwallettxes", 0);
+ // -zapwallettxes implies dropping the mempool on startup
+ if (zapwallettxes != 0 && SoftSetBoolArg("-persistmempool", false)) {
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -persistmempool=0\n", __func__, zapwallettxes);
+ }
+
+ // -zapwallettxes implies a rescan
+ if (zapwallettxes != 0) {
if (is_multiwallet) {
return InitError(strprintf("%s is only allowed with a single wallet file", "-zapwallettxes"));
}
if (SoftSetBoolArg("-rescan", true)) {
- LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
+ LogPrintf("%s: parameter interaction: -zapwallettxes=%s -> setting -rescan=1\n", __func__, zapwallettxes);
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index bb9d146a20..b716e46a7d 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -699,7 +699,8 @@ private:
/* HD derive new child key (on internal or external chain) */
void DeriveNewChildKey(CKeyMetadata& metadata, CKey& secret, bool internal = false);
- std::set<int64_t> setKeyPool;
+ std::set<int64_t> setInternalKeyPool;
+ std::set<int64_t> setExternalKeyPool;
int64_t nTimeFirstKey;
@@ -744,7 +745,11 @@ public:
void LoadKeyPool(int nIndex, const CKeyPool &keypool)
{
- setKeyPool.insert(nIndex);
+ if (keypool.fInternal) {
+ setInternalKeyPool.insert(nIndex);
+ } else {
+ setExternalKeyPool.insert(nIndex);
+ }
// If no metadata exists yet, create a default with the pool key's
// creation time. Note that this may be overwritten by actually
@@ -974,9 +979,9 @@ public:
bool NewKeyPool();
size_t KeypoolCountExternalKeys();
bool TopUpKeyPool(unsigned int kpSize = 0);
- void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool internal);
+ void ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal);
void KeepKey(int64_t nIndex);
- void ReturnKey(int64_t nIndex);
+ void ReturnKey(int64_t nIndex, bool fInternal);
bool GetKeyFromPool(CPubKey &key, bool internal = false);
int64_t GetOldestKeyPoolTime();
void GetAllReserveKeys(std::set<CKeyID>& setAddress) const;
@@ -1030,8 +1035,8 @@ public:
unsigned int GetKeyPoolSize()
{
- AssertLockHeld(cs_wallet); // setKeyPool
- return setKeyPool.size();
+ AssertLockHeld(cs_wallet); // set{Ex,In}ternalKeyPool
+ return setInternalKeyPool.size() + setExternalKeyPool.size();
}
bool SetDefaultKey(const CPubKey &vchPubKey);
@@ -1135,11 +1140,13 @@ protected:
CWallet* pwallet;
int64_t nIndex;
CPubKey vchPubKey;
+ bool fInternal;
public:
CReserveKey(CWallet* pwalletIn)
{
nIndex = -1;
pwallet = pwalletIn;
+ fInternal = false;
}
CReserveKey() = default;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 2a33dca240..65a28af46d 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -94,23 +94,23 @@ bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
{
- return WriteIC(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
+ return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, false);
}
bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
{
- if (!WriteIC(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta)) {
+ if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) {
return false;
}
- return WriteIC(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
+ return WriteIC(std::make_pair(std::string("watchs"), dest), '1');
}
bool CWalletDB::EraseWatchOnly(const CScript &dest)
{
- if (!EraseIC(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)))) {
+ if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) {
return false;
}
- return EraseIC(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
+ return EraseIC(std::make_pair(std::string("watchs"), dest));
}
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
@@ -323,7 +323,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
{
wss.nWatchKeys++;
CScript script;
- ssKey >> *(CScriptBase*)(&script);
+ ssKey >> script;
char fYes;
ssValue >> fYes;
if (fYes == '1')
@@ -440,7 +440,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
else if (strType == "watchmeta")
{
CScript script;
- ssKey >> *(CScriptBase*)(&script);
+ ssKey >> script;
keyID = CScriptID(script);
}
@@ -474,7 +474,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
uint160 hash;
ssKey >> hash;
CScript script;
- ssValue >> *(CScriptBase*)(&script);
+ ssValue >> script;
if (!pwallet->LoadCScript(script))
{
strErr = "Error reading wallet database: LoadCScript failed";