aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r--src/wallet.cpp160
1 files changed, 133 insertions, 27 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp
index 9648f6f88d..823c96949f 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2013 The Bitcoin developers
+// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -18,6 +18,7 @@ using namespace std;
// Settings
int64_t nTransactionFee = 0;
+bool bSpendZeroConfChange = true;
//////////////////////////////////////////////////////////////////////////////
//
@@ -191,18 +192,6 @@ void CWallet::SetBestChain(const CBlockLocator& loc)
walletdb.WriteBestBlock(loc);
}
-// This class implements an addrIncoming entry that causes pre-0.4
-// clients to crash on startup if reading a private-key-encrypted wallet.
-class CCorruptAddress
-{
-public:
- IMPLEMENT_SERIALIZE
- (
- if (nType & SER_DISK)
- READWRITE(nVersion);
- )
-};
-
bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
{
AssertLockHeld(cs_wallet); // nWalletVersion
@@ -221,13 +210,6 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn,
if (fFileBacked)
{
CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
- if (nWalletVersion >= 40000)
- {
- // Versions prior to 0.4.0 did not support the "minversion" record.
- // Use a CCorruptAddress to make them crash instead.
- CCorruptAddress corruptAddress;
- pwalletdb->WriteSetting("addrIncoming", corruptAddress);
- }
if (nWalletVersion > 40000)
pwalletdb->WriteMinVersion(nWalletVersion);
if (!pwalletdbIn)
@@ -249,6 +231,82 @@ bool CWallet::SetMaxVersion(int nVersion)
return true;
}
+set<uint256> CWallet::GetConflicts(const uint256& txid) const
+{
+ set<uint256> result;
+ AssertLockHeld(cs_wallet);
+
+ std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid);
+ if (it == mapWallet.end())
+ return result;
+ const CWalletTx& wtx = it->second;
+
+ std::pair<TxConflicts::const_iterator, TxConflicts::const_iterator> range;
+
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ range = mapTxConflicts.equal_range(txin.prevout);
+ for (TxConflicts::const_iterator it = range.first; it != range.second; ++it)
+ result.insert(it->second);
+ }
+ return result;
+}
+
+void CWallet::SyncMetaData(pair<TxConflicts::iterator, TxConflicts::iterator> range)
+{
+ // We want all the wallet transactions in range to have the same metadata as
+ // the oldest (smallest nOrderPos).
+ // So: find smallest nOrderPos:
+
+ int nMinOrderPos = std::numeric_limits<int>::max();
+ const CWalletTx* copyFrom = NULL;
+ for (TxConflicts::iterator it = range.first; it != range.second; ++it)
+ {
+ const uint256& hash = it->second;
+ int n = mapWallet[hash].nOrderPos;
+ if (n < nMinOrderPos)
+ {
+ nMinOrderPos = n;
+ copyFrom = &mapWallet[hash];
+ }
+ }
+ // Now copy data from copyFrom to rest:
+ for (TxConflicts::iterator it = range.first; it != range.second; ++it)
+ {
+ const uint256& hash = it->second;
+ CWalletTx* copyTo = &mapWallet[hash];
+ if (copyFrom == copyTo) continue;
+ copyTo->mapValue = copyFrom->mapValue;
+ copyTo->vOrderForm = copyFrom->vOrderForm;
+ // fTimeReceivedIsTxTime not copied on purpose
+ // nTimeReceived not copied on purpose
+ copyTo->nTimeSmart = copyFrom->nTimeSmart;
+ copyTo->fFromMe = copyFrom->fFromMe;
+ copyTo->strFromAccount = copyFrom->strFromAccount;
+ // vfSpent not copied on purpose
+ // nOrderPos not copied on purpose
+ // cached members not copied on purpose
+ }
+}
+
+void CWallet::AddToConflicts(const uint256& wtxhash)
+{
+ assert(mapWallet.count(wtxhash));
+ CWalletTx& thisTx = mapWallet[wtxhash];
+ if (thisTx.IsCoinBase())
+ return;
+
+ BOOST_FOREACH(const CTxIn& txin, thisTx.vin)
+ {
+ mapTxConflicts.insert(make_pair(txin.prevout, wtxhash));
+
+ pair<TxConflicts::iterator, TxConflicts::iterator> range;
+ range = mapTxConflicts.equal_range(txin.prevout);
+ if (range.first != range.second)
+ SyncMetaData(range);
+ }
+}
+
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
if (IsCrypted())
@@ -403,9 +461,16 @@ void CWallet::MarkDirty()
}
}
-bool CWallet::AddToWallet(const CWalletTx& wtxIn)
+bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet)
{
uint256 hash = wtxIn.GetHash();
+
+ if (fFromLoadWallet)
+ {
+ mapWallet[hash] = wtxIn;
+ AddToConflicts(hash);
+ }
+ else
{
LOCK(cs_wallet);
// Inserts only if not already there, returns tx inserted or tx found
@@ -463,6 +528,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
wtxIn.GetHash().ToString(),
wtxIn.hashBlock.ToString());
}
+ AddToConflicts(hash);
}
bool fUpdated = false;
@@ -925,6 +991,18 @@ void CWalletTx::RelayWalletTransaction()
}
}
+set<uint256> CWalletTx::GetConflicts() const
+{
+ set<uint256> result;
+ if (pwallet != NULL)
+ {
+ uint256 myHash = GetHash();
+ result = pwallet->GetConflicts(myHash);
+ result.erase(myHash);
+ }
+ return result;
+}
+
void CWallet::ResendWalletTransactions()
{
// Do this infrequently and randomly to avoid giving away
@@ -982,7 +1060,7 @@ int64_t CWallet::GetBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (pcoin->IsConfirmed())
+ if (pcoin->IsTrusted())
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -998,7 +1076,7 @@ int64_t CWallet::GetUnconfirmedBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
+ if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -1033,17 +1111,21 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
if (!IsFinalTx(*pcoin))
continue;
- if (fOnlyConfirmed && !pcoin->IsConfirmed())
+ if (fOnlyConfirmed && !pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
continue;
+ int nDepth = pcoin->GetDepthInMainChain();
+ if (nDepth < 0)
+ continue;
+
for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) &&
!IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0 &&
(!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
- vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain()));
+ vCoins.push_back(COutput(pcoin, i, nDepth));
}
}
}
@@ -1211,7 +1293,7 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) ||
SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet));
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet)));
}
@@ -1515,6 +1597,30 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
}
+DBErrors CWallet::ZapWalletTx()
+{
+ if (!fFileBacked)
+ return DB_LOAD_OK;
+ DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this);
+ if (nZapWalletTxRet == DB_NEED_REWRITE)
+ {
+ if (CDB::Rewrite(strWalletFile, "\x04pool"))
+ {
+ LOCK(cs_wallet);
+ setKeyPool.clear();
+ // Note: can't top-up keypool here, because wallet is locked.
+ // User will be prompted to unlock wallet the next operation
+ // the requires a new key.
+ }
+ }
+
+ if (nZapWalletTxRet != DB_LOAD_OK)
+ return nZapWalletTxRet;
+
+ return DB_LOAD_OK;
+}
+
+
bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
{
AssertLockHeld(cs_wallet); // mapAddressBook
@@ -1728,7 +1834,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances()
{
CWalletTx *pcoin = &walletEntry.second;
- if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
+ if (!IsFinalTx(*pcoin) || !pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)