From d0640f940d7294596664c7d1d78d5f9560edff25 Mon Sep 17 00:00:00 2001 From: Casey Fleser Date: Wed, 19 Feb 2014 16:43:41 -0600 Subject: [PATCH 1/4] significant optimizations to Solver and CWalletTx::GetAmounts --- src/script.cpp | 148 +++++++++++++++++++++++++++++++++++++------------ src/script.h | 1 + src/wallet.cpp | 19 ++++++- src/wallet.h | 1 + 4 files changed, 132 insertions(+), 37 deletions(-) diff --git a/src/script.cpp b/src/script.cpp index 2fea7a7d5..cdd2dc668 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -31,6 +31,7 @@ static const CBigNum bnFalse(0); static const CBigNum bnTrue(1); static const size_t nMaxNumSize = 4; +#undef printf CBigNum CastToBigNum(const valtype& vch) { @@ -1119,27 +1120,40 @@ bool CheckSig(vector vchSig, const vector &vchPubK +typedef struct { + txnouttype txType; + CScript *tScript; +} SScriptPairRec; - - -// -// Return public keys or hashes from scriptPubKey, for 'standard' transaction types. -// bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector >& vSolutionsRet) { - // Templates - static map mTemplates; - if (mTemplates.empty()) - { - // Standard tx, sender provides pubkey, receiver adds signature - mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG)); - - // Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey - mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG)); - - // Sender provides N pubkeys, receivers provides M signatures - mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG)); - } + static SScriptPairRec *sTemplates = NULL; + SScriptPairRec *curTemplate; + + if (sTemplates == NULL) { + CScript *tScript; + + sTemplates = (SScriptPairRec *)malloc(sizeof(SScriptPairRec) * 4); + + // order templates such that most common transaction types are checked first + tScript = new CScript(); + *tScript << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG; + sTemplates[0].txType = TX_PUBKEYHASH; + sTemplates[0].tScript = tScript; + + tScript = new CScript(); + *tScript << OP_PUBKEY << OP_CHECKSIG; + sTemplates[1].txType = TX_PUBKEY; + sTemplates[1].tScript = tScript; + + tScript = new CScript(); + *tScript << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG; + sTemplates[2].txType = TX_MULTISIG; + sTemplates[2].tScript = tScript; + + sTemplates[3].txType = (txnouttype)-1; + sTemplates[3].tScript = NULL; + } // Shortcut for pay-to-script-hash, which are more constrained than the other types: // it is always OP_HASH160 20 [20 byte hash] OP_EQUAL @@ -1150,26 +1164,29 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vectortScript != NULL) { + const CScript *testScript = curTemplate->tScript; + opcodetype opcode1, opcode2; + vector vch1; - opcodetype opcode1, opcode2; - vector vch1, vch2; + vSolutionsRet.clear(); // Compare CScript::const_iterator pc1 = script1.begin(); - CScript::const_iterator pc2 = script2.begin(); + CScript::const_iterator pc2 = testScript->begin(); + CScript::const_iterator end1 = script1.end(); + CScript::const_iterator end2 = testScript->end(); + loop { - if (pc1 == script1.end() && pc2 == script2.end()) + if (pc1 == end1 && pc2 == end2) { // Found a match - typeRet = tplate.first; + typeRet = curTemplate->txType; if (typeRet == TX_MULTISIG) { // Additional checks for TX_MULTISIG: @@ -1182,7 +1199,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vectorGetOp(pc2, opcode2)) // templates push no data, no need to get vch break; // Template matching opcodes: @@ -1194,7 +1211,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vectorGetOp(pc2, opcode2)) break; // Normal situation is to fall through // to other if/else statements @@ -1223,16 +1240,18 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector vSolutions; + txnouttype whichType; + bool hasDestination = false; + + *outIsMine = false; + + if (Solver(scriptPubKey, whichType, vSolutions)) { + CKeyID keyID; + + switch (whichType) { + case TX_NONSTANDARD: + break; + + case TX_PUBKEY: + keyID = CPubKey(vSolutions[0]).GetID(); + addressRet = keyID; + *outIsMine = keystore.HaveKey(keyID); + hasDestination = true; + break; + + case TX_PUBKEYHASH: + keyID = CKeyID(uint160(vSolutions[0])); + addressRet = keyID; + *outIsMine = keystore.HaveKey(keyID); + hasDestination = true; + break; + + case TX_SCRIPTHASH: { + CScript subscript; + CScriptID scriptID = CScriptID(uint160(vSolutions[0])); + + addressRet = scriptID; + hasDestination = true; + + if (keystore.GetCScript(scriptID, subscript)) + *outIsMine = IsMine(keystore, subscript); + } + break; + + case TX_MULTISIG: + { + // Only consider transactions "mine" if we own ALL the + // keys involved. multi-signature transactions that are + // partially owned (somebody else has a key that can spend + // them) enable spend-out-from-under-you attacks, especially + // in shared-wallet situations. + vector keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1); + *outIsMine = HaveKeys(keys, keystore) == keys.size(); + } + } + } + + return hasDestination; +} + bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector& addressRet, int& nRequiredRet) { addressRet.clear(); @@ -1732,7 +1812,7 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const return subscript.GetSigOpCount(true); } -bool CScript::IsPayToScriptHash() const +inline bool CScript::IsPayToScriptHash() const { // Extra-fast test for pay-to-script-hash CScripts: return (this->size() == 23 && diff --git a/src/script.h b/src/script.h index d736c2cb1..62225e564 100644 --- a/src/script.h +++ b/src/script.h @@ -676,6 +676,7 @@ bool IsStandard(const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CScript& scriptPubKey); bool IsMine(const CKeyStore& keystore, const CTxDestination &dest); bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet); +bool ExtractDestinationAndMine(const CKeyStore &keystore, const CScript& scriptPubKey, CTxDestination& addressRet, bool *outMine); bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector& addressRet, int& nRequiredRet); bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); diff --git a/src/wallet.cpp b/src/wallet.cpp index 22926a4a9..becf2cda2 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -570,6 +570,17 @@ int64 CWallet::GetDebit(const CTxIn &txin) const return 0; } +bool CWallet::HasAddress(const CTxDestination &txDest) const +{ + bool hasAddress = false; + + LOCK(cs_wallet); + if (mapAddressBook.count(txDest)) + hasAddress = true; + + return hasAddress; +} + bool CWallet::IsChange(const CTxOut& txout) const { CTxDestination address; @@ -656,20 +667,22 @@ void CWalletTx::GetAmounts(list >& listReceived, { CTxDestination address; vector vchPubKey; - if (!ExtractDestination(txout.scriptPubKey, address)) + bool isMine; + + if (!ExtractDestinationAndMine(*pwallet, txout.scriptPubKey, address, &isMine)) { printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString().c_str()); } // Don't report 'change' txouts - if (nDebit > 0 && pwallet->IsChange(txout)) + if (nDebit > 0 && isMine && !pwallet->HasAddress(address)) // equivalent to CWallet::IsChange, but avoids an additional call to Solver continue; if (nDebit > 0) listSent.push_back(make_pair(address, txout.nValue)); - if (pwallet->IsMine(txout)) + if (isMine) listReceived.push_back(make_pair(address, txout.nValue)); } diff --git a/src/wallet.h b/src/wallet.h index 551f81568..574335d81 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -213,6 +213,7 @@ public: throw std::runtime_error("CWallet::GetCredit() : value out of range"); return (IsMine(txout) ? txout.nValue : 0); } + bool HasAddress(const CTxDestination &txDest) const; bool IsChange(const CTxOut& txout) const; int64 GetChange(const CTxOut& txout) const { From 3071f2072eddcecf2d06e89038f21406f13307f0 Mon Sep 17 00:00:00 2001 From: Casey Fleser Date: Thu, 20 Feb 2014 06:54:45 -0600 Subject: [PATCH 2/4] a few more tweaks --- src/compat.h | 1 + src/script.cpp | 12 +++++------- src/script.h | 14 +++++++------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/compat.h b/src/compat.h index 3f61a9964..25aa6d89b 100644 --- a/src/compat.h +++ b/src/compat.h @@ -28,6 +28,7 @@ #endif #if MAC_OSX +#undef MSG_NOSIGNAL // undef prior to redefinition eliminates warnings #define MSG_NOSIGNAL SO_NOSIGPIPE #endif diff --git a/src/script.cpp b/src/script.cpp index cdd2dc668..adeeffa57 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -31,8 +31,6 @@ static const CBigNum bnFalse(0); static const CBigNum bnTrue(1); static const size_t nMaxNumSize = 4; -#undef printf - CBigNum CastToBigNum(const valtype& vch) { if (vch.size() > nMaxNumSize) @@ -1197,9 +1195,9 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vectorGetOp(pc2, opcode2)) // templates push no data, no need to get vch + if (!testScript->GetOp2(pc2, opcode2, NULL)) // templates push no data, no need to get vch break; // Template matching opcodes: @@ -1208,10 +1206,10 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector= 33 && vch1.size() <= 120) { vSolutionsRet.push_back(vch1); - if (!script1.GetOp(pc1, opcode1, vch1)) + if (!script1.GetOp2(pc1, opcode1, &vch1)) break; } - if (!testScript->GetOp(pc2, opcode2)) + if (!testScript->GetOp2(pc2, opcode2, NULL)) break; // Normal situation is to fall through // to other if/else statements @@ -1812,7 +1810,7 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const return subscript.GetSigOpCount(true); } -inline bool CScript::IsPayToScriptHash() const +bool CScript::IsPayToScriptHash() const { // Extra-fast test for pay-to-script-hash CScripts: return (this->size() == 23 && diff --git a/src/script.h b/src/script.h index 62225e564..a174fcd96 100644 --- a/src/script.h +++ b/src/script.h @@ -426,14 +426,14 @@ public: bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector* pvchRet) const { + const_iterator scriptEnd = end(); + opcodeRet = OP_INVALIDOPCODE; if (pvchRet) pvchRet->clear(); - if (pc >= end()) - return false; // Read instruction - if (end() - pc < 1) + if (scriptEnd - pc < 1) return false; unsigned int opcode = *pc++; @@ -447,13 +447,13 @@ public: } else if (opcode == OP_PUSHDATA1) { - if (end() - pc < 1) + if (scriptEnd - pc < 1) return false; nSize = *pc++; } else if (opcode == OP_PUSHDATA2) { - if (end() - pc < 2) + if (scriptEnd - pc < 2) return false; nSize = 0; memcpy(&nSize, &pc[0], 2); @@ -461,12 +461,12 @@ public: } else if (opcode == OP_PUSHDATA4) { - if (end() - pc < 4) + if (scriptEnd - pc < 4) return false; memcpy(&nSize, &pc[0], 4); pc += 4; } - if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize) + if (scriptEnd - pc < 0 || (unsigned int)(scriptEnd - pc) < nSize) return false; if (pvchRet) pvchRet->assign(pc, pc + nSize); From c4cc936890c39a3f26e3b8e2f7ff244621686cbb Mon Sep 17 00:00:00 2001 From: Casey Fleser Date: Fri, 21 Feb 2014 10:49:46 -0600 Subject: [PATCH 3/4] alternate listaccounts / GetCredits functions --- src/rpcwallet.cpp | 33 +++++++++++++++------------------ src/wallet.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ src/wallet.h | 8 ++++++++ 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index ec83914dc..a73cdfa60 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1124,7 +1124,9 @@ Value listaccounts(const Array& params, bool fHelp) if (params.size() > 0) nMinDepth = params[0].get_int(); - map mapAccountBalances; + std::map mapAccountBalances; + std::list > listCredits; + BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) { if (IsMine(*pwalletMain, entry.first)) // This address belongs to me mapAccountBalances[entry.second] = 0; @@ -1132,23 +1134,18 @@ Value listaccounts(const Array& params, bool fHelp) for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx& wtx = (*it).second; - int64 nFee; - string strSentAccount; - list > listReceived; - list > listSent; - wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount); - mapAccountBalances[strSentAccount] -= nFee; - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) - mapAccountBalances[strSentAccount] -= s.second; - if (wtx.GetDepthInMainChain() >= nMinDepth) - { - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) - if (pwalletMain->mapAddressBook.count(r.first)) - mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; - else - mapAccountBalances[""] += r.second; - } + const CWalletTx &wtx = (*it).second; + + if (wtx.GetDepthInMainChain() >= nMinDepth) { + wtx.GetCredits(listCredits); + + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listCredits) { + if (pwalletMain->mapAddressBook.count(r.first)) + mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; + else + mapAccountBalances[""] += r.second; + } + } } list acentries; diff --git a/src/wallet.cpp b/src/wallet.cpp index becf2cda2..c14c0074f 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -646,6 +646,49 @@ int CWalletTx::GetRequestCount() const return nRequests; } +void CWalletTx::GetCredits( + std::list >& listCredits) const +{ + listCredits.clear(); + + if (!IsCoinBase() || GetBlocksToMaturity() <= 0) { + if (!fMineCached) + vfMine.resize(vout.size()); + + for (unsigned int i = 0; i < vout.size(); i++) { + if (!IsSpent(i)) { + const CTxOut &txout = vout[i]; + int64 credit = txout.nValue; + + if (credit) { + CTxDestination address; + bool isMine = false; + + if (!MoneyRange(credit)) { + throw std::runtime_error("CWalletTx::GetCredits() : value out of range"); + } + + if (!fMineCached) { + ExtractDestinationAndMine(*pwallet, txout.scriptPubKey, address, &isMine); + vfMine[i] = isMine; + } + else { + if (vfMine[i]) { + ExtractDestinationAndMine(*pwallet, txout.scriptPubKey, address, &isMine); + } + } + + if (isMine) { + listCredits.push_back(make_pair(address, credit)); + } + } + } + } + + fMineCached = true; + } +} + void CWalletTx::GetAmounts(list >& listReceived, list >& listSent, int64& nFee, string& strSentAccount) const { diff --git a/src/wallet.h b/src/wallet.h index 574335d81..5908ffc4a 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -384,6 +384,8 @@ public: int64 nOrderPos; // position in ordered transaction list // memory only + mutable std::vector vfMine; // which outputs are mine + mutable bool fMineCached; mutable bool fDebitCached; mutable bool fCreditCached; mutable bool fImmatureCreditCached; @@ -427,6 +429,8 @@ public: fFromMe = false; strFromAccount.clear(); vfSpent.clear(); + vfMine.clear(); + fMineCached = false; fDebitCached = false; fCreditCached = false; fImmatureCreditCached = false; @@ -520,6 +524,8 @@ public: // make sure balances are recalculated void MarkDirty() { + vfMine.clear(); + fMineCached = false; fCreditCached = false; fAvailableCreditCached = false; fDebitCached = false; @@ -628,6 +634,8 @@ public: return nChangeCached; } + void GetCredits(std::list >& listCredits) const; + void GetAmounts(std::list >& listReceived, std::list >& listSent, int64& nFee, std::string& strSentAccount) const; From a4a57df0598e6e663225e78818d6511bc35c085d Mon Sep 17 00:00:00 2001 From: Casey Fleser Date: Sat, 22 Feb 2014 09:05:52 -0600 Subject: [PATCH 4/4] add caching to CWalletTx::GetAmounts and undo some other changes --- src/rpcwallet.cpp | 33 +++++++++--------- src/wallet.cpp | 86 ++++++++++++++++------------------------------- src/wallet.h | 2 -- 3 files changed, 47 insertions(+), 74 deletions(-) diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index a73cdfa60..ec83914dc 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1124,9 +1124,7 @@ Value listaccounts(const Array& params, bool fHelp) if (params.size() > 0) nMinDepth = params[0].get_int(); - std::map mapAccountBalances; - std::list > listCredits; - + map mapAccountBalances; BOOST_FOREACH(const PAIRTYPE(CTxDestination, string)& entry, pwalletMain->mapAddressBook) { if (IsMine(*pwalletMain, entry.first)) // This address belongs to me mapAccountBalances[entry.second] = 0; @@ -1134,18 +1132,23 @@ Value listaccounts(const Array& params, bool fHelp) for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { - const CWalletTx &wtx = (*it).second; - - if (wtx.GetDepthInMainChain() >= nMinDepth) { - wtx.GetCredits(listCredits); - - BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listCredits) { - if (pwalletMain->mapAddressBook.count(r.first)) - mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; - else - mapAccountBalances[""] += r.second; - } - } + const CWalletTx& wtx = (*it).second; + int64 nFee; + string strSentAccount; + list > listReceived; + list > listSent; + wtx.GetAmounts(listReceived, listSent, nFee, strSentAccount); + mapAccountBalances[strSentAccount] -= nFee; + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) + mapAccountBalances[strSentAccount] -= s.second; + if (wtx.GetDepthInMainChain() >= nMinDepth) + { + BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) + if (pwalletMain->mapAddressBook.count(r.first)) + mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second; + else + mapAccountBalances[""] += r.second; + } } list acentries; diff --git a/src/wallet.cpp b/src/wallet.cpp index c14c0074f..e506ba878 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -646,52 +646,11 @@ int CWalletTx::GetRequestCount() const return nRequests; } -void CWalletTx::GetCredits( - std::list >& listCredits) const -{ - listCredits.clear(); - - if (!IsCoinBase() || GetBlocksToMaturity() <= 0) { - if (!fMineCached) - vfMine.resize(vout.size()); - - for (unsigned int i = 0; i < vout.size(); i++) { - if (!IsSpent(i)) { - const CTxOut &txout = vout[i]; - int64 credit = txout.nValue; - - if (credit) { - CTxDestination address; - bool isMine = false; - - if (!MoneyRange(credit)) { - throw std::runtime_error("CWalletTx::GetCredits() : value out of range"); - } - - if (!fMineCached) { - ExtractDestinationAndMine(*pwallet, txout.scriptPubKey, address, &isMine); - vfMine[i] = isMine; - } - else { - if (vfMine[i]) { - ExtractDestinationAndMine(*pwallet, txout.scriptPubKey, address, &isMine); - } - } - - if (isMine) { - listCredits.push_back(make_pair(address, credit)); - } - } - } - } - - fMineCached = true; - } -} - void CWalletTx::GetAmounts(list >& listReceived, list >& listSent, int64& nFee, string& strSentAccount) const { + CTxDestination address; + nFee = 0; listReceived.clear(); listSent.clear(); @@ -705,30 +664,43 @@ void CWalletTx::GetAmounts(list >& listReceived, nFee = nDebit - nValueOut; } - // Sent/received. - BOOST_FOREACH(const CTxOut& txout, vout) - { - CTxDestination address; - vector vchPubKey; - bool isMine; + if (!fMineCached) + vfMine.resize(vout.size()); - if (!ExtractDestinationAndMine(*pwallet, txout.scriptPubKey, address, &isMine)) - { - printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", - this->GetHash().ToString().c_str()); + // Sent/received. + for (unsigned int i = 0; i < vout.size(); i++) { + const CTxOut &txout = vout[i]; + bool isMine = false; + bool warnUnkownTX = false; + + if (!fMineCached) { + address = CNoDestination(); + warnUnkownTX = !ExtractDestinationAndMine(*pwallet, txout.scriptPubKey, address, &isMine); + vfMine[i] = isMine; + } + else { + if (vfMine[i]) { + isMine = true; // already know this is ours, just fetch address + address = CNoDestination(); + warnUnkownTX = !ExtractDestination(txout.scriptPubKey, address); + } + } + if (warnUnkownTX) { + printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", this->GetHash().ToString().c_str()); } - // Don't report 'change' txouts - if (nDebit > 0 && isMine && !pwallet->HasAddress(address)) // equivalent to CWallet::IsChange, but avoids an additional call to Solver - continue; + if (nDebit > 0) { + if (isMine && !pwallet->HasAddress(address)) // Don't report 'change' txouts + continue; - if (nDebit > 0) listSent.push_back(make_pair(address, txout.nValue)); + } if (isMine) listReceived.push_back(make_pair(address, txout.nValue)); } + fMineCached = true; } void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nReceived, diff --git a/src/wallet.h b/src/wallet.h index 5908ffc4a..6fdbdf82f 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -634,8 +634,6 @@ public: return nChangeCached; } - void GetCredits(std::list >& listCredits) const; - void GetAmounts(std::list >& listReceived, std::list >& listSent, int64& nFee, std::string& strSentAccount) const;