Skip to content

Commit

Permalink
Transaction hash caching
Browse files Browse the repository at this point in the history
Use CBlock's vMerkleTree to cache transaction hashes, and pass them
along as argument in more function calls.
  • Loading branch information
alex authored and alex committed Jan 21, 2014
1 parent 4a1fde4 commit cdef376
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 27 deletions.
35 changes: 17 additions & 18 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ void static EraseFromWallets(uint256 hash)
}

// make sure all wallets know about the given transaction, in the given block
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fConnect)
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fConnect)
{
if (!fConnect)
{
Expand All @@ -145,7 +145,7 @@ void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate,
}

BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
pwallet->AddToWalletIfInvolvingMe(hash, tx, pblock, fUpdate);
}

// notify wallets about a new best chain
Expand Down Expand Up @@ -1351,10 +1351,8 @@ unsigned int CTransaction::GetP2SHSigOpCount(CCoinsView& inputs) const
return nSigOps;
}

bool CTransaction::UpdateCoins(CCoinsView &inputs, CTxUndo &txundo, int nHeight, unsigned int nTimeStamp) const
bool CTransaction::UpdateCoins(CCoinsView &inputs, CTxUndo &txundo, int nHeight, unsigned int nTimeStamp, const uint256 &txhash) const
{
uint256 hash = GetHash();

// mark inputs spent
if (!IsCoinBase()) {
BOOST_FOREACH(const CTxIn &txin, vin) {
Expand All @@ -1373,7 +1371,7 @@ bool CTransaction::UpdateCoins(CCoinsView &inputs, CTxUndo &txundo, int nHeight,
}

// add outputs
if (!inputs.SetCoins(hash, CCoins(*this, nHeight, nTimeStamp)))
if (!inputs.SetCoins(txhash, CCoins(*this, nHeight, nTimeStamp)))
return error("UpdateCoins() : cannot update output");

return true;
Expand Down Expand Up @@ -1653,8 +1651,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
bool fEnforceBIP30 = true;

if (fEnforceBIP30) {
BOOST_FOREACH(CTransaction& tx, vtx) {
uint256 hash = tx.GetHash();
for (unsigned int i=0; i<vtx.size(); i++) {
uint256 hash = GetTxHash(i);
CCoins coins;
if (view.GetCoins(hash, coins) && !coins.IsPruned())
return error("ConnectBlock() : tried to overwrite transaction");
Expand All @@ -1668,8 +1666,9 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck

int64 nFees = 0, nValueIn = 0, nValueOut = 0;
unsigned int nSigOps = 0;
BOOST_FOREACH(CTransaction& tx, vtx)
for (unsigned int i=0; i<vtx.size(); i++)
{
const CTransaction &tx = vtx[i];
nSigOps += tx.GetLegacySigOpCount();
if (nSigOps > MAX_BLOCK_SIGOPS)
return DoS(100, error("ConnectBlock() : too many sigops"));
Expand Down Expand Up @@ -1711,7 +1710,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
continue;

CTxUndo txundo;
if (!tx.UpdateCoins(view, txundo, pindex->nHeight, pindex->nTime))
if (!tx.UpdateCoins(view, txundo, pindex->nHeight, pindex->nTime, GetTxHash(i)))
return error("ConnectBlock() : UpdateInputs failed");
if (!tx.IsCoinBase())
blockundo.vtxundo.push_back(txundo);
Expand Down Expand Up @@ -1751,8 +1750,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
printf("ConnectBlock() : destroy=%s nFees=%"PRI64d"\n", FormatMoney(nFees).c_str(), nFees);

// Watch for transactions paying to me
BOOST_FOREACH(CTransaction& tx, vtx)
SyncWithWallets(tx, this, true);
for (unsigned int i=0; i<vtx.size(); i++)
SyncWithWallets(GetTxHash(i), vtx[i], this, true);

return true;
}
Expand Down Expand Up @@ -2053,7 +2052,7 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = vtx[0].GetHash();
hashPrevBestCoinBase = GetTxHash(0);
}

uiInterface.NotifyBlocksChanged();
Expand Down Expand Up @@ -2224,10 +2223,10 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) c

// Check for duplicate txids. This is caught by ConnectInputs(),
// but catching it earlier avoids a potential DoS attack:
BuildMerkleTree();
set<uint256> uniqueTx;
BOOST_FOREACH(const CTransaction& tx, vtx)
{
uniqueTx.insert(tx.GetHash());
for (unsigned int i=0; i<vtx.size(); i++) {
uniqueTx.insert(GetTxHash(i));
}
if (uniqueTx.size() != vtx.size())
return DoS(100, error("CheckBlock() : duplicate transaction"));
Expand Down Expand Up @@ -3551,7 +3550,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
bool fMissingInputs = false;
if (tx.AcceptToMemoryPool(true, &fMissingInputs))
{
SyncWithWallets(tx, NULL, true);
SyncWithWallets(inv.hash, tx, NULL, true);
RelayTransaction(tx, inv.hash);
mapAlreadyAskedFor.erase(inv);
vWorkQueue.push_back(inv.hash);
Expand All @@ -3572,7 +3571,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
if (orphanTx.AcceptToMemoryPool(true, &fMissingInputs2))
{
printf(" accepted orphan tx %s\n", orphanTxHash.ToString().substr(0,10).c_str());
SyncWithWallets(tx, NULL, true);
SyncWithWallets(inv.hash, tx, NULL, true);
RelayTransaction(orphanTx, orphanTxHash);
mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanTxHash));
vWorkQueue.push_back(orphanTxHash);
Expand Down
10 changes: 8 additions & 2 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class CCoinsView;

void RegisterWallet(CWallet* pwalletIn);
void UnregisterWallet(CWallet* pwalletIn);
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true);
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false, bool fConnect = true);
bool ProcessBlock(CNode* pfrom, CBlock* pblock);
bool CheckDiskSpace(uint64 nAdditionalBytes=0);
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
Expand Down Expand Up @@ -631,7 +631,7 @@ class CTransaction
bool CheckInputs(CCoinsView &view, enum CheckSig_mode csmode, bool fStrictPayToScriptHash=true, bool fStrictEncodings=true, CBlock *pblock=NULL) const;

// Apply the effects of this transaction on the UTXO set represented by view
bool UpdateCoins(CCoinsView &view, CTxUndo &txundo, int nHeight, unsigned int nBlockTime) const;
bool UpdateCoins(CCoinsView &view, CTxUndo &txundo, int nHeight, unsigned int nBlockTime, const uint256 &txhash) const;

// Context-independent validity checks
bool CheckTransaction() const;
Expand Down Expand Up @@ -1265,6 +1265,12 @@ class CBlock
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
}

const uint256 &GetTxHash(unsigned int nIndex) const {
assert(vMerkleTree.size() > 0); // BuildMerkleTree must have been called first
assert(nIndex < vtx.size());
return vMerkleTree[nIndex];
}

std::vector<uint256> GetMerkleBranch(int nIndex) const
{
if (vMerkleTree.empty())
Expand Down
6 changes: 4 additions & 2 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,9 +313,12 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
if (!tx.UpdateCoins(viewTemp, txundo, pindexPrev->nHeight+1, pblock->nTime))
continue;
*/

// push changes from the second layer cache to the first one
viewTemp.Flush();
*/
uint256 hash = tx.GetHash();

// Added
pblock->vtx.push_back(tx);
nBlockSize += nTxSize;
Expand All @@ -330,7 +333,6 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
}

// Add transactions that depend on this one to the priority queue
uint256 hash = tx.GetHash();
if (mapDependers.count(hash))
{
BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
Expand Down
2 changes: 1 addition & 1 deletion src/rpcrawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
// Not in block, but already in the memory pool; will drop
// through to re-relay it.
} else {
SyncWithWallets(tx, NULL, true);
SyncWithWallets(hashTx, tx, NULL, true);
}
RelayTransaction(tx, hashTx);

Expand Down
5 changes: 2 additions & 3 deletions src/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -520,9 +520,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
// 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 CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate, bool fFindBlock)
{
uint256 hash = tx.GetHash();
{
LOCK(cs_wallet);
bool fExisted = mapWallet.count(hash);
Expand Down Expand Up @@ -809,7 +808,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
block.ReadFromDisk(pindex, true);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
ret++;
}
pindex = pindex->pnext;
Expand Down
2 changes: 1 addition & 1 deletion src/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class CWallet : public CCryptoKeyStore

void MarkDirty();
bool AddToWallet(const CWalletTx& wtxIn);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false);
bool AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate = false, bool fFindBlock = false);
bool EraseFromWallet(uint256 hash);
void WalletUpdateSpent(const CTransaction& prevout);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
Expand Down

0 comments on commit cdef376

Please sign in to comment.