aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r--src/wallet.cpp97
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"))