Fix rpc-hanging deadlocks

Collapsed multiple wallet mutexes to a single cs_wallet, to avoid deadlocks with wallet methods that acquired locks in different order.
Also change master RPC call handler to acquire cs_main and cs_wallet locks before executing RPC calls; requiring each RPC call to acquire the right set of locks in the right order was too error-prone.
This commit is contained in:
Gavin Andresen 2011-08-26 14:37:23 -04:00
parent b0243da77c
commit 6cc4a62c0e
9 changed files with 481 additions and 570 deletions

View File

@ -683,8 +683,7 @@ int CWalletDB::LoadWallet(CWallet* pwallet)
#endif
//// todo: shouldn't we catch exceptions and try to recover and continue?
CRITICAL_BLOCK(pwallet->cs_mapWallet)
CRITICAL_BLOCK(pwallet->cs_KeyStore)
CRITICAL_BLOCK(pwallet->cs_wallet)
{
// Get cursor
Dbc* pcursor = GetCursor();

View File

@ -45,7 +45,7 @@ std::vector<unsigned char> CCryptoKeyStore::GenerateNewKey()
bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
{
CRITICAL_BLOCK(cs_vMasterKey)
CRITICAL_BLOCK(cs_KeyStore)
{
if (!SetCrypted())
return false;
@ -72,7 +72,6 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
bool CCryptoKeyStore::AddKey(const CKey& key)
{
CRITICAL_BLOCK(cs_KeyStore)
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!IsCrypted())
return CBasicKeyStore::AddKey(key);
@ -106,7 +105,7 @@ bool CCryptoKeyStore::AddCryptedKey(const std::vector<unsigned char> &vchPubKey,
bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const
{
CRITICAL_BLOCK(cs_vMasterKey)
CRITICAL_BLOCK(cs_KeyStore)
{
if (!IsCrypted())
return CBasicKeyStore::GetKey(address, keyOut);
@ -128,7 +127,7 @@ bool CCryptoKeyStore::GetKey(const CBitcoinAddress &address, CKey& keyOut) const
bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const
{
CRITICAL_BLOCK(cs_vMasterKey)
CRITICAL_BLOCK(cs_KeyStore)
{
if (!IsCrypted())
return CKeyStore::GetPubKey(address, vchPubKeyOut);
@ -146,7 +145,6 @@ bool CCryptoKeyStore::GetPubKey(const CBitcoinAddress &address, std::vector<unsi
bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn)
{
CRITICAL_BLOCK(cs_KeyStore)
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!mapCryptedKeys.empty() || IsCrypted())
return false;

View File

@ -9,9 +9,10 @@
class CKeyStore
{
public:
protected:
mutable CCriticalSection cs_KeyStore;
public:
virtual bool AddKey(const CKey& key) =0;
virtual bool HaveKey(const CBitcoinAddress &address) const =0;
virtual bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const =0;
@ -30,9 +31,14 @@ public:
bool AddKey(const CKey& key);
bool HaveKey(const CBitcoinAddress &address) const
{
return (mapKeys.count(address) > 0);
bool result;
CRITICAL_BLOCK(cs_KeyStore)
result = (mapKeys.count(address) > 0);
return result;
}
bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
KeyMap::const_iterator mi = mapKeys.find(address);
if (mi != mapKeys.end())
@ -40,6 +46,7 @@ public:
keyOut.SetSecret((*mi).second);
return true;
}
}
return false;
}
};
@ -74,8 +81,6 @@ protected:
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
public:
mutable CCriticalSection cs_vMasterKey; //No guarantees master key wont get locked before you can use it, so lock this first
CCryptoKeyStore() : fUseCrypto(false)
{
}
@ -89,18 +94,20 @@ public:
{
if (!IsCrypted())
return false;
return vMasterKey.empty();
bool result;
CRITICAL_BLOCK(cs_KeyStore)
result = vMasterKey.empty();
return result;
}
bool Lock()
{
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!SetCrypted())
return false;
CRITICAL_BLOCK(cs_KeyStore)
vMasterKey.clear();
}
return true;
}
@ -108,11 +115,14 @@ public:
std::vector<unsigned char> GenerateNewKey();
bool AddKey(const CKey& key);
bool HaveKey(const CBitcoinAddress &address) const
{
CRITICAL_BLOCK(cs_KeyStore)
{
if (!IsCrypted())
return CBasicKeyStore::HaveKey(address);
return mapCryptedKeys.count(address) > 0;
}
}
bool GetKey(const CBitcoinAddress &address, CKey& keyOut) const;
bool GetPubKey(const CBitcoinAddress &address, std::vector<unsigned char>& vchPubKeyOut) const;
};

View File

@ -2879,7 +2879,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
reservekey.KeepKey();
// Track how many getdata requests this block gets
CRITICAL_BLOCK(wallet.cs_mapRequestCount)
CRITICAL_BLOCK(wallet.cs_wallet)
wallet.mapRequestCount[pblock->GetHash()] = 0;
// Process this block the same as if we had received it from another node

View File

@ -346,21 +346,17 @@ Value getnewaddress(const Array& params, bool fHelp)
CBitcoinAddress address(pwalletMain->GetOrReuseKeyFromPool());
// This could be done in the same main CS as GetKeyFromKeyPool.
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
pwalletMain->SetAddressBookName(address, strAccount);
return address.ToString();
}
// requires cs_main, cs_mapWallet, cs_mapAddressBook locks
CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
{
CWalletDB walletdb(pwalletMain->strWalletFile);
CAccount account;
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
walletdb.ReadAccount(strAccount, account);
bool bKeyUsed = false;
@ -396,7 +392,6 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
walletdb.WriteAccount(strAccount, account);
}
}
}
return CBitcoinAddress(account.vchPubKey);
}
@ -413,12 +408,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
Value ret;
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
ret = GetAccountAddress(strAccount).ToString();
}
return ret;
}
@ -442,10 +432,6 @@ Value setaccount(const Array& params, bool fHelp)
strAccount = AccountFromValue(params[1]);
// Detect when changing the account of an address that is the 'unused current key' of another account:
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
if (pwalletMain->mapAddressBook.count(address))
{
string strOldAccount = pwalletMain->mapAddressBook[address];
@ -454,7 +440,6 @@ Value setaccount(const Array& params, bool fHelp)
}
pwalletMain->SetAddressBookName(address, strAccount);
}
return Value::null;
}
@ -472,12 +457,9 @@ Value getaccount(const Array& params, bool fHelp)
throw JSONRPCError(-5, "Invalid bitcoin address");
string strAccount;
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
strAccount = (*mi).second;
}
return strAccount;
}
@ -493,8 +475,6 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
// Find all addresses that have the given account
Array ret;
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
@ -502,7 +482,6 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
if (strName == strAccount)
ret.push_back(address.ToString());
}
}
return ret;
}
@ -548,16 +527,12 @@ Value sendtoaddress(const Array& params, bool fHelp)
if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str();
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if(pwalletMain->IsLocked())
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
if (strError != "")
throw JSONRPCError(-4, strError);
}
return wtx.GetHash().GetHex();
}
@ -586,8 +561,6 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
// Tally
int64 nAmount = 0;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
@ -599,7 +572,6 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue;
}
}
return ValueFromAmount(nAmount);
}
@ -607,8 +579,6 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
{
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
@ -616,7 +586,6 @@ void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
if (strName == strAccount)
setAddress.insert(address);
}
}
}
@ -639,8 +608,6 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
// Tally
int64 nAmount = 0;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
@ -655,7 +622,6 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
nAmount += txout.nValue;
}
}
}
return (double)nAmount / (double)COIN;
}
@ -664,8 +630,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
{
int64 nBalance = 0;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
// Tally wallet transactions
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
@ -683,7 +648,6 @@ int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinD
// Tally internal accounting entries
nBalance += walletdb.GetAccountCreditDebit(strAccount);
}
return nBalance;
}
@ -763,8 +727,6 @@ Value movecmd(const Array& params, bool fHelp)
if (params.size() > 4)
strComment = params[4].get_str();
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin();
@ -789,7 +751,7 @@ Value movecmd(const Array& params, bool fHelp)
walletdb.WriteAccountingEntry(credit);
walletdb.TxnCommit();
}
return true;
}
@ -822,11 +784,7 @@ Value sendfrom(const Array& params, bool fHelp)
if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
wtx.mapValue["to"] = params[5].get_str();
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if(pwalletMain->IsLocked())
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
// Check funds
@ -838,7 +796,6 @@ Value sendfrom(const Array& params, bool fHelp)
string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
if (strError != "")
throw JSONRPCError(-4, strError);
}
return wtx.GetHash().GetHex();
}
@ -889,11 +846,7 @@ Value sendmany(const Array& params, bool fHelp)
vecSend.push_back(make_pair(scriptPubKey, nAmount));
}
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if(pwalletMain->IsLocked())
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
// Check funds
@ -913,7 +866,6 @@ Value sendmany(const Array& params, bool fHelp)
}
if (!pwalletMain->CommitTransaction(wtx, keyChange))
throw JSONRPCError(-4, "Transaction commit failed");
}
return wtx.GetHash().GetHex();
}
@ -944,8 +896,6 @@ Value ListReceived(const Array& params, bool fByAccounts)
// Tally
map<CBitcoinAddress, tallyitem> mapTally;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
@ -967,13 +917,10 @@ Value ListReceived(const Array& params, bool fByAccounts)
item.nConf = min(item.nConf, nDepth);
}
}
}
// Reply
Array ret;
map<string, tallyitem> mapAccountTally;
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
@ -1007,7 +954,6 @@ Value ListReceived(const Array& params, bool fByAccounts)
ret.push_back(obj);
}
}
}
if (fByAccounts)
{
@ -1107,8 +1053,6 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// Received
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
{
string account;
@ -1126,8 +1070,6 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
ret.push_back(entry);
}
}
}
}
void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
@ -1167,8 +1109,6 @@ Value listtransactions(const Array& params, bool fHelp)
Array ret;
CWalletDB walletdb(pwalletMain->strWalletFile);
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
// Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap:
typedef pair<CWalletTx*, CAccountingEntry*> TxPair;
typedef multimap<int64, TxPair > TxItems;
@ -1201,7 +1141,6 @@ Value listtransactions(const Array& params, bool fHelp)
if (ret.size() >= nCount) break;
}
// ret is now newest to oldest
}
// Make sure we return only last nCount items (sends-to-self might give us an extra):
if (ret.size() > nCount)
@ -1227,9 +1166,6 @@ Value listaccounts(const Array& params, bool fHelp)
nMinDepth = params[0].get_int();
map<string, int64> mapAccountBalances;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
mapAccountBalances[entry.second] = 0;
@ -1256,7 +1192,6 @@ Value listaccounts(const Array& params, bool fHelp)
mapAccountBalances[""] += r.second;
}
}
}
list<CAccountingEntry> acentries;
CWalletDB(pwalletMain->strWalletFile).ListAccountCreditDebit("*", acentries);
@ -1281,8 +1216,7 @@ Value gettransaction(const Array& params, bool fHelp)
hash.SetHex(params[0].get_str());
Object entry;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
{
if (!pwalletMain->mapWallet.count(hash))
throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
const CWalletTx& wtx = pwalletMain->mapWallet[hash];
@ -1301,7 +1235,6 @@ Value gettransaction(const Array& params, bool fHelp)
Array details;
ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
entry.push_back(Pair("details", details));
}
return entry;
}
@ -1332,13 +1265,10 @@ Value keypoolrefill(const Array& params, bool fHelp)
"keypoolrefill\n"
"Fills the keypool.");
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
pwalletMain->TopUpKeyPool();
}
if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
throw JSONRPCError(-4, "Error refreshing keypool.");
@ -1407,8 +1337,6 @@ Value walletpassphrase(const Array& params, bool fHelp)
mlock(&strWalletPass[0], strWalletPass.capacity());
strWalletPass = params[0].get_str();
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
if (strWalletPass.length() > 0)
{
if (!pwalletMain->Unlock(strWalletPass))
@ -1424,7 +1352,6 @@ Value walletpassphrase(const Array& params, bool fHelp)
throw runtime_error(
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
}
CreateThread(ThreadTopUpKeyPool, NULL);
int* pnSleepTime = new int(params[1].get_int());
@ -1553,12 +1480,9 @@ Value validateaddress(const Array& params, bool fHelp)
string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress));
ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0)));
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
if (pwalletMain->mapAddressBook.count(address))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
}
}
return ret;
}
@ -2233,7 +2157,10 @@ void ThreadRPCServer2(void* parg)
try
{
// Execute
Value result = (*(*mi).second)(params, false);
Value result;
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_wallet)
result = (*(*mi).second)(params, false);
// Send reply
string strReply = JSONRPCReply(result, Value::null, id);

View File

@ -1033,8 +1033,6 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false;
// Compile solution
CRITICAL_BLOCK(keystore.cs_KeyStore)
{
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
if (item.first == OP_PUBKEY)
@ -1075,7 +1073,6 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false;
}
}
}
return true;
}
@ -1095,8 +1092,6 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
return false;
// Compile solution
CRITICAL_BLOCK(keystore.cs_KeyStore)
{
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{
if (item.first == OP_PUBKEY)
@ -1118,12 +1113,10 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
return false;
}
}
}
return true;
}
// requires either keystore==0, or a lock on keystore->cs_KeyStore
bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
{
vector<pair<opcodetype, valtype> > vSolution;
@ -1146,7 +1139,6 @@ bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* ke
bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
{
if (keystore)
CRITICAL_BLOCK(keystore->cs_KeyStore)
return ExtractAddressInner(scriptPubKey, keystore, addressRet);
else
return ExtractAddressInner(scriptPubKey, NULL, addressRet);

View File

@ -862,7 +862,7 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
// Collect list of wallet transactions and sort newest first
bool fEntered = false;
vector<pair<unsigned int, uint256> > vSorted;
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
printf("RefreshListCtrl starting\n");
fEntered = true;
@ -890,7 +890,7 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
if (fShutdown)
return;
bool fEntered = false;
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
fEntered = true;
uint256& hash = vSorted[i++].second;
@ -913,7 +913,7 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
static int64 nLastTime;
if (GetTime() > nLastTime + 30)
{
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
nLastTime = GetTime();
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
@ -937,7 +937,7 @@ void CMainFrame::RefreshStatusColumn()
if (nTop == nLastTop && pindexLastBest == pindexBest)
return;
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
int nStart = nTop;
int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
@ -1057,7 +1057,7 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
// Update listctrl contents
if (!pwalletMain->vWalletUpdated.empty())
{
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
string strTop;
if (m_listCtrl->GetItemCount())
@ -1075,7 +1075,7 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
}
// Balance total
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
fPaintedBalance = true;
m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " ");
@ -1420,7 +1420,7 @@ void CMainFrame::OnListItemActivated(wxListEvent& event)
{
uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
CWalletTx wtx;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
if (mi == pwalletMain->mapWallet.end())
@ -1662,7 +1662,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
strHTML += HtmlEscape(wtx.ToString(), true);
strHTML += "<br><b>Inputs:</b><br>";
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_wallet)
{
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{
@ -2621,7 +2621,6 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
m_listCtrlReceiving->SetFocus();
// Fill listctrl with address book data
CRITICAL_BLOCK(pwalletMain->cs_KeyStore)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();

View File

@ -33,7 +33,7 @@ bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector
return false;
if (!fFileBacked)
return true;
CRITICAL_BLOCK(cs_pwalletdbEncryption)
CRITICAL_BLOCK(cs_wallet)
{
if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
@ -44,14 +44,13 @@ bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector
bool CWallet::Unlock(const string& strWalletPassphrase)
{
CRITICAL_BLOCK(cs_vMasterKey)
{
if (!IsLocked())
return false;
CCrypter crypter;
CKeyingMaterial vMasterKey;
CRITICAL_BLOCK(cs_wallet)
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
@ -61,16 +60,15 @@ bool CWallet::Unlock(const string& strWalletPassphrase)
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
}
return false;
}
bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
{
CRITICAL_BLOCK(cs_vMasterKey)
{
bool fWasLocked = IsLocked();
CRITICAL_BLOCK(cs_wallet)
{
Lock();
CCrypter crypter;
@ -79,7 +77,7 @@ bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const
{
if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if(!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
{
@ -107,6 +105,7 @@ bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const
}
}
}
return false;
}
@ -125,10 +124,6 @@ public:
bool CWallet::EncryptWallet(const string& strWalletPassphrase)
{
CRITICAL_BLOCK(cs_KeyStore)
CRITICAL_BLOCK(cs_vMasterKey)
CRITICAL_BLOCK(cs_pwalletdbEncryption)
{
if (IsCrypted())
return false;
@ -163,6 +158,8 @@ bool CWallet::EncryptWallet(const string& strWalletPassphrase)
if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
return false;
CRITICAL_BLOCK(cs_wallet)
{
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked)
{
@ -191,6 +188,7 @@ bool CWallet::EncryptWallet(const string& strWalletPassphrase)
Lock();
}
return true;
}
@ -199,7 +197,7 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx)
// Anytime a signature is successfully verified, it's proof the outpoint is spent.
// Update the wallet spent flag if it doesn't know due to wallet.dat being
// restored from backup or the user making copies of wallet.dat.
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
@ -222,7 +220,7 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx)
bool CWallet::AddToWallet(const CWalletTx& wtxIn)
{
uint256 hash = wtxIn.GetHash();
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
// Inserts only if not already there, returns tx inserted or tx found
pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
@ -290,6 +288,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{
uint256 hash = tx.GetHash();
CRITICAL_BLOCK(cs_wallet)
{
bool fExisted = mapWallet.count(hash);
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
@ -302,6 +302,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl
}
else
WalletUpdateSpent(tx);
}
return false;
}
@ -309,7 +310,7 @@ bool CWallet::EraseFromWallet(uint256 hash)
{
if (!fFileBacked)
return false;
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
if (mapWallet.erase(hash))
CWalletDB(strWalletFile).EraseTx(hash);
@ -320,7 +321,7 @@ bool CWallet::EraseFromWallet(uint256 hash)
bool CWallet::IsMine(const CTxIn &txin) const
{
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
@ -336,7 +337,7 @@ bool CWallet::IsMine(const CTxIn &txin) const
int64 CWallet::GetDebit(const CTxIn &txin) const
{
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end())
@ -352,6 +353,8 @@ int64 CWallet::GetDebit(const CTxIn &txin) const
int64 CWalletTx::GetTxTime() const
{
CRITICAL_BLOCK(cs_main)
{
if (!fTimeReceivedIsTxTime && hashBlock != 0)
{
// If we did not receive the transaction directly, we rely on the block's
@ -365,6 +368,7 @@ int64 CWalletTx::GetTxTime() const
return pindex->GetMedianTime();
}
}
}
return nTimeReceived;
}
@ -372,7 +376,7 @@ int CWalletTx::GetRequestCount() const
{
// Returns -1 if it wasn't being tracked
int nRequests = -1;
CRITICAL_BLOCK(pwallet->cs_mapRequestCount)
CRITICAL_BLOCK(pwallet->cs_wallet)
{
if (IsCoinBase())
{
@ -478,7 +482,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i
nSent += s.second;
nFee = allFee;
}
CRITICAL_BLOCK(pwallet->cs_mapAddressBook)
CRITICAL_BLOCK(pwallet->cs_wallet)
{
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
{
@ -508,7 +512,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
vWorkQueue.push_back(txin.prevout.hash);
// This critsect is OK because txdb is already open
CRITICAL_BLOCK(pwallet->cs_mapWallet)
CRITICAL_BLOCK(pwallet->cs_wallet)
{
map<uint256, const CMerkleTx*> mapWalletPrev;
set<uint256> setAlreadyDone;
@ -564,7 +568,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
int ret = 0;
CBlockIndex* pindex = pindexStart;
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
while (pindex)
{
@ -585,7 +589,7 @@ void CWallet::ReacceptWalletTransactions()
{
CTxDB txdb("r");
bool fRepeat = true;
while (fRepeat) CRITICAL_BLOCK(cs_mapWallet)
while (fRepeat) CRITICAL_BLOCK(cs_wallet)
{
fRepeat = false;
vector<CDiskTxPos> vMissingTx;
@ -688,7 +692,7 @@ void CWallet::ResendWalletTransactions()
// Rebroadcast any of our txes that aren't in a block yet
printf("ResendWalletTransactions()\n");
CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
// Sort them in chronological order
multimap<unsigned int, CWalletTx*> mapSorted;
@ -722,7 +726,7 @@ void CWallet::ResendWalletTransactions()
int64 CWallet::GetBalance() const
{
int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
@ -749,7 +753,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
int64 nTotalLower = 0;
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
vector<const CWalletTx*> vCoins;
vCoins.reserve(mapWallet.size());
@ -907,10 +911,10 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
wtxNew.pwallet = this;
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
{
// txdb must be opened before the mapWallet lock
CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
{
nFeeRet = nTransactionFee;
loop
@ -1021,9 +1025,9 @@ bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& w
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
{
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
{
printf("CommitTransaction:\n%s", wtxNew.ToString().c_str());
CRITICAL_BLOCK(cs_mapWallet)
{
// This is only to keep the database open to defeat the auto-flush for the
// duration of this scope. This is the only place where this optimization
@ -1053,7 +1057,6 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
}
// Track how many getdata requests our transaction gets
CRITICAL_BLOCK(cs_mapRequestCount)
mapRequestCount[wtxNew.GetHash()] = 0;
// Broadcast
@ -1072,13 +1075,11 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
// requires cs_main lock
string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
{
CReserveKey reservekey(this);
int64 nFeeRequired;
CRITICAL_BLOCK(cs_vMasterKey)
{
if (IsLocked())
{
string strError = _("Error: Wallet locked, unable to create transaction ");
@ -1095,7 +1096,6 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
printf("SendMoney() : %s", strError.c_str());
return strError;
}
}
if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
return "ABORTED";
@ -1109,7 +1109,6 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew,
// requires cs_main lock
string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
{
// Check amount
@ -1172,7 +1171,7 @@ bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
void CWallet::PrintWallet(const CBlock& block)
{
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
if (mapWallet.count(block.vtx[0].GetHash()))
{
@ -1185,7 +1184,7 @@ void CWallet::PrintWallet(const CBlock& block)
bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
{
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
{
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
if (mi != mapWallet.end())
@ -1218,10 +1217,7 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
bool CWallet::TopUpKeyPool()
{
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool)
CRITICAL_BLOCK(cs_vMasterKey)
CRITICAL_BLOCK(cs_wallet)
{
if (IsLocked())
return false;
@ -1248,9 +1244,7 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey.clear();
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool)
CRITICAL_BLOCK(cs_wallet)
{
if (!IsLocked())
TopUpKeyPool();
@ -1278,18 +1272,15 @@ void CWallet::KeepKey(int64 nIndex)
if (fFileBacked)
{
CWalletDB walletdb(strWalletFile);
CRITICAL_BLOCK(cs_main)
{
walletdb.ErasePool(nIndex);
}
}
printf("keypool keep %"PRI64d"\n", nIndex);
}
void CWallet::ReturnKey(int64 nIndex)
{
// Return to key pool
CRITICAL_BLOCK(cs_setKeyPool)
CRITICAL_BLOCK(cs_wallet)
setKeyPool.insert(nIndex);
printf("keypool return %"PRI64d"\n", nIndex);
}

View File

@ -20,14 +20,14 @@ private:
bool SelectCoins(int64 nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const;
CWalletDB *pwalletdbEncryption;
CCriticalSection cs_pwalletdbEncryption;
public:
mutable CCriticalSection cs_wallet;
bool fFileBacked;
std::string strWalletFile;
std::set<int64> setKeyPool;
CCriticalSection cs_setKeyPool;
typedef std::map<unsigned int, CMasterKey> MasterKeyMap;
MasterKeyMap mapMasterKeys;
@ -47,15 +47,12 @@ public:
pwalletdbEncryption = NULL;
}
mutable CCriticalSection cs_mapWallet;
std::map<uint256, CWalletTx> mapWallet;
std::vector<uint256> vWalletUpdated;
std::map<uint256, int> mapRequestCount;
mutable CCriticalSection cs_mapRequestCount;
std::map<CBitcoinAddress, std::string> mapAddressBook;
mutable CCriticalSection cs_mapAddressBook;
std::vector<unsigned char> vchDefaultKey;
@ -107,7 +104,7 @@ public:
{
CBitcoinAddress address;
if (ExtractAddress(txout.scriptPubKey, this, address))
CRITICAL_BLOCK(cs_mapAddressBook)
CRITICAL_BLOCK(cs_wallet)
if (!mapAddressBook.count(address))
return true;
return false;
@ -171,15 +168,13 @@ public:
int LoadWallet(bool& fFirstRunRet);
// bool BackupWallet(const std::string& strDest);
// requires cs_mapAddressBook lock
bool SetAddressBookName(const CBitcoinAddress& address, const std::string& strName);
// requires cs_mapAddressBook lock
bool DelAddressBookName(const CBitcoinAddress& address);
void UpdatedTransaction(const uint256 &hashTx)
{
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_wallet)
vWalletUpdated.push_back(hashTx);
}
@ -187,7 +182,7 @@ public:
void Inventory(const uint256 &hash)
{
CRITICAL_BLOCK(cs_mapRequestCount)
CRITICAL_BLOCK(cs_wallet)
{
std::map<uint256, int>::iterator mi = mapRequestCount.find(hash);
if (mi != mapRequestCount.end())