Skip to content

Commit

Permalink
ReacceptWalletTransactions bugfix
Browse files Browse the repository at this point in the history
Fix two bugs that can happen if you copy your wallet to another machine
and perform transactions on both.

First, ReacceptWalletTransactions would notice if the other wallet spent coins, and
would correctly mark the receiving transaction spent.  However, it did not add the spending
transaction to the wallet.  Now it does.

Second, account balances could get out of sync with 'getbalance' because coins received
by the other copy of the wallet were not necessarily detected.  Now ReacceptWalletTransactions
will scan the entire blockchain for transactions that should be in the wallet if it runs
across a 'spent in the other wallet' transaction.

Finally, there was a small bug in the accounts getbalance code-- generated coins with between
100 and 119 confirmations were not being counted in the balance of account "".
  • Loading branch information
gavinandresen committed Jan 19, 2011
1 parent c9f70b3 commit 1d23c74
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 7 deletions.
73 changes: 66 additions & 7 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,19 @@ bool AddToWalletIfMine(const CTransaction& tx, const CBlock* pblock)
return true;
}

bool AddToWalletIfFromMe(const CTransaction& tx, const CBlock* pblock)
{
if (tx.IsFromMe() || mapWallet.count(tx.GetHash()))
{
CWalletTx wtx(tx);
// Get merkle branch if transaction was found in a block
if (pblock)
wtx.SetMerkleBranch(pblock);
return AddToWallet(wtx);
}
return true;
}

bool EraseFromWallet(uint256 hash)
{
CRITICAL_BLOCK(cs_mapWallet)
Expand Down Expand Up @@ -404,7 +417,7 @@ void CWalletTx::GetAmounts(int64& nGenerated, list<pair<string, int64> >& listRe

if (IsCoinBase())
{
if (GetBlocksToMaturity() == 0)
if (GetDepthInMainChain() >= COINBASE_MATURITY)
nGenerated = GetCredit();
return;
}
Expand Down Expand Up @@ -849,11 +862,50 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs)
return false;
}

int ScanForWalletTransactions(CBlockIndex* pindexStart)
{
int ret = 0;

CBlockIndex* pindex = pindexStart;
CRITICAL_BLOCK(cs_mapWallet)
{
while (pindex)
{
CBlock block;
block.ReadFromDisk(pindex, true);
foreach(CTransaction& tx, block.vtx)
{
uint256 hash = tx.GetHash();
if (mapWallet.count(hash)) continue;
AddToWalletIfMine(tx, &block);
if (mapWallet.count(hash))
{
++ret;
printf("Added missing RECEIVE %s\n", hash.ToString().c_str());
continue;
}
AddToWalletIfFromMe(tx, &block);
if (mapWallet.count(hash))
{
++ret;
printf("Added missing SEND %s\n", hash.ToString().c_str());
continue;
}
}
pindex = pindex->pnext;
}
}
return ret;
}

void ReacceptWalletTransactions()
{
CTxDB txdb("r");
CRITICAL_BLOCK(cs_mapWallet)
bool fRepeat = true;
while (fRepeat) CRITICAL_BLOCK(cs_mapWallet)
{
fRepeat = false;
vector<CDiskTxPos> vMissingTx;
foreach(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{
CWalletTx& wtx = item.second;
Expand All @@ -875,12 +927,15 @@ void ReacceptWalletTransactions()
{
if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine())
{
printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
wtx.fSpent = true;
wtx.WriteToDisk();
break;
vMissingTx.push_back(txindex.vSpent[i]);
}
}
if (wtx.fSpent)
{
printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
wtx.WriteToDisk();
}
}
}
else
Expand All @@ -890,6 +945,12 @@ void ReacceptWalletTransactions()
wtx.AcceptWalletTransaction(txdb, false);
}
}
if (!vMissingTx.empty())
{
// TODO: optimize this to scan just part of the block chain?
if (ScanForWalletTransactions(pindexGenesisBlock))
fRepeat = true; // Found missing transactions: re-do Reaccept.
}
}
}

Expand Down Expand Up @@ -1361,8 +1422,6 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex)
return true;
}



bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew)
{
printf("REORGANIZE\n");
Expand Down
1 change: 1 addition & 0 deletions main.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ bool AddKey(const CKey& key);
vector<unsigned char> GenerateNewKey();
bool AddToWallet(const CWalletTx& wtxIn);
void WalletUpdateSpent(const COutPoint& prevout);
int ScanForWalletTransactions(CBlockIndex* pindexStart);
void ReacceptWalletTransactions();
bool LoadBlockIndex(bool fAllowNew=true);
void PrintBlockTree();
Expand Down
24 changes: 24 additions & 0 deletions rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,30 @@ Value getbalance(const Array& params, bool fHelp)
if (params.size() == 0)
return ((double)GetBalance() / (double)COIN);

if (params[0].get_str() == "*") {
// Calculate total balance a different way from GetBalance()
// (GetBalance() sums up all unspent TxOuts)
// getbalance and getbalance '*' should always return the same number.
int64 nBalance = 0;
for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
int64 allGenerated, allFee;
allGenerated = allFee = 0;
string strSentAccount;
list<pair<string, int64> > listReceived;
list<pair<string, int64> > listSent;
wtx.GetAmounts(allGenerated, listReceived, listSent, allFee, strSentAccount);
foreach(const PAIRTYPE(string,int64)& r, listReceived)
nBalance += r.second;
foreach(const PAIRTYPE(string,int64)& r, listSent)
nBalance -= r.second;
nBalance -= allFee;
nBalance += allGenerated;
}
return (double)nBalance / (double)COIN;
}

string strAccount = AccountFromValue(params[0]);
int nMinDepth = 1;
if (params.size() > 1)
Expand Down

0 comments on commit 1d23c74

Please sign in to comment.