diff options
Diffstat (limited to 'src/wallet.cpp')
| -rw-r--r-- | src/wallet.cpp | 97 |
1 files changed, 73 insertions, 24 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp index ef0b442e1..daca7ac04 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -9,6 +9,7 @@ #include "checkpoints.h" #include "coincontrol.h" #include "net.h" +#include "timedata.h" #include <boost/algorithm/string/replace.hpp> #include <openssl/rand.h> @@ -128,6 +129,22 @@ bool CWallet::AddCScript(const CScript& redeemScript) return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript); } +bool CWallet::LoadCScript(const CScript& redeemScript) +{ + /* A sanity check was added in pull #3843 to avoid adding redeemScripts + * that never can be redeemed. However, old wallets may still contain + * these. Do not add them to the wallet and warn. */ + if (redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE) + { + std::string strAddr = CBitcoinAddress(redeemScript.GetID()).ToString(); + LogPrintf("%s: Warning: This wallet contains a redeemScript of size %i which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", + __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr); + return true; + } + + return CCryptoKeyStore::AddCScript(redeemScript); +} + bool CWallet::Unlock(const SecureString& strWalletPassphrase) { CCrypter crypter; @@ -239,7 +256,7 @@ bool CWallet::SetMaxVersion(int nVersion) return true; } -set<uint256> CWallet::GetConflicts(const uint256& txid) const +set<uint256> CWallet::GetConflicts(const uint256& txid, bool includeEquivalent) const { set<uint256> result; AssertLockHeld(cs_wallet); @@ -257,7 +274,8 @@ set<uint256> CWallet::GetConflicts(const uint256& txid) const continue; // No conflict if zero or one spends range = mapTxSpends.equal_range(txin.prevout); for (TxSpends::const_iterator it = range.first; it != range.second; ++it) - result.insert(it->second); + if (includeEquivalent || !wtx.IsEquivalentTo(mapWallet.at(it->second))) + result.insert(it->second); } return result; } @@ -286,6 +304,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range) const uint256& hash = it->second; CWalletTx* copyTo = &mapWallet[hash]; if (copyFrom == copyTo) continue; + if (!copyFrom->IsEquivalentTo(*copyTo)) continue; copyTo->mapValue = copyFrom->mapValue; copyTo->vOrderForm = copyFrom->vOrderForm; // fTimeReceivedIsTxTime not copied on purpose @@ -571,6 +590,28 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) // Notify UI of new or updated transaction NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED); + // Notifications for existing transactions that now have conflicts with this one + if (fInsertedNew) + { + BOOST_FOREACH(const uint256& conflictHash, wtxIn.GetConflicts(false)) + { + CWalletTx& txConflict = mapWallet[conflictHash]; + NotifyTransactionChanged(this, conflictHash, CT_UPDATED); //Updates UI table + if (IsFromMe(txConflict) || IsMine(txConflict)) + { + NotifyTransactionChanged(this, conflictHash, CT_GOT_CONFLICT); //Throws dialog + // external respend notify + std::string strCmd = GetArg("-respendnotify", ""); + if (!strCmd.empty()) + { + boost::replace_all(strCmd, "%s", wtxIn.GetHash().GetHex()); + boost::replace_all(strCmd, "%t", conflictHash.GetHex()); + boost::thread t(runCommand, strCmd); // thread runs free + } + } + } + } + // notify an external script when a wallet transaction comes in or is updated std::string strCmd = GetArg("-walletnotify", ""); @@ -587,13 +628,18 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) // Add a transaction to the wallet, or update it. // pblock is optional, but should be provided if the transaction is known to be in a block. // If fUpdate is true, existing transactions will be updated. -bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate) +bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate) { { AssertLockHeld(cs_wallet); - bool fExisted = mapWallet.count(hash); + bool fExisted = mapWallet.count(tx.GetHash()); if (fExisted && !fUpdate) return false; - if (fExisted || IsMine(tx) || IsFromMe(tx)) + + bool fIsConflicting = IsConflicting(tx); + if (fIsConflicting) + nConflictsReceived++; + + if (fExisted || IsMine(tx) || IsFromMe(tx) || fIsConflicting) { CWalletTx wtx(this,tx); // Get merkle branch if transaction was found in a block @@ -605,10 +651,10 @@ bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& return false; } -void CWallet::SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock) +void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock) { LOCK2(cs_main, cs_wallet); - if (!AddToWalletIfInvolvingMe(hash, tx, pblock, true)) + if (!AddToWalletIfInvolvingMe(tx, pblock, true)) return; // Not one of ours // If a transaction changes 'conflicted' state, that changes the balance @@ -854,7 +900,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) ReadBlockFromDisk(block, pindex); BOOST_FOREACH(CTransaction& tx, block.vtx) { - if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate)) + if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) ret++; } pindex = chainActive.Next(pindex); @@ -879,7 +925,7 @@ void CWallet::ReacceptWalletTransactions() int nDepth = wtx.GetDepthInMainChain(); - if (!wtx.IsCoinBase() && nDepth < 0) + if (!wtx.IsCoinBase() && nDepth < 0 && (IsMine(wtx) || IsFromMe(wtx))) { // Try to add to memory pool LOCK(mempool.cs); @@ -893,20 +939,19 @@ void CWalletTx::RelayWalletTransaction() if (!IsCoinBase()) { if (GetDepthInMainChain() == 0) { - uint256 hash = GetHash(); - LogPrintf("Relaying wtx %s\n", hash.ToString()); - RelayTransaction((CTransaction)*this, hash); + LogPrintf("Relaying wtx %s\n", GetHash().ToString()); + RelayTransaction((CTransaction)*this); } } } -set<uint256> CWalletTx::GetConflicts() const +set<uint256> CWalletTx::GetConflicts(bool includeEquivalent) const { set<uint256> result; if (pwallet != NULL) { uint256 myHash = GetHash(); - result = pwallet->GetConflicts(myHash); + result = pwallet->GetConflicts(myHash, includeEquivalent); result.erase(myHash); } return result; @@ -1012,7 +1057,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const vCoins.clear(); { - LOCK(cs_wallet); + LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const uint256& wtxid = it->first; @@ -1229,6 +1274,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, } wtxNew.BindWallet(this); + CMutableTransaction txNew; { LOCK2(cs_main, cs_wallet); @@ -1236,8 +1282,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, nFeeRet = payTxFee.GetFeePerK(); while (true) { - wtxNew.vin.clear(); - wtxNew.vout.clear(); + txNew.vin.clear(); + txNew.vout.clear(); wtxNew.fFromMe = true; int64_t nTotalValue = nValue + nFeeRet; @@ -1251,7 +1297,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, strFailReason = _("Transaction amount too small"); return false; } - wtxNew.vout.push_back(txout); + txNew.vout.push_back(txout); } // Choose coins to use @@ -1315,8 +1361,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, else { // Insert change txn at random position: - vector<CTxOut>::iterator position = wtxNew.vout.begin()+GetRandInt(wtxNew.vout.size()+1); - wtxNew.vout.insert(position, newTxOut); + vector<CTxOut>::iterator position = txNew.vout.begin()+GetRandInt(txNew.vout.size()+1); + txNew.vout.insert(position, newTxOut); } } else @@ -1324,17 +1370,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, // Fill vin BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) - wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second)); + txNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second)); // Sign int nIn = 0; BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) - if (!SignSignature(*this, *coin.first, wtxNew, nIn++)) + if (!SignSignature(*this, *coin.first, txNew, nIn++)) { strFailReason = _("Signing transaction failed"); return false; } + // Embed the constructed transaction data in wtxNew. + *static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew); + // Limit size unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); if (nBytes >= MAX_STANDARD_TX_SIZE) @@ -1495,11 +1544,11 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) } -DBErrors CWallet::ZapWalletTx() +DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx) { if (!fFileBacked) return DB_LOAD_OK; - DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this); + DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this, vWtx); if (nZapWalletTxRet == DB_NEED_REWRITE) { if (CDB::Rewrite(strWalletFile, "\x04pool")) |