diff options
author | Gavin Andresen <gavinandresen@gmail.com> | 2011-04-05 19:34:06 -0400 |
---|---|---|
committer | Gavin Andresen <gavinandresen@gmail.com> | 2011-04-05 19:34:06 -0400 |
commit | 57b7fe4e6f4f49de0d11d107c24430cd71007c6b (patch) | |
tree | 8d0b8bee4251acda657dea89eb45caf44f58f888 | |
parent | a2b6c1930dee40b33c3395a60f73e7c4277775cc (diff) | |
parent | 6f074b71bb4c21e0a3ce059a64be1e9383538413 (diff) |
Merge branch 'deadlock-fixes' of https://github.com/jgarzik/bitcoin
-rw-r--r-- | db.cpp | 2 | ||||
-rw-r--r-- | main.cpp | 36 | ||||
-rw-r--r-- | rpc.cpp | 83 | ||||
-rw-r--r-- | ui.cpp | 31 |
4 files changed, 85 insertions, 67 deletions
@@ -668,8 +668,8 @@ bool CWalletDB::LoadWallet() #endif //// todo: shouldn't we catch exceptions and try to recover and continue? - CRITICAL_BLOCK(cs_mapKeys) CRITICAL_BLOCK(cs_mapWallet) + CRITICAL_BLOCK(cs_mapKeys) { // Get cursor Dbc* pcursor = GetCursor(); @@ -4046,35 +4046,35 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) +// requires cs_main lock string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee) { - CRITICAL_BLOCK(cs_main) + CReserveKey reservekey; + int64 nFeeRequired; + if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) { - CReserveKey reservekey; - int64 nFeeRequired; - if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired)) - { - string strError; - if (nValue + nFeeRequired > GetBalance()) - strError = strprintf(_("Error: This is an oversized transaction that requires a transaction fee of %s "), FormatMoney(nFeeRequired).c_str()); - else - strError = _("Error: Transaction creation failed "); - printf("SendMoney() : %s", strError.c_str()); - return strError; - } + string strError; + if (nValue + nFeeRequired > GetBalance()) + strError = strprintf(_("Error: This is an oversized transaction that requires a transaction fee of %s "), FormatMoney(nFeeRequired).c_str()); + else + strError = _("Error: Transaction creation failed "); + printf("SendMoney() : %s", strError.c_str()); + return strError; + } - if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL)) - return "ABORTED"; + if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL)) + return "ABORTED"; + + if (!CommitTransaction(wtxNew, reservekey)) + return _("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."); - if (!CommitTransaction(wtxNew, reservekey)) - return _("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."); - } MainFrameRepaint(); return ""; } +// requires cs_main lock string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee) { // Check amount @@ -315,46 +315,45 @@ Value getnewaddress(const Array& params, bool fHelp) } +// requires cs_main, cs_mapWallet locks string GetAccountAddress(string strAccount, bool bForceNew=false) { string strAddress; - CRITICAL_BLOCK(cs_mapWallet) - { - CWalletDB walletdb; - walletdb.TxnBegin(); + CWalletDB walletdb; + walletdb.TxnBegin(); - CAccount account; - walletdb.ReadAccount(strAccount, account); + CAccount account; + walletdb.ReadAccount(strAccount, account); - // Check if the current key has been used - if (!account.vchPubKey.empty()) - { - CScript scriptPubKey; - scriptPubKey.SetBitcoinAddress(account.vchPubKey); - for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); - it != mapWallet.end() && !account.vchPubKey.empty(); - ++it) - { - const CWalletTx& wtx = (*it).second; - foreach(const CTxOut& txout, wtx.vout) - if (txout.scriptPubKey == scriptPubKey) - account.vchPubKey.clear(); - } - } - - // Generate a new key - if (account.vchPubKey.empty() || bForceNew) + // Check if the current key has been used + if (!account.vchPubKey.empty()) + { + CScript scriptPubKey; + scriptPubKey.SetBitcoinAddress(account.vchPubKey); + for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); + it != mapWallet.end() && !account.vchPubKey.empty(); + ++it) { - account.vchPubKey = GetKeyFromKeyPool(); - string strAddress = PubKeyToAddress(account.vchPubKey); - SetAddressBookName(strAddress, strAccount); - walletdb.WriteAccount(strAccount, account); + const CWalletTx& wtx = (*it).second; + foreach(const CTxOut& txout, wtx.vout) + if (txout.scriptPubKey == scriptPubKey) + account.vchPubKey.clear(); } + } - walletdb.TxnCommit(); - strAddress = PubKeyToAddress(account.vchPubKey); + // Generate a new key + if (account.vchPubKey.empty() || bForceNew) + { + account.vchPubKey = GetKeyFromKeyPool(); + string strAddress = PubKeyToAddress(account.vchPubKey); + SetAddressBookName(strAddress, strAccount); + walletdb.WriteAccount(strAccount, account); } + + walletdb.TxnCommit(); + strAddress = PubKeyToAddress(account.vchPubKey); + return strAddress; } @@ -368,7 +367,15 @@ Value getaccountaddress(const Array& params, bool fHelp) // Parse the account first so we don't generate a key if there's an error string strAccount = AccountFromValue(params[0]); - return GetAccountAddress(strAccount); + Value ret; + + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_mapWallet) + { + ret = GetAccountAddress(strAccount); + } + + return ret; } @@ -392,6 +399,8 @@ 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(cs_mapWallet) CRITICAL_BLOCK(cs_mapAddressBook) { if (mapAddressBook.count(strAddress)) @@ -475,9 +484,13 @@ 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(); - string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); - if (strError != "") - throw JSONRPCError(-4, strError); + CRITICAL_BLOCK(cs_main) + { + string strError = SendMoneyToBitcoinAddress(strAddress, nAmount, wtx); + if (strError != "") + throw JSONRPCError(-4, strError); + } + return wtx.GetHash().GetHex(); } @@ -752,6 +765,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(cs_mapWallet) { // Check funds @@ -808,6 +822,7 @@ Value sendmany(const Array& params, bool fHelp) vecSend.push_back(make_pair(scriptPubKey, nAmount)); } + CRITICAL_BLOCK(cs_main) CRITICAL_BLOCK(cs_mapWallet) { // Check funds @@ -1934,20 +1934,23 @@ void CSendDialog::OnButtonSend(wxCommandEvent& event) if (fBitcoinAddress) { - // Send to bitcoin address - CScript scriptPubKey; - scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; - - string strError = SendMoney(scriptPubKey, nValue, wtx, true); - if (strError == "") - wxMessageBox(_("Payment sent "), _("Sending...")); - else if (strError == "ABORTED") - return; // leave send dialog open - else - { - wxMessageBox(strError + " ", _("Sending...")); - EndModal(false); - } + CRITICAL_BLOCK(cs_main) + { + // Send to bitcoin address + CScript scriptPubKey; + scriptPubKey << OP_DUP << OP_HASH160 << hash160 << OP_EQUALVERIFY << OP_CHECKSIG; + + string strError = SendMoney(scriptPubKey, nValue, wtx, true); + if (strError == "") + wxMessageBox(_("Payment sent "), _("Sending...")); + else if (strError == "ABORTED") + return; // leave send dialog open + else + { + wxMessageBox(strError + " ", _("Sending...")); + EndModal(false); + } + } } else { |