Browse Source

Merge pull request #480 from gavinandresen/deadlocks

Simplify mutex locking, fix deadlocks. Fixes issue #453
miguelfreitas
Gavin Andresen 13 years ago
parent
commit
cb6c4b883d
  1. 44
      doc/coding.txt
  2. 3
      src/db.cpp
  3. 8
      src/keystore.cpp
  4. 44
      src/keystore.h
  5. 2
      src/main.cpp
  6. 633
      src/rpc.cpp
  7. 102
      src/script.cpp
  8. 375
      src/ui.cpp
  9. 8
      src/util.cpp
  10. 201
      src/wallet.cpp
  11. 15
      src/wallet.h

44
doc/coding.txt

@ -39,3 +39,47 @@ v vector or similar list objects
map map or multimap map map or multimap
set set or multiset set set or multiset
bn CBigNum bn CBigNum
-------------------------
Locking/mutex usage notes
The code is multi-threaded, and uses mutexes and the CRITICAL_BLOCK/TRY_CRITICAL_BLOCK macros to protect data structures.
Deadlocks due to inconsistent lock ordering (thread 1 locks cs_main and then cs_wallet, while thread 2 locks them in the opposite order: result, deadlock as each waits for the other to release its lock) are a problem. Compile with -DDEBUG_LOCKORDER to get lock order inconsistencies reported in the debug.log file.
Re-architecting the core code so there are better-defined interfaces between the various components is a goal, with any necessary locking done by the components (e.g. see the self-contained CKeyStore class and its cs_KeyStore lock for example).
-------
Threads
StartNode : Starts other threads.
ThreadGetMyExternalIP : Determines outside-the-firewall IP address, sends addr message to connected peers when it determines it.
ThreadIRCSeed : Joins IRC bootstrapping channel, watching for new peers and advertising this node's IP address.
ThreadSocketHandler : Sends/Receives data from peers on port 8333.
ThreadMessageHandler : Higher-level message handling (sending and receiving).
ThreadOpenConnections : Initiates new connections to peers.
ThreadTopUpKeyPool : replenishes the keystore's keypool.
ThreadCleanWalletPassphrase : re-locks an encrypted wallet after user has unlocked it for a period of time.
SendingDialogStartTransfer : used by pay-via-ip-address code (obsolete)
ThreadDelayedRepaint : repaint the gui
ThreadFlushWalletDB : Close the wallet.dat file if it hasn't been used in 500ms.
ThreadRPCServer : Remote procedure call handler, listens on port 8332 for connections and services them.
ThreadBitcoinMiner : Generates bitcoins
ThreadMapPort : Universal plug-and-play startup/shutdown
Shutdown : Does an orderly shutdown of everything
ExitTimeout : Windows-only, sleeps 5 seconds then exits application

3
src/db.cpp

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

8
src/keystore.cpp

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

44
src/keystore.h

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

2
src/main.cpp

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

633
src/rpc.cpp

@ -346,55 +346,50 @@ Value getnewaddress(const Array& params, bool fHelp)
CBitcoinAddress address(pwalletMain->GetOrReuseKeyFromPool()); CBitcoinAddress address(pwalletMain->GetOrReuseKeyFromPool());
// This could be done in the same main CS as GetKeyFromKeyPool. // This could be done in the same main CS as GetKeyFromKeyPool.
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) pwalletMain->SetAddressBookName(address, strAccount);
pwalletMain->SetAddressBookName(address, strAccount);
return address.ToString(); return address.ToString();
} }
// requires cs_main, cs_mapWallet, cs_mapAddressBook locks
CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false) CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
{ {
CWalletDB walletdb(pwalletMain->strWalletFile); CWalletDB walletdb(pwalletMain->strWalletFile);
CAccount account; CAccount account;
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) walletdb.ReadAccount(strAccount, account);
{
walletdb.ReadAccount(strAccount, account);
bool bKeyUsed = false; bool bKeyUsed = false;
// Check if the current key has been used // Check if the current key has been used
if (!account.vchPubKey.empty()) if (!account.vchPubKey.empty())
{
CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(account.vchPubKey);
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin();
it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty();
++it)
{ {
CScript scriptPubKey; const CWalletTx& wtx = (*it).second;
scriptPubKey.SetBitcoinAddress(account.vchPubKey); BOOST_FOREACH(const CTxOut& txout, wtx.vout)
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); if (txout.scriptPubKey == scriptPubKey)
it != pwalletMain->mapWallet.end() && !account.vchPubKey.empty(); bKeyUsed = true;
++it)
{
const CWalletTx& wtx = (*it).second;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (txout.scriptPubKey == scriptPubKey)
bKeyUsed = true;
}
} }
}
// Generate a new key // Generate a new key
if (account.vchPubKey.empty() || bForceNew || bKeyUsed) if (account.vchPubKey.empty() || bForceNew || bKeyUsed)
{
if (pwalletMain->GetKeyPoolSize() < 1)
{ {
if (pwalletMain->GetKeyPoolSize() < 1) if (bKeyUsed || bForceNew)
{ throw JSONRPCError(-12, "Error: Keypool ran out, please call topupkeypool first");
if (bKeyUsed || bForceNew) }
throw JSONRPCError(-12, "Error: Keypool ran out, please call topupkeypool first"); else
} {
else account.vchPubKey = pwalletMain->GetOrReuseKeyFromPool();
{ pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
account.vchPubKey = pwalletMain->GetOrReuseKeyFromPool(); walletdb.WriteAccount(strAccount, account);
pwalletMain->SetAddressBookName(CBitcoinAddress(account.vchPubKey), strAccount);
walletdb.WriteAccount(strAccount, account);
}
} }
} }
@ -413,12 +408,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
Value ret; Value ret;
CRITICAL_BLOCK(cs_main) ret = GetAccountAddress(strAccount).ToString();
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{
ret = GetAccountAddress(strAccount).ToString();
}
return ret; return ret;
} }
@ -442,20 +432,15 @@ Value setaccount(const Array& params, bool fHelp)
strAccount = AccountFromValue(params[1]); strAccount = AccountFromValue(params[1]);
// Detect when changing the account of an address that is the 'unused current key' of another account: // Detect when changing the account of an address that is the 'unused current key' of another account:
CRITICAL_BLOCK(cs_main) if (pwalletMain->mapAddressBook.count(address))
CRITICAL_BLOCK(pwalletMain->cs_mapWallet)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
if (pwalletMain->mapAddressBook.count(address)) string strOldAccount = pwalletMain->mapAddressBook[address];
{ if (address == GetAccountAddress(strOldAccount))
string strOldAccount = pwalletMain->mapAddressBook[address]; GetAccountAddress(strOldAccount, true);
if (address == GetAccountAddress(strOldAccount))
GetAccountAddress(strOldAccount, true);
}
pwalletMain->SetAddressBookName(address, strAccount);
} }
pwalletMain->SetAddressBookName(address, strAccount);
return Value::null; return Value::null;
} }
@ -472,12 +457,9 @@ Value getaccount(const Array& params, bool fHelp)
throw JSONRPCError(-5, "Invalid bitcoin address"); throw JSONRPCError(-5, "Invalid bitcoin address");
string strAccount; string strAccount;
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address);
{ if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
map<CBitcoinAddress, string>::iterator mi = pwalletMain->mapAddressBook.find(address); strAccount = (*mi).second;
if (mi != pwalletMain->mapAddressBook.end() && !(*mi).second.empty())
strAccount = (*mi).second;
}
return strAccount; return strAccount;
} }
@ -493,15 +475,12 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
// Find all addresses that have the given account // Find all addresses that have the given account
Array ret; Array ret;
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) const CBitcoinAddress& address = item.first;
{ const string& strName = item.second;
const CBitcoinAddress& address = item.first; if (strName == strAccount)
const string& strName = item.second; ret.push_back(address.ToString());
if (strName == strAccount)
ret.push_back(address.ToString());
}
} }
return ret; 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()) if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str(); wtx.mapValue["to"] = params[3].get_str();
CRITICAL_BLOCK(cs_main) if (pwalletMain->IsLocked())
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
{
if(pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx); string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
if (strError != "") if (strError != "")
throw JSONRPCError(-4, strError); throw JSONRPCError(-4, strError);
}
return wtx.GetHash().GetHex(); return wtx.GetHash().GetHex();
} }
@ -586,19 +561,16 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
// Tally // Tally
int64 nAmount = 0; int64 nAmount = 0;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) const CWalletTx& wtx = (*it).second;
{ if (wtx.IsCoinBase() || !wtx.IsFinal())
const CWalletTx& wtx = (*it).second; continue;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
if (txout.scriptPubKey == scriptPubKey) if (txout.scriptPubKey == scriptPubKey)
if (wtx.GetDepthInMainChain() >= nMinDepth) if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue; nAmount += txout.nValue;
}
} }
return ValueFromAmount(nAmount); return ValueFromAmount(nAmount);
@ -607,15 +579,12 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress) void GetAccountAddresses(string strAccount, set<CBitcoinAddress>& setAddress)
{ {
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) const CBitcoinAddress& address = item.first;
{ const string& strName = item.second;
const CBitcoinAddress& address = item.first; if (strName == strAccount)
const string& strName = item.second; setAddress.insert(address);
if (strName == strAccount)
setAddress.insert(address);
}
} }
} }
@ -639,21 +608,18 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
// Tally // Tally
int64 nAmount = 0; int64 nAmount = 0;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) const CWalletTx& wtx = (*it).second;
{ if (wtx.IsCoinBase() || !wtx.IsFinal())
const CWalletTx& wtx = (*it).second; continue;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{ {
CBitcoinAddress address; CBitcoinAddress address;
if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address)) if (ExtractAddress(txout.scriptPubKey, pwalletMain, address) && setAddress.count(address))
if (wtx.GetDepthInMainChain() >= nMinDepth) if (wtx.GetDepthInMainChain() >= nMinDepth)
nAmount += txout.nValue; nAmount += txout.nValue;
}
} }
} }
@ -664,27 +630,25 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth) int64 GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth)
{ {
int64 nBalance = 0; 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)
{
const CWalletTx& wtx = (*it).second;
if (!wtx.IsFinal())
continue;
int64 nGenerated, nReceived, nSent, nFee; // Tally wallet transactions
wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee); for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
if (!wtx.IsFinal())
continue;
if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) int64 nGenerated, nReceived, nSent, nFee;
nBalance += nReceived; wtx.GetAccountAmounts(strAccount, nGenerated, nReceived, nSent, nFee);
nBalance += nGenerated - nSent - nFee;
}
// Tally internal accounting entries if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth)
nBalance += walletdb.GetAccountCreditDebit(strAccount); nBalance += nReceived;
nBalance += nGenerated - nSent - nFee;
} }
// Tally internal accounting entries
nBalance += walletdb.GetAccountCreditDebit(strAccount);
return nBalance; return nBalance;
} }
@ -763,33 +727,31 @@ Value movecmd(const Array& params, bool fHelp)
if (params.size() > 4) if (params.size() > 4)
strComment = params[4].get_str(); strComment = params[4].get_str();
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) CWalletDB walletdb(pwalletMain->strWalletFile);
{ walletdb.TxnBegin();
CWalletDB walletdb(pwalletMain->strWalletFile);
walletdb.TxnBegin(); int64 nNow = GetAdjustedTime();
int64 nNow = GetAdjustedTime(); // Debit
CAccountingEntry debit;
// Debit debit.strAccount = strFrom;
CAccountingEntry debit; debit.nCreditDebit = -nAmount;
debit.strAccount = strFrom; debit.nTime = nNow;
debit.nCreditDebit = -nAmount; debit.strOtherAccount = strTo;
debit.nTime = nNow; debit.strComment = strComment;
debit.strOtherAccount = strTo; walletdb.WriteAccountingEntry(debit);
debit.strComment = strComment;
walletdb.WriteAccountingEntry(debit); // Credit
CAccountingEntry credit;
// Credit credit.strAccount = strTo;
CAccountingEntry credit; credit.nCreditDebit = nAmount;
credit.strAccount = strTo; credit.nTime = nNow;
credit.nCreditDebit = nAmount; credit.strOtherAccount = strFrom;
credit.nTime = nNow; credit.strComment = strComment;
credit.strOtherAccount = strFrom; walletdb.WriteAccountingEntry(credit);
credit.strComment = strComment;
walletdb.WriteAccountingEntry(credit); walletdb.TxnCommit();
walletdb.TxnCommit();
}
return true; return true;
} }
@ -822,23 +784,18 @@ Value sendfrom(const Array& params, bool fHelp)
if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty()) if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
wtx.mapValue["to"] = params[5].get_str(); wtx.mapValue["to"] = params[5].get_str();
CRITICAL_BLOCK(cs_main) if (pwalletMain->IsLocked())
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{ // Check funds
if(pwalletMain->IsLocked()) int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first."); if (nAmount > nBalance)
throw JSONRPCError(-6, "Account has insufficient funds");
// Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth); // Send
if (nAmount > nBalance) string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
throw JSONRPCError(-6, "Account has insufficient funds"); if (strError != "")
throw JSONRPCError(-4, strError);
// Send
string strError = pwalletMain->SendMoneyToBitcoinAddress(address, nAmount, wtx);
if (strError != "")
throw JSONRPCError(-4, strError);
}
return wtx.GetHash().GetHex(); return wtx.GetHash().GetHex();
} }
@ -889,31 +846,26 @@ Value sendmany(const Array& params, bool fHelp)
vecSend.push_back(make_pair(scriptPubKey, nAmount)); vecSend.push_back(make_pair(scriptPubKey, nAmount));
} }
CRITICAL_BLOCK(cs_main) if (pwalletMain->IsLocked())
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
// Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
if (totalAmount > nBalance)
throw JSONRPCError(-6, "Account has insufficient funds");
// Send
CReserveKey keyChange(pwalletMain);
int64 nFeeRequired = 0;
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
if (!fCreated)
{ {
if(pwalletMain->IsLocked()) if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first."); throw JSONRPCError(-6, "Insufficient funds");
throw JSONRPCError(-4, "Transaction creation failed");
// Check funds
int64 nBalance = GetAccountBalance(strAccount, nMinDepth);
if (totalAmount > nBalance)
throw JSONRPCError(-6, "Account has insufficient funds");
// Send
CReserveKey keyChange(pwalletMain);
int64 nFeeRequired = 0;
bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired);
if (!fCreated)
{
if (totalAmount + nFeeRequired > pwalletMain->GetBalance())
throw JSONRPCError(-6, "Insufficient funds");
throw JSONRPCError(-4, "Transaction creation failed");
}
if (!pwalletMain->CommitTransaction(wtx, keyChange))
throw JSONRPCError(-4, "Transaction commit failed");
} }
if (!pwalletMain->CommitTransaction(wtx, keyChange))
throw JSONRPCError(-4, "Transaction commit failed");
return wtx.GetHash().GetHex(); return wtx.GetHash().GetHex();
} }
@ -944,68 +896,62 @@ Value ListReceived(const Array& params, bool fByAccounts)
// Tally // Tally
map<CBitcoinAddress, tallyitem> mapTally; map<CBitcoinAddress, tallyitem> mapTally;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) const CWalletTx& wtx = (*it).second;
{ if (wtx.IsCoinBase() || !wtx.IsFinal())
const CWalletTx& wtx = (*it).second; continue;
if (wtx.IsCoinBase() || !wtx.IsFinal())
continue;
int nDepth = wtx.GetDepthInMainChain(); int nDepth = wtx.GetDepthInMainChain();
if (nDepth < nMinDepth) if (nDepth < nMinDepth)
continue; continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{ {
CBitcoinAddress address; CBitcoinAddress address;
if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid()) if (!ExtractAddress(txout.scriptPubKey, pwalletMain, address) || !address.IsValid())
continue; continue;
tallyitem& item = mapTally[address]; tallyitem& item = mapTally[address];
item.nAmount += txout.nValue; item.nAmount += txout.nValue;
item.nConf = min(item.nConf, nDepth); item.nConf = min(item.nConf, nDepth);
}
} }
} }
// Reply // Reply
Array ret; Array ret;
map<string, tallyitem> mapAccountTally; map<string, tallyitem> mapAccountTally;
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) const CBitcoinAddress& address = item.first;
{ const string& strAccount = item.second;
const CBitcoinAddress& address = item.first; map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address);
const string& strAccount = item.second; if (it == mapTally.end() && !fIncludeEmpty)
map<CBitcoinAddress, tallyitem>::iterator it = mapTally.find(address); continue;
if (it == mapTally.end() && !fIncludeEmpty)
continue;
int64 nAmount = 0; int64 nAmount = 0;
int nConf = INT_MAX; int nConf = INT_MAX;
if (it != mapTally.end()) if (it != mapTally.end())
{ {
nAmount = (*it).second.nAmount; nAmount = (*it).second.nAmount;
nConf = (*it).second.nConf; nConf = (*it).second.nConf;
} }
if (fByAccounts) if (fByAccounts)
{ {
tallyitem& item = mapAccountTally[strAccount]; tallyitem& item = mapAccountTally[strAccount];
item.nAmount += nAmount; item.nAmount += nAmount;
item.nConf = min(item.nConf, nConf); item.nConf = min(item.nConf, nConf);
} }
else else
{ {
Object obj; Object obj;
obj.push_back(Pair("address", address.ToString())); obj.push_back(Pair("address", address.ToString()));
obj.push_back(Pair("account", strAccount)); obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("label", strAccount)); // deprecated obj.push_back(Pair("label", strAccount)); // deprecated
obj.push_back(Pair("amount", ValueFromAmount(nAmount))); obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf))); obj.push_back(Pair("confirmations", (nConf == INT_MAX ? 0 : nConf)));
ret.push_back(obj); ret.push_back(obj);
}
} }
} }
@ -1107,27 +1053,23 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
// Received // Received
if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived) string account;
if (pwalletMain->mapAddressBook.count(r.first))
account = pwalletMain->mapAddressBook[r.first];
if (fAllAccounts || (account == strAccount))
{ {
string account; Object entry;
if (pwalletMain->mapAddressBook.count(r.first)) entry.push_back(Pair("account", account));
account = pwalletMain->mapAddressBook[r.first]; entry.push_back(Pair("address", r.first.ToString()));
if (fAllAccounts || (account == strAccount)) entry.push_back(Pair("category", "receive"));
{ entry.push_back(Pair("amount", ValueFromAmount(r.second)));
Object entry; if (fLong)
entry.push_back(Pair("account", account)); WalletTxToJSON(wtx, entry);
entry.push_back(Pair("address", r.first.ToString())); ret.push_back(entry);
entry.push_back(Pair("category", "receive"));
entry.push_back(Pair("amount", ValueFromAmount(r.second)));
if (fLong)
WalletTxToJSON(wtx, entry);
ret.push_back(entry);
}
} }
} }
} }
void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret) void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
@ -1167,41 +1109,38 @@ Value listtransactions(const Array& params, bool fHelp)
Array ret; Array ret;
CWalletDB walletdb(pwalletMain->strWalletFile); 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;
// Firs: get all CWalletTx and CAccountingEntry into a sorted-by-time multimap: typedef multimap<int64, TxPair > TxItems;
typedef pair<CWalletTx*, CAccountingEntry*> TxPair; TxItems txByTime;
typedef multimap<int64, TxPair > TxItems;
TxItems txByTime;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{ {
CWalletTx* wtx = &((*it).second); CWalletTx* wtx = &((*it).second);
txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0))); txByTime.insert(make_pair(wtx->GetTxTime(), TxPair(wtx, (CAccountingEntry*)0)));
} }
list<CAccountingEntry> acentries; list<CAccountingEntry> acentries;
walletdb.ListAccountCreditDebit(strAccount, acentries); walletdb.ListAccountCreditDebit(strAccount, acentries);
BOOST_FOREACH(CAccountingEntry& entry, acentries) BOOST_FOREACH(CAccountingEntry& entry, acentries)
{ {
txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry))); txByTime.insert(make_pair(entry.nTime, TxPair((CWalletTx*)0, &entry)));
} }
// Now: iterate backwards until we have nCount items to return: // Now: iterate backwards until we have nCount items to return:
TxItems::reverse_iterator it = txByTime.rbegin(); TxItems::reverse_iterator it = txByTime.rbegin();
if (txByTime.size() > nFrom) std::advance(it, nFrom); if (txByTime.size() > nFrom) std::advance(it, nFrom);
for (; it != txByTime.rend(); ++it) for (; it != txByTime.rend(); ++it)
{ {
CWalletTx *const pwtx = (*it).second.first; CWalletTx *const pwtx = (*it).second.first;
if (pwtx != 0) if (pwtx != 0)
ListTransactions(*pwtx, strAccount, 0, true, ret); ListTransactions(*pwtx, strAccount, 0, true, ret);
CAccountingEntry *const pacentry = (*it).second.second; CAccountingEntry *const pacentry = (*it).second.second;
if (pacentry != 0) if (pacentry != 0)
AcentryToJSON(*pacentry, strAccount, ret); AcentryToJSON(*pacentry, strAccount, ret);
if (ret.size() >= nCount) break; if (ret.size() >= nCount) break;
}
// ret is now newest to oldest
} }
// ret is now newest to oldest
// Make sure we return only last nCount items (sends-to-self might give us an extra): // Make sure we return only last nCount items (sends-to-self might give us an extra):
if (ret.size() > nCount) if (ret.size() > nCount)
@ -1227,34 +1166,30 @@ Value listaccounts(const Array& params, bool fHelp)
nMinDepth = params[0].get_int(); nMinDepth = params[0].get_int();
map<string, int64> mapAccountBalances; map<string, int64> mapAccountBalances;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) {
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
{ mapAccountBalances[entry.second] = 0;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& entry, pwalletMain->mapAddressBook) { }
if (pwalletMain->HaveKey(entry.first)) // This address belongs to me
mapAccountBalances[entry.second] = 0;
}
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
int64 nGeneratedImmature, nGeneratedMature, nFee;
string strSentAccount;
list<pair<CBitcoinAddress, int64> > listReceived;
list<pair<CBitcoinAddress, int64> > listSent;
wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount);
mapAccountBalances[strSentAccount] -= nFee;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
mapAccountBalances[strSentAccount] -= s.second;
if (wtx.GetDepthInMainChain() >= nMinDepth)
{ {
const CWalletTx& wtx = (*it).second; mapAccountBalances[""] += nGeneratedMature;
int64 nGeneratedImmature, nGeneratedMature, nFee; BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
string strSentAccount; if (pwalletMain->mapAddressBook.count(r.first))
list<pair<CBitcoinAddress, int64> > listReceived; mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
list<pair<CBitcoinAddress, int64> > listSent; else
wtx.GetAmounts(nGeneratedImmature, nGeneratedMature, listReceived, listSent, nFee, strSentAccount); mapAccountBalances[""] += r.second;
mapAccountBalances[strSentAccount] -= nFee;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& s, listSent)
mapAccountBalances[strSentAccount] -= s.second;
if (wtx.GetDepthInMainChain() >= nMinDepth)
{
mapAccountBalances[""] += nGeneratedMature;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, int64)& r, listReceived)
if (pwalletMain->mapAddressBook.count(r.first))
mapAccountBalances[pwalletMain->mapAddressBook[r.first]] += r.second;
else
mapAccountBalances[""] += r.second;
}
} }
} }
@ -1281,27 +1216,25 @@ Value gettransaction(const Array& params, bool fHelp)
hash.SetHex(params[0].get_str()); hash.SetHex(params[0].get_str());
Object entry; 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];
int64 nCredit = wtx.GetCredit(); if (!pwalletMain->mapWallet.count(hash))
int64 nDebit = wtx.GetDebit(); throw JSONRPCError(-5, "Invalid or non-wallet transaction id");
int64 nNet = nCredit - nDebit; const CWalletTx& wtx = pwalletMain->mapWallet[hash];
int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); int64 nCredit = wtx.GetCredit();
if (wtx.IsFromMe()) int64 nDebit = wtx.GetDebit();
entry.push_back(Pair("fee", ValueFromAmount(nFee))); int64 nNet = nCredit - nDebit;
int64 nFee = (wtx.IsFromMe() ? wtx.GetValueOut() - nDebit : 0);
WalletTxToJSON(pwalletMain->mapWallet[hash], entry); entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
if (wtx.IsFromMe())
entry.push_back(Pair("fee", ValueFromAmount(nFee)));
Array details; WalletTxToJSON(pwalletMain->mapWallet[hash], entry);
ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
entry.push_back(Pair("details", details)); Array details;
} ListTransactions(pwalletMain->mapWallet[hash], "*", 0, false, details);
entry.push_back(Pair("details", details));
return entry; return entry;
} }
@ -1332,13 +1265,10 @@ Value keypoolrefill(const Array& params, bool fHelp)
"keypoolrefill\n" "keypoolrefill\n"
"Fills the keypool."); "Fills the keypool.");
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) if (pwalletMain->IsLocked())
{ throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
if (pwalletMain->IsLocked())
throw JSONRPCError(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.");
pwalletMain->TopUpKeyPool(); pwalletMain->TopUpKeyPool();
}
if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100)) if (pwalletMain->GetKeyPoolSize() < GetArg("-keypool", 100))
throw JSONRPCError(-4, "Error refreshing keypool."); throw JSONRPCError(-4, "Error refreshing keypool.");
@ -1407,24 +1337,21 @@ Value walletpassphrase(const Array& params, bool fHelp)
mlock(&strWalletPass[0], strWalletPass.capacity()); mlock(&strWalletPass[0], strWalletPass.capacity());
strWalletPass = params[0].get_str(); strWalletPass = params[0].get_str();
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) if (strWalletPass.length() > 0)
{ {
if (strWalletPass.length() > 0) if (!pwalletMain->Unlock(strWalletPass))
{ {
if (!pwalletMain->Unlock(strWalletPass))
{
fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity());
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
}
fill(strWalletPass.begin(), strWalletPass.end(), '\0'); fill(strWalletPass.begin(), strWalletPass.end(), '\0');
munlock(&strWalletPass[0], strWalletPass.capacity()); munlock(&strWalletPass[0], strWalletPass.capacity());
throw JSONRPCError(-14, "Error: The wallet passphrase entered was incorrect.");
} }
else fill(strWalletPass.begin(), strWalletPass.end(), '\0');
throw runtime_error( munlock(&strWalletPass[0], strWalletPass.capacity());
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
} }
else
throw runtime_error(
"walletpassphrase <passphrase> <timeout>\n"
"Stores the wallet decryption key in memory for <timeout> seconds.");
CreateThread(ThreadTopUpKeyPool, NULL); CreateThread(ThreadTopUpKeyPool, NULL);
int* pnSleepTime = new int(params[1].get_int()); int* pnSleepTime = new int(params[1].get_int());
@ -1553,11 +1480,8 @@ Value validateaddress(const Array& params, bool fHelp)
string currentAddress = address.ToString(); string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress)); ret.push_back(Pair("address", currentAddress));
ret.push_back(Pair("ismine", (pwalletMain->HaveKey(address) > 0))); 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]));
if (pwalletMain->mapAddressBook.count(address))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[address]));
}
} }
return ret; return ret;
} }
@ -2233,7 +2157,10 @@ void ThreadRPCServer2(void* parg)
try try
{ {
// Execute // 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 // Send reply
string strReply = JSONRPCReply(result, Value::null, id); string strReply = JSONRPCReply(result, Value::null, id);

102
src/script.cpp

@ -1033,48 +1033,45 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash
return false; return false;
// Compile solution // Compile solution
CRITICAL_BLOCK(keystore.cs_KeyStore) BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{ {
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) if (item.first == OP_PUBKEY)
{ {
if (item.first == OP_PUBKEY) // Sign
const valtype& vchPubKey = item.second;
CKey key;
if (!keystore.GetKey(Hash160(vchPubKey), key))
return false;
if (key.GetPubKey() != vchPubKey)
return false;
if (hash != 0)
{ {
// Sign vector<unsigned char> vchSig;
const valtype& vchPubKey = item.second; if (!key.Sign(hash, vchSig))
CKey key;
if (!keystore.GetKey(Hash160(vchPubKey), key))
return false;
if (key.GetPubKey() != vchPubKey)
return false; return false;
if (hash != 0) vchSig.push_back((unsigned char)nHashType);
{ scriptSigRet << vchSig;
vector<unsigned char> vchSig;
if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig;
}
} }
else if (item.first == OP_PUBKEYHASH) }
else if (item.first == OP_PUBKEYHASH)
{
// Sign and give pubkey
CKey key;
if (!keystore.GetKey(uint160(item.second), key))
return false;
if (hash != 0)
{ {
// Sign and give pubkey vector<unsigned char> vchSig;
CKey key; if (!key.Sign(hash, vchSig))
if (!keystore.GetKey(uint160(item.second), key))
return false; return false;
if (hash != 0) vchSig.push_back((unsigned char)nHashType);
{ scriptSigRet << vchSig << key.GetPubKey();
vector<unsigned char> vchSig;
if (!key.Sign(hash, vchSig))
return false;
vchSig.push_back((unsigned char)nHashType);
scriptSigRet << vchSig << key.GetPubKey();
}
}
else
{
return false;
} }
} }
else
{
return false;
}
} }
return true; return true;
@ -1095,35 +1092,31 @@ bool IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
return false; return false;
// Compile solution // Compile solution
CRITICAL_BLOCK(keystore.cs_KeyStore) BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution)
{ {
BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) if (item.first == OP_PUBKEY)
{ {
if (item.first == OP_PUBKEY) const valtype& vchPubKey = item.second;
{ vector<unsigned char> vchPubKeyFound;
const valtype& vchPubKey = item.second; if (!keystore.GetPubKey(Hash160(vchPubKey), vchPubKeyFound))
vector<unsigned char> vchPubKeyFound;
if (!keystore.GetPubKey(Hash160(vchPubKey), vchPubKeyFound))
return false;
if (vchPubKeyFound != vchPubKey)
return false;
}
else if (item.first == OP_PUBKEYHASH)
{
if (!keystore.HaveKey(uint160(item.second)))
return false;
}
else
{
return false; return false;
} if (vchPubKeyFound != vchPubKey)
return false;
}
else if (item.first == OP_PUBKEYHASH)
{
if (!keystore.HaveKey(uint160(item.second)))
return false;
}
else
{
return false;
} }
} }
return true; return true;
} }
// requires either keystore==0, or a lock on keystore->cs_KeyStore
bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet) bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
{ {
vector<pair<opcodetype, valtype> > vSolution; vector<pair<opcodetype, valtype> > vSolution;
@ -1146,8 +1139,7 @@ bool static ExtractAddressInner(const CScript& scriptPubKey, const CKeyStore* ke
bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet) bool ExtractAddress(const CScript& scriptPubKey, const CKeyStore* keystore, CBitcoinAddress& addressRet)
{ {
if (keystore) if (keystore)
CRITICAL_BLOCK(keystore->cs_KeyStore) return ExtractAddressInner(scriptPubKey, keystore, addressRet);
return ExtractAddressInner(scriptPubKey, keystore, addressRet);
else else
return ExtractAddressInner(scriptPubKey, NULL, addressRet); return ExtractAddressInner(scriptPubKey, NULL, addressRet);
return false; return false;

375
src/ui.cpp

@ -708,7 +708,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
CBitcoinAddress address; CBitcoinAddress address;
if (ExtractAddress(txout.scriptPubKey, pwalletMain, address)) if (ExtractAddress(txout.scriptPubKey, pwalletMain, address))
{ {
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
//strDescription += _("Received payment to "); //strDescription += _("Received payment to ");
//strDescription += _("Received with address "); //strDescription += _("Received with address ");
@ -792,7 +792,7 @@ bool CMainFrame::InsertTransaction(const CWalletTx& wtx, bool fNew, int nIndex)
} }
string strDescription = _("To: "); string strDescription = _("To: ");
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
if (pwalletMain->mapAddressBook.count(address) && !pwalletMain->mapAddressBook[address].empty()) if (pwalletMain->mapAddressBook.count(address) && !pwalletMain->mapAddressBook[address].empty())
strDescription += pwalletMain->mapAddressBook[address] + " "; strDescription += pwalletMain->mapAddressBook[address] + " ";
strDescription += strAddress; strDescription += strAddress;
@ -862,7 +862,7 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
// Collect list of wallet transactions and sort newest first // Collect list of wallet transactions and sort newest first
bool fEntered = false; bool fEntered = false;
vector<pair<unsigned int, uint256> > vSorted; vector<pair<unsigned int, uint256> > vSorted;
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
printf("RefreshListCtrl starting\n"); printf("RefreshListCtrl starting\n");
fEntered = true; fEntered = true;
@ -890,7 +890,7 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
if (fShutdown) if (fShutdown)
return; return;
bool fEntered = false; bool fEntered = false;
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
fEntered = true; fEntered = true;
uint256& hash = vSorted[i++].second; uint256& hash = vSorted[i++].second;
@ -913,7 +913,7 @@ void CMainFrame::OnIdle(wxIdleEvent& event)
static int64 nLastTime; static int64 nLastTime;
if (GetTime() > nLastTime + 30) if (GetTime() > nLastTime + 30)
{ {
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
nLastTime = GetTime(); nLastTime = GetTime();
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) 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) if (nTop == nLastTop && pindexLastBest == pindexBest)
return; return;
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
int nStart = nTop; int nStart = nTop;
int nEnd = min(nStart + 100, m_listCtrl->GetItemCount()); int nEnd = min(nStart + 100, m_listCtrl->GetItemCount());
@ -1032,6 +1032,7 @@ void MainFrameRepaint()
printf("MainFrameRepaint\n"); printf("MainFrameRepaint\n");
wxPaintEvent event; wxPaintEvent event;
pframeMain->fRefresh = true; pframeMain->fRefresh = true;
pframeMain->fRefreshListCtrl = true;
pframeMain->GetEventHandler()->AddPendingEvent(event); pframeMain->GetEventHandler()->AddPendingEvent(event);
} }
} }
@ -1057,7 +1058,7 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
// Update listctrl contents // Update listctrl contents
if (!pwalletMain->vWalletUpdated.empty()) if (!pwalletMain->vWalletUpdated.empty())
{ {
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
string strTop; string strTop;
if (m_listCtrl->GetItemCount()) if (m_listCtrl->GetItemCount())
@ -1075,7 +1076,7 @@ void CMainFrame::OnPaintListCtrl(wxPaintEvent& event)
} }
// Balance total // Balance total
TRY_CRITICAL_BLOCK(pwalletMain->cs_mapWallet) TRY_CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
fPaintedBalance = true; fPaintedBalance = true;
m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " "); m_staticTextBalance->SetLabel(FormatMoney(pwalletMain->GetBalance()) + " ");
@ -1247,83 +1248,80 @@ void CMainFrame::OnMenuOptionsChangeWalletPassphrase(wxCommandEvent& event)
strOldWalletPass = wxGetPasswordFromUser(_("Enter the current passphrase to the wallet."), strOldWalletPass = wxGetPasswordFromUser(_("Enter the current passphrase to the wallet."),
_("Passphrase")).ToStdString(); _("Passphrase")).ToStdString();
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) bool fWasLocked = pwalletMain->IsLocked();
{ pwalletMain->Lock();
bool fWasLocked = pwalletMain->IsLocked();
pwalletMain->Lock();
if (!strOldWalletPass.size() || !pwalletMain->Unlock(strOldWalletPass)) if (!strOldWalletPass.size() || !pwalletMain->Unlock(strOldWalletPass))
{ {
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR); wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
return; return;
} }
if (fWasLocked) if (fWasLocked)
pwalletMain->Lock(); pwalletMain->Lock();
string strNewWalletPass; string strNewWalletPass;
strNewWalletPass.reserve(100); strNewWalletPass.reserve(100);
mlock(&strNewWalletPass[0], strNewWalletPass.capacity()); mlock(&strNewWalletPass[0], strNewWalletPass.capacity());
// obtain new wallet encrypt/decrypt key, from passphrase // obtain new wallet encrypt/decrypt key, from passphrase
// Note that the passphrase is not mlock()d during this entry and could potentially // Note that the passphrase is not mlock()d during this entry and could potentially
// be obtained from disk long after bitcoin has run. // be obtained from disk long after bitcoin has run.
strNewWalletPass = wxGetPasswordFromUser(_("Enter the new passphrase for the wallet."), strNewWalletPass = wxGetPasswordFromUser(_("Enter the new passphrase for the wallet."),
_("Passphrase")).ToStdString(); _("Passphrase")).ToStdString();
if (!strNewWalletPass.size()) if (!strNewWalletPass.size())
{ {
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
wxMessageBox(_("Error: The supplied passphrase was too short."), "Bitcoin", wxOK | wxICON_ERROR); wxMessageBox(_("Error: The supplied passphrase was too short."), "Bitcoin", wxOK | wxICON_ERROR);
return; return;
} }
string strNewWalletPassTest; string strNewWalletPassTest;
strNewWalletPassTest.reserve(100); strNewWalletPassTest.reserve(100);
mlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity()); mlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
// obtain new wallet encrypt/decrypt key, from passphrase // obtain new wallet encrypt/decrypt key, from passphrase
// Note that the passphrase is not mlock()d during this entry and could potentially // Note that the passphrase is not mlock()d during this entry and could potentially
// be obtained from disk long after bitcoin has run. // be obtained from disk long after bitcoin has run.
strNewWalletPassTest = wxGetPasswordFromUser(_("Re-enter the new passphrase for the wallet."), strNewWalletPassTest = wxGetPasswordFromUser(_("Re-enter the new passphrase for the wallet."),
_("Passphrase")).ToStdString(); _("Passphrase")).ToStdString();
if (strNewWalletPassTest != strNewWalletPass) if (strNewWalletPassTest != strNewWalletPass)
{ {
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0'); fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity()); munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
wxMessageBox(_("Error: the supplied passphrases didn't match."), "Bitcoin", wxOK | wxICON_ERROR); wxMessageBox(_("Error: the supplied passphrases didn't match."), "Bitcoin", wxOK | wxICON_ERROR);
return; return;
} }
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
{ {
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
return;
}
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0'); fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0'); fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0'); fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity()); munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity()); munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity()); munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
wxMessageBox(_("Wallet Passphrase Changed."), "Bitcoin"); wxMessageBox(_("The passphrase entered for the wallet decryption was incorrect."), "Bitcoin", wxOK | wxICON_ERROR);
return;
} }
fill(strOldWalletPass.begin(), strOldWalletPass.end(), '\0');
fill(strNewWalletPass.begin(), strNewWalletPass.end(), '\0');
fill(strNewWalletPassTest.begin(), strNewWalletPassTest.end(), '\0');
munlock(&strOldWalletPass[0], strOldWalletPass.capacity());
munlock(&strNewWalletPass[0], strNewWalletPass.capacity());
munlock(&strNewWalletPassTest[0], strNewWalletPassTest.capacity());
wxMessageBox(_("Wallet Passphrase Changed."), "Bitcoin");
} }
void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event) void CMainFrame::OnMenuOptionsOptions(wxCommandEvent& event)
@ -1387,21 +1385,19 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event)
string strName = dialog.GetValue(); string strName = dialog.GetValue();
string strAddress; string strAddress;
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey)
{
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
// Generate new key bool fWasLocked = pwalletMain->IsLocked();
strAddress = CBitcoinAddress(pwalletMain->GetOrReuseKeyFromPool()).ToString(); if (!GetWalletPassphrase())
return;
if (fWasLocked) // Generate new key
pwalletMain->Lock(); strAddress = CBitcoinAddress(pwalletMain->GetOrReuseKeyFromPool()).ToString();
}
if (fWasLocked)
pwalletMain->Lock();
// Save // Save
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
pwalletMain->SetAddressBookName(strAddress, strName); pwalletMain->SetAddressBookName(strAddress, strName);
SetDefaultReceivingAddress(strAddress); SetDefaultReceivingAddress(strAddress);
} }
@ -1420,7 +1416,7 @@ void CMainFrame::OnListItemActivated(wxListEvent& event)
{ {
uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1)); uint256 hash((string)GetItemText(m_listCtrl, event.GetIndex(), 1));
CWalletTx wtx; CWalletTx wtx;
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash); map<uint256, CWalletTx>::iterator mi = pwalletMain->mapWallet.find(hash);
if (mi == pwalletMain->mapWallet.end()) if (mi == pwalletMain->mapWallet.end())
@ -1451,7 +1447,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
#ifdef __WXMSW__ #ifdef __WXMSW__
SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight()); SetSize(nScaleX * GetSize().GetWidth(), nScaleY * GetSize().GetHeight());
#endif #endif
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
string strHTML; string strHTML;
strHTML.reserve(4000); strHTML.reserve(4000);
@ -1662,7 +1658,7 @@ CTxDetailsDialog::CTxDetailsDialog(wxWindow* parent, CWalletTx wtx) : CTxDetails
strHTML += HtmlEscape(wtx.ToString(), true); strHTML += HtmlEscape(wtx.ToString(), true);
strHTML += "<br><b>Inputs:</b><br>"; strHTML += "<br><b>Inputs:</b><br>";
CRITICAL_BLOCK(pwalletMain->cs_mapWallet) CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
BOOST_FOREACH(const CTxIn& txin, wtx.vin) BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{ {
@ -2160,38 +2156,39 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
if (fBitcoinAddress) if (fBitcoinAddress)
{ {
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
string strError;
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
bool fWasLocked = pwalletMain->IsLocked();
if (!GetWalletPassphrase())
return;
// Send to bitcoin address // Send to bitcoin address
CScript scriptPubKey; CScript scriptPubKey;
scriptPubKey.SetBitcoinAddress(address); scriptPubKey.SetBitcoinAddress(address);
string strError = pwalletMain->SendMoney(scriptPubKey, nValue, wtx, true); strError = pwalletMain->SendMoney(scriptPubKey, nValue, wtx, true);
if (strError == "") }
wxMessageBox(_("Payment sent "), _("Sending...")); if (strError == "")
else if (strError == "ABORTED") wxMessageBox(_("Payment sent "), _("Sending..."));
{ else if (strError == "ABORTED")
if (fWasLocked) {
pwalletMain->Lock(); if (fWasLocked)
return; // leave send dialog open pwalletMain->Lock();
} return; // leave send dialog open
else }
{ else
wxMessageBox(strError + " ", _("Sending...")); {
EndModal(false); wxMessageBox(strError + " ", _("Sending..."));
if (fWasLocked) EndModal(false);
pwalletMain->Lock();
return;
}
if (fWasLocked) if (fWasLocked)
pwalletMain->Lock(); pwalletMain->Lock();
} return;
}
if (fWasLocked)
pwalletMain->Lock();
} }
else else
{ {
@ -2212,7 +2209,7 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event)
return; return;
} }
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
if (!pwalletMain->mapAddressBook.count(address)) if (!pwalletMain->mapAddressBook.count(address))
pwalletMain->SetAddressBookName(strAddress, ""); pwalletMain->SetAddressBookName(strAddress, "");
@ -2464,83 +2461,89 @@ void CSendingDialog::OnReply2(CDataStream& vRecv)
return; return;
} }
CRITICAL_BLOCK(cs_main) // Pay
if (!Status(_("Creating transaction...")))
return;
if (nPrice + nTransactionFee > pwalletMain->GetBalance())
{ {
// Pay Error(_("Insufficient funds"));
if (!Status(_("Creating transaction..."))) return;
return; }
if (nPrice + nTransactionFee > pwalletMain->GetBalance())
{
Error(_("Insufficient funds"));
return;
}
CReserveKey reservekey(pwalletMain); CReserveKey reservekey(pwalletMain);
int64 nFeeRequired; int64 nFeeRequired;
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) bool fWasLocked = pwalletMain->IsLocked();
{ if (!GetWalletPassphrase())
bool fWasLocked = pwalletMain->IsLocked(); return;
if (!GetWalletPassphrase())
return;
if (!pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired)) bool fTxCreated = false;
{ CRITICAL_BLOCK(cs_main)
if (nPrice + nFeeRequired > pwalletMain->GetBalance()) CRITICAL_BLOCK(pwalletMain->cs_wallet)
Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str())); {
else fTxCreated = pwalletMain->CreateTransaction(scriptPubKey, nPrice, wtx, reservekey, nFeeRequired);
Error(_("Transaction creation failed")); }
return; if (!fTxCreated)
} {
if (nPrice + nFeeRequired > pwalletMain->GetBalance())
Error(strprintf(_("This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds"), FormatMoney(nFeeRequired).c_str()));
else
Error(_("Transaction creation failed"));
return;
}
if (fWasLocked) if (fWasLocked)
pwalletMain->Lock(); pwalletMain->Lock();
}
// Transaction fee // Transaction fee
if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this)) if (!ThreadSafeAskFee(nFeeRequired, _("Sending..."), this))
{ {
Error(_("Transaction aborted")); Error(_("Transaction aborted"));
return; return;
} }
// Make sure we're still connected // Make sure we're still connected
CNode* pnode = ConnectNode(addr, 2 * 60 * 60); CNode* pnode = ConnectNode(addr, 2 * 60 * 60);
if (!pnode) if (!pnode)
{ {
Error(_("Lost connection, transaction cancelled")); Error(_("Lost connection, transaction cancelled"));
return; return;
} }
// Last chance to cancel // Last chance to cancel
Sleep(50); Sleep(50);
if (!Status())
return;
fCanCancel = false;
if (fAbort)
{
fCanCancel = true;
if (!Status()) if (!Status())
return; return;
fCanCancel = false; fCanCancel = false;
if (fAbort) }
{ if (!Status(_("Sending payment...")))
fCanCancel = true; return;
if (!Status())
return;
fCanCancel = false;
}
if (!Status(_("Sending payment...")))
return;
// Commit // Commit
if (!pwalletMain->CommitTransaction(wtx, reservekey)) bool fTxCommitted = false;
{ CRITICAL_BLOCK(cs_main)
Error(_("The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.")); CRITICAL_BLOCK(pwalletMain->cs_wallet)
return; {
} fTxCommitted = pwalletMain->CommitTransaction(wtx, reservekey);
}
if (!fTxCommitted)
{
Error(_("The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."));
return;
}
// Send payment tx to seller, with response going to OnReply3 via event handler // Send payment tx to seller, with response going to OnReply3 via event handler
CWalletTx wtxSend = wtx; CWalletTx wtxSend = wtx;
wtxSend.fFromMe = false; wtxSend.fFromMe = false;
pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this); pnode->PushRequest("submitorder", wtxSend, SendingDialogOnReply3, this);
Status(_("Waiting for confirmation...")); Status(_("Waiting for confirmation..."));
MainFrameRepaint(); MainFrameRepaint();
}
} }
void SendingDialogOnReply3(void* parg, CDataStream& vRecv) void SendingDialogOnReply3(void* parg, CDataStream& vRecv)
@ -2621,8 +2624,7 @@ CAddressBookDialog::CAddressBookDialog(wxWindow* parent, const wxString& strInit
m_listCtrlReceiving->SetFocus(); m_listCtrlReceiving->SetFocus();
// Fill listctrl with address book data // Fill listctrl with address book data
CRITICAL_BLOCK(pwalletMain->cs_KeyStore) CRITICAL_BLOCK(pwalletMain->cs_wallet)
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook)
{ {
string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue(); string strDefaultReceiving = (string)pframeMain->m_textCtrlAddress->GetValue();
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook) BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, string)& item, pwalletMain->mapAddressBook)
@ -2683,7 +2685,7 @@ void CAddressBookDialog::OnListEndLabelEdit(wxListEvent& event)
if (event.IsEditCancelled()) if (event.IsEditCancelled())
return; return;
string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1); string strAddress = (string)GetItemText(m_listCtrl, event.GetIndex(), 1);
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
pwalletMain->SetAddressBookName(strAddress, string(event.GetText())); pwalletMain->SetAddressBookName(strAddress, string(event.GetText()));
pframeMain->RefreshListCtrl(); pframeMain->RefreshListCtrl();
} }
@ -2719,7 +2721,7 @@ void CAddressBookDialog::OnButtonDelete(wxCommandEvent& event)
if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED)) if (m_listCtrl->GetItemState(nIndex, wxLIST_STATE_SELECTED))
{ {
string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1); string strAddress = (string)GetItemText(m_listCtrl, nIndex, 1);
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
pwalletMain->DelAddressBookName(strAddress); pwalletMain->DelAddressBookName(strAddress);
m_listCtrl->DeleteItem(nIndex); m_listCtrl->DeleteItem(nIndex);
} }
@ -2779,7 +2781,7 @@ void CAddressBookDialog::OnButtonEdit(wxCommandEvent& event)
} }
// Write back // Write back
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
{ {
if (strAddress != strAddressOrg) if (strAddress != strAddressOrg)
pwalletMain->DelAddressBookName(strAddressOrg); pwalletMain->DelAddressBookName(strAddressOrg);
@ -2819,22 +2821,19 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
return; return;
strName = dialog.GetValue(); strName = dialog.GetValue();
CRITICAL_BLOCK(pwalletMain->cs_vMasterKey) bool fWasLocked = pwalletMain->IsLocked();
{ if (!GetWalletPassphrase())
bool fWasLocked = pwalletMain->IsLocked(); return;
if (!GetWalletPassphrase())
return;
// Generate new key // Generate new key
strAddress = CBitcoinAddress(pwalletMain->GetOrReuseKeyFromPool()).ToString(); strAddress = CBitcoinAddress(pwalletMain->GetOrReuseKeyFromPool()).ToString();
if (fWasLocked) if (fWasLocked)
pwalletMain->Lock(); pwalletMain->Lock();
}
} }
// Add to list and select it // Add to list and select it
CRITICAL_BLOCK(pwalletMain->cs_mapAddressBook) CRITICAL_BLOCK(pwalletMain->cs_wallet)
pwalletMain->SetAddressBookName(strAddress, strName); pwalletMain->SetAddressBookName(strAddress, strName);
int nIndex = InsertLine(m_listCtrl, strName, strAddress); int nIndex = InsertLine(m_listCtrl, strName, strAddress);
SetSelection(m_listCtrl, nIndex); SetSelection(m_listCtrl, nIndex);

8
src/util.cpp

@ -942,17 +942,21 @@ static std::map<std::pair<CCriticalSection*, CCriticalSection*>, LockStack> lock
static boost::thread_specific_ptr<LockStack> lockstack; static boost::thread_specific_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const LockStack& s1, const LockStack& s2) static void potential_deadlock_detected(const std::pair<CCriticalSection*, CCriticalSection*>& mismatch, const LockStack& s1, const LockStack& s2)
{ {
printf("POTENTIAL DEADLOCK DETECTED\n"); printf("POTENTIAL DEADLOCK DETECTED\n");
printf("Previous lock order was:\n"); printf("Previous lock order was:\n");
BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2) BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s2)
{ {
if (i.first == mismatch.first) printf(" (1)");
if (i.first == mismatch.second) printf(" (2)");
printf(" %s %s:%d\n", i.second.mutexName.c_str(), i.second.sourceFile.c_str(), i.second.sourceLine); printf(" %s %s:%d\n", i.second.mutexName.c_str(), i.second.sourceFile.c_str(), i.second.sourceLine);
} }
printf("Current lock order is:\n"); printf("Current lock order is:\n");
BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1) BOOST_FOREACH(const PAIRTYPE(CCriticalSection*, CLockLocation)& i, s1)
{ {
if (i.first == mismatch.first) printf(" (1)");
if (i.first == mismatch.second) printf(" (2)");
printf(" %s %s:%d\n", i.second.mutexName.c_str(), i.second.sourceFile.c_str(), i.second.sourceLine); printf(" %s %s:%d\n", i.second.mutexName.c_str(), i.second.sourceFile.c_str(), i.second.sourceLine);
} }
} }
@ -979,7 +983,7 @@ static void push_lock(CCriticalSection* c, const CLockLocation& locklocation)
std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first); std::pair<CCriticalSection*, CCriticalSection*> p2 = std::make_pair(c, i.first);
if (lockorders.count(p2)) if (lockorders.count(p2))
{ {
potential_deadlock_detected(lockorders[p2], lockorders[p1]); potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
break; break;
} }
} }

201
src/wallet.cpp

@ -33,7 +33,7 @@ bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector
return false; return false;
if (!fFileBacked) if (!fFileBacked)
return true; return true;
CRITICAL_BLOCK(cs_pwalletdbEncryption) CRITICAL_BLOCK(cs_wallet)
{ {
if (pwalletdbEncryption) if (pwalletdbEncryption)
return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret); 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) bool CWallet::Unlock(const string& strWalletPassphrase)
{ {
CRITICAL_BLOCK(cs_vMasterKey) if (!IsLocked())
{ return false;
if (!IsLocked())
return false;
CCrypter crypter; CCrypter crypter;
CKeyingMaterial vMasterKey; CKeyingMaterial vMasterKey;
CRITICAL_BLOCK(cs_wallet)
BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys) BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
{ {
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) 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)) if (CCryptoKeyStore::Unlock(vMasterKey))
return true; return true;
} }
}
return false; return false;
} }
bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase) bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
{ {
CRITICAL_BLOCK(cs_vMasterKey) bool fWasLocked = IsLocked();
{
bool fWasLocked = IsLocked();
CRITICAL_BLOCK(cs_wallet)
{
Lock(); Lock();
CCrypter crypter; 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)) if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false; return false;
if(!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey)) if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
return false; return false;
if (CCryptoKeyStore::Unlock(vMasterKey)) if (CCryptoKeyStore::Unlock(vMasterKey))
{ {
@ -107,6 +105,7 @@ bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const
} }
} }
} }
return false; return false;
} }
@ -125,44 +124,42 @@ public:
bool CWallet::EncryptWallet(const string& strWalletPassphrase) bool CWallet::EncryptWallet(const string& strWalletPassphrase)
{ {
CRITICAL_BLOCK(cs_KeyStore) if (IsCrypted())
CRITICAL_BLOCK(cs_vMasterKey) return false;
CRITICAL_BLOCK(cs_pwalletdbEncryption)
{
if (IsCrypted())
return false;
CKeyingMaterial vMasterKey; CKeyingMaterial vMasterKey;
RandAddSeedPerfmon(); RandAddSeedPerfmon();
vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
CMasterKey kMasterKey; CMasterKey kMasterKey;
RandAddSeedPerfmon(); RandAddSeedPerfmon();
kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE); kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE); RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter; CCrypter crypter;
int64 nStartTime = GetTimeMillis(); int64 nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod); crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime)); kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
nStartTime = GetTimeMillis(); nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod); crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2; kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
if (kMasterKey.nDeriveIterations < 25000) if (kMasterKey.nDeriveIterations < 25000)
kMasterKey.nDeriveIterations = 25000; kMasterKey.nDeriveIterations = 25000;
printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations); printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod)) if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
return false; return false;
if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey)) if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
return false; return false;
CRITICAL_BLOCK(cs_wallet)
{
mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
if (fFileBacked) if (fFileBacked)
{ {
@ -191,6 +188,7 @@ bool CWallet::EncryptWallet(const string& strWalletPassphrase)
Lock(); Lock();
} }
return true; 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. // 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 // 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. // 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) BOOST_FOREACH(const CTxIn& txin, tx.vin)
{ {
@ -222,7 +220,7 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx)
bool CWallet::AddToWallet(const CWalletTx& wtxIn) bool CWallet::AddToWallet(const CWalletTx& wtxIn)
{ {
uint256 hash = wtxIn.GetHash(); uint256 hash = wtxIn.GetHash();
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_wallet)
{ {
// Inserts only if not already there, returns tx inserted or tx found // 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)); pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
@ -290,18 +288,21 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
{ {
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();
bool fExisted = mapWallet.count(hash); CRITICAL_BLOCK(cs_wallet)
if (fExisted && !fUpdate) return false;
if (fExisted || IsMine(tx) || IsFromMe(tx))
{ {
CWalletTx wtx(this,tx); bool fExisted = mapWallet.count(hash);
// Get merkle branch if transaction was found in a block if (fExisted && !fUpdate) return false;
if (pblock) if (fExisted || IsMine(tx) || IsFromMe(tx))
wtx.SetMerkleBranch(pblock); {
return AddToWallet(wtx); CWalletTx wtx(this,tx);
// Get merkle branch if transaction was found in a block
if (pblock)
wtx.SetMerkleBranch(pblock);
return AddToWallet(wtx);
}
else
WalletUpdateSpent(tx);
} }
else
WalletUpdateSpent(tx);
return false; return false;
} }
@ -309,7 +310,7 @@ bool CWallet::EraseFromWallet(uint256 hash)
{ {
if (!fFileBacked) if (!fFileBacked)
return false; return false;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_wallet)
{ {
if (mapWallet.erase(hash)) if (mapWallet.erase(hash))
CWalletDB(strWalletFile).EraseTx(hash); CWalletDB(strWalletFile).EraseTx(hash);
@ -320,7 +321,7 @@ bool CWallet::EraseFromWallet(uint256 hash)
bool CWallet::IsMine(const CTxIn &txin) const 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); map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end()) if (mi != mapWallet.end())
@ -336,7 +337,7 @@ bool CWallet::IsMine(const CTxIn &txin) const
int64 CWallet::GetDebit(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); map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
if (mi != mapWallet.end()) if (mi != mapWallet.end())
@ -352,19 +353,6 @@ int64 CWallet::GetDebit(const CTxIn &txin) const
int64 CWalletTx::GetTxTime() const int64 CWalletTx::GetTxTime() const
{ {
if (!fTimeReceivedIsTxTime && hashBlock != 0)
{
// If we did not receive the transaction directly, we rely on the block's
// time to figure out when it happened. We use the median over a range
// of blocks to try to filter out inaccurate block times.
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
if (mi != mapBlockIndex.end())
{
CBlockIndex* pindex = (*mi).second;
if (pindex)
return pindex->GetMedianTime();
}
}
return nTimeReceived; return nTimeReceived;
} }
@ -372,7 +360,7 @@ int CWalletTx::GetRequestCount() const
{ {
// Returns -1 if it wasn't being tracked // Returns -1 if it wasn't being tracked
int nRequests = -1; int nRequests = -1;
CRITICAL_BLOCK(pwallet->cs_mapRequestCount) CRITICAL_BLOCK(pwallet->cs_wallet)
{ {
if (IsCoinBase()) if (IsCoinBase())
{ {
@ -478,7 +466,7 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i
nSent += s.second; nSent += s.second;
nFee = allFee; nFee = allFee;
} }
CRITICAL_BLOCK(pwallet->cs_mapAddressBook) CRITICAL_BLOCK(pwallet->cs_wallet)
{ {
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived) BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
{ {
@ -508,7 +496,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
vWorkQueue.push_back(txin.prevout.hash); vWorkQueue.push_back(txin.prevout.hash);
// This critsect is OK because txdb is already open // This critsect is OK because txdb is already open
CRITICAL_BLOCK(pwallet->cs_mapWallet) CRITICAL_BLOCK(pwallet->cs_wallet)
{ {
map<uint256, const CMerkleTx*> mapWalletPrev; map<uint256, const CMerkleTx*> mapWalletPrev;
set<uint256> setAlreadyDone; set<uint256> setAlreadyDone;
@ -564,7 +552,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
int ret = 0; int ret = 0;
CBlockIndex* pindex = pindexStart; CBlockIndex* pindex = pindexStart;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_wallet)
{ {
while (pindex) while (pindex)
{ {
@ -585,7 +573,7 @@ void CWallet::ReacceptWalletTransactions()
{ {
CTxDB txdb("r"); CTxDB txdb("r");
bool fRepeat = true; bool fRepeat = true;
while (fRepeat) CRITICAL_BLOCK(cs_mapWallet) while (fRepeat) CRITICAL_BLOCK(cs_wallet)
{ {
fRepeat = false; fRepeat = false;
vector<CDiskTxPos> vMissingTx; vector<CDiskTxPos> vMissingTx;
@ -688,7 +676,7 @@ void CWallet::ResendWalletTransactions()
// Rebroadcast any of our txes that aren't in a block yet // Rebroadcast any of our txes that aren't in a block yet
printf("ResendWalletTransactions()\n"); printf("ResendWalletTransactions()\n");
CTxDB txdb("r"); CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_wallet)
{ {
// Sort them in chronological order // Sort them in chronological order
multimap<unsigned int, CWalletTx*> mapSorted; multimap<unsigned int, CWalletTx*> mapSorted;
@ -722,7 +710,7 @@ void CWallet::ResendWalletTransactions()
int64 CWallet::GetBalance() const int64 CWallet::GetBalance() const
{ {
int64 nTotal = 0; int64 nTotal = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_wallet)
{ {
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{ {
@ -749,7 +737,7 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe
vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue; vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
int64 nTotalLower = 0; int64 nTotalLower = 0;
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_wallet)
{ {
vector<const CWalletTx*> vCoins; vector<const CWalletTx*> vCoins;
vCoins.reserve(mapWallet.size()); vCoins.reserve(mapWallet.size());
@ -907,10 +895,10 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CW
wtxNew.pwallet = this; wtxNew.pwallet = this;
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
{ {
// txdb must be opened before the mapWallet lock // txdb must be opened before the mapWallet lock
CTxDB txdb("r"); CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
{ {
nFeeRet = nTransactionFee; nFeeRet = nTransactionFee;
loop loop
@ -1021,9 +1009,9 @@ bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& w
bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
{ {
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
{ {
printf("CommitTransaction:\n%s", wtxNew.ToString().c_str()); 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 // 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 // duration of this scope. This is the only place where this optimization
@ -1053,8 +1041,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
} }
// Track how many getdata requests our transaction gets // Track how many getdata requests our transaction gets
CRITICAL_BLOCK(cs_mapRequestCount) mapRequestCount[wtxNew.GetHash()] = 0;
mapRequestCount[wtxNew.GetHash()] = 0;
// Broadcast // Broadcast
if (!wtxNew.AcceptToMemoryPool()) if (!wtxNew.AcceptToMemoryPool())
@ -1072,29 +1059,26 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
// requires cs_main lock
string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee) string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
{ {
CReserveKey reservekey(this); CReserveKey reservekey(this);
int64 nFeeRequired; int64 nFeeRequired;
CRITICAL_BLOCK(cs_vMasterKey)
if (IsLocked())
{ {
if (IsLocked()) string strError = _("Error: Wallet locked, unable to create transaction ");
{ printf("SendMoney() : %s", strError.c_str());
string strError = _("Error: Wallet locked, unable to create transaction "); return strError;
printf("SendMoney() : %s", strError.c_str()); }
return strError; if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
} {
if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) string strError;
{ if (nValue + nFeeRequired > GetBalance())
string strError; strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str());
if (nValue + nFeeRequired > GetBalance()) else
strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds "), FormatMoney(nFeeRequired).c_str()); strError = _("Error: Transaction creation failed ");
else printf("SendMoney() : %s", strError.c_str());
strError = _("Error: Transaction creation failed "); return strError;
printf("SendMoney() : %s", strError.c_str());
return strError;
}
} }
if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL)) if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
@ -1109,7 +1093,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) string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
{ {
// Check amount // Check amount
@ -1172,7 +1155,7 @@ bool CWallet::DelAddressBookName(const CBitcoinAddress& address)
void CWallet::PrintWallet(const CBlock& block) void CWallet::PrintWallet(const CBlock& block)
{ {
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_wallet)
{ {
if (mapWallet.count(block.vtx[0].GetHash())) if (mapWallet.count(block.vtx[0].GetHash()))
{ {
@ -1185,7 +1168,7 @@ void CWallet::PrintWallet(const CBlock& block)
bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
{ {
CRITICAL_BLOCK(cs_mapWallet) CRITICAL_BLOCK(cs_wallet)
{ {
map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx); map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
if (mi != mapWallet.end()) if (mi != mapWallet.end())
@ -1218,10 +1201,7 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
bool CWallet::TopUpKeyPool() bool CWallet::TopUpKeyPool()
{ {
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_wallet)
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool)
CRITICAL_BLOCK(cs_vMasterKey)
{ {
if (IsLocked()) if (IsLocked())
return false; return false;
@ -1248,9 +1228,7 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
{ {
nIndex = -1; nIndex = -1;
keypool.vchPubKey.clear(); keypool.vchPubKey.clear();
CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_wallet)
CRITICAL_BLOCK(cs_mapWallet)
CRITICAL_BLOCK(cs_setKeyPool)
{ {
if (!IsLocked()) if (!IsLocked())
TopUpKeyPool(); TopUpKeyPool();
@ -1278,10 +1256,7 @@ void CWallet::KeepKey(int64 nIndex)
if (fFileBacked) if (fFileBacked)
{ {
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(strWalletFile);
CRITICAL_BLOCK(cs_main) walletdb.ErasePool(nIndex);
{
walletdb.ErasePool(nIndex);
}
} }
printf("keypool keep %"PRI64d"\n", nIndex); printf("keypool keep %"PRI64d"\n", nIndex);
} }
@ -1289,7 +1264,7 @@ void CWallet::KeepKey(int64 nIndex)
void CWallet::ReturnKey(int64 nIndex) void CWallet::ReturnKey(int64 nIndex)
{ {
// Return to key pool // Return to key pool
CRITICAL_BLOCK(cs_setKeyPool) CRITICAL_BLOCK(cs_wallet)
setKeyPool.insert(nIndex); setKeyPool.insert(nIndex);
printf("keypool return %"PRI64d"\n", nIndex); printf("keypool return %"PRI64d"\n", nIndex);
} }

15
src/wallet.h

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

Loading…
Cancel
Save