mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
Transaction hash caching
Use CBlock's vMerkleTree to cache transaction hashes, and pass them along as argument in more function calls. During initial block download, this results in every transaction's hash to be only computed once.
This commit is contained in:
parent
ae8bfd12da
commit
64dd46fd05
40
src/main.cpp
40
src/main.cpp
@ -111,10 +111,10 @@ void static EraseFromWallets(uint256 hash)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// make sure all wallets know about the given transaction, in the given block
|
// make sure all wallets know about the given transaction, in the given block
|
||||||
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
|
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock, bool fUpdate)
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered)
|
||||||
pwallet->AddToWalletIfInvolvingMe(tx, pblock, fUpdate);
|
pwallet->AddToWalletIfInvolvingMe(hash, tx, pblock, fUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify wallets about a new best chain
|
// notify wallets about a new best chain
|
||||||
@ -1197,10 +1197,8 @@ unsigned int CTransaction::GetP2SHSigOpCount(CCoinsView& inputs) const
|
|||||||
return nSigOps;
|
return nSigOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CTransaction::UpdateCoins(CCoinsView &inputs, CTxUndo &txundo, int nHeight) const
|
bool CTransaction::UpdateCoins(CCoinsView &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) const
|
||||||
{
|
{
|
||||||
uint256 hash = GetHash();
|
|
||||||
|
|
||||||
// mark inputs spent
|
// mark inputs spent
|
||||||
if (!IsCoinBase()) {
|
if (!IsCoinBase()) {
|
||||||
BOOST_FOREACH(const CTxIn &txin, vin) {
|
BOOST_FOREACH(const CTxIn &txin, vin) {
|
||||||
@ -1217,7 +1215,7 @@ bool CTransaction::UpdateCoins(CCoinsView &inputs, CTxUndo &txundo, int nHeight)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add outputs
|
// add outputs
|
||||||
if (!inputs.SetCoins(hash, CCoins(*this, nHeight)))
|
if (!inputs.SetCoins(txhash, CCoins(*this, nHeight)))
|
||||||
return error("UpdateCoins() : cannot update output");
|
return error("UpdateCoins() : cannot update output");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1467,8 +1465,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
|
|||||||
bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
|
bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
|
||||||
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
|
(pindex->nHeight==91880 && pindex->GetBlockHash() == uint256("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
|
||||||
if (fEnforceBIP30) {
|
if (fEnforceBIP30) {
|
||||||
BOOST_FOREACH(CTransaction& tx, vtx) {
|
for (unsigned int i=0; i<vtx.size(); i++) {
|
||||||
uint256 hash = tx.GetHash();
|
uint256 hash = GetTxHash(i);
|
||||||
CCoins coins;
|
CCoins coins;
|
||||||
if (view.GetCoins(hash, coins) && !coins.IsPruned())
|
if (view.GetCoins(hash, coins) && !coins.IsPruned())
|
||||||
return error("ConnectBlock() : tried to overwrite transaction");
|
return error("ConnectBlock() : tried to overwrite transaction");
|
||||||
@ -1483,8 +1481,10 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
|
|||||||
|
|
||||||
int64 nFees = 0;
|
int64 nFees = 0;
|
||||||
unsigned int nSigOps = 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();
|
nSigOps += tx.GetLegacySigOpCount();
|
||||||
if (nSigOps > MAX_BLOCK_SIGOPS)
|
if (nSigOps > MAX_BLOCK_SIGOPS)
|
||||||
return DoS(100, error("ConnectBlock() : too many sigops"));
|
return DoS(100, error("ConnectBlock() : too many sigops"));
|
||||||
@ -1511,7 +1511,7 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
|
|||||||
}
|
}
|
||||||
|
|
||||||
CTxUndo txundo;
|
CTxUndo txundo;
|
||||||
if (!tx.UpdateCoins(view, txundo, pindex->nHeight))
|
if (!tx.UpdateCoins(view, txundo, pindex->nHeight, GetTxHash(i)))
|
||||||
return error("ConnectBlock() : UpdateInputs failed");
|
return error("ConnectBlock() : UpdateInputs failed");
|
||||||
if (!tx.IsCoinBase())
|
if (!tx.IsCoinBase())
|
||||||
blockundo.vtxundo.push_back(txundo);
|
blockundo.vtxundo.push_back(txundo);
|
||||||
@ -1542,8 +1542,8 @@ bool CBlock::ConnectBlock(CBlockIndex* pindex, CCoinsView &view, bool fJustCheck
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Watch for transactions paying to me
|
// Watch for transactions paying to me
|
||||||
BOOST_FOREACH(CTransaction& tx, vtx)
|
for (unsigned int i=0; i<vtx.size(); i++)
|
||||||
SyncWithWallets(tx, this, true);
|
SyncWithWallets(GetTxHash(i), vtx[i], this, true);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1755,7 +1755,7 @@ bool CBlock::AddToBlockIndex(const CDiskBlockPos &pos)
|
|||||||
// Notify UI to display prev block's coinbase if it was ours
|
// Notify UI to display prev block's coinbase if it was ours
|
||||||
static uint256 hashPrevBestCoinBase;
|
static uint256 hashPrevBestCoinBase;
|
||||||
UpdatedTransaction(hashPrevBestCoinBase);
|
UpdatedTransaction(hashPrevBestCoinBase);
|
||||||
hashPrevBestCoinBase = vtx[0].GetHash();
|
hashPrevBestCoinBase = GetTxHash(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uiInterface.NotifyBlocksChanged();
|
uiInterface.NotifyBlocksChanged();
|
||||||
@ -1876,10 +1876,10 @@ bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot) const
|
|||||||
|
|
||||||
// Check for duplicate txids. This is caught by ConnectInputs(),
|
// Check for duplicate txids. This is caught by ConnectInputs(),
|
||||||
// but catching it earlier avoids a potential DoS attack:
|
// but catching it earlier avoids a potential DoS attack:
|
||||||
|
BuildMerkleTree();
|
||||||
set<uint256> uniqueTx;
|
set<uint256> uniqueTx;
|
||||||
BOOST_FOREACH(const CTransaction& tx, vtx)
|
for (unsigned int i=0; i<vtx.size(); i++) {
|
||||||
{
|
uniqueTx.insert(GetTxHash(i));
|
||||||
uniqueTx.insert(tx.GetHash());
|
|
||||||
}
|
}
|
||||||
if (uniqueTx.size() != vtx.size())
|
if (uniqueTx.size() != vtx.size())
|
||||||
return DoS(100, error("CheckBlock() : duplicate transaction"));
|
return DoS(100, error("CheckBlock() : duplicate transaction"));
|
||||||
@ -2914,7 +2914,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||||||
bool fMissingInputs = false;
|
bool fMissingInputs = false;
|
||||||
if (tx.AcceptToMemoryPool(true, &fMissingInputs))
|
if (tx.AcceptToMemoryPool(true, &fMissingInputs))
|
||||||
{
|
{
|
||||||
SyncWithWallets(tx, NULL, true);
|
SyncWithWallets(inv.hash, tx, NULL, true);
|
||||||
RelayMessage(inv, vMsg);
|
RelayMessage(inv, vMsg);
|
||||||
mapAlreadyAskedFor.erase(inv);
|
mapAlreadyAskedFor.erase(inv);
|
||||||
vWorkQueue.push_back(inv.hash);
|
vWorkQueue.push_back(inv.hash);
|
||||||
@ -2937,7 +2937,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||||||
if (tx.AcceptToMemoryPool(true, &fMissingInputs2))
|
if (tx.AcceptToMemoryPool(true, &fMissingInputs2))
|
||||||
{
|
{
|
||||||
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
|
printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
|
||||||
SyncWithWallets(tx, NULL, true);
|
SyncWithWallets(inv.hash, tx, NULL, true);
|
||||||
RelayMessage(inv, vMsg);
|
RelayMessage(inv, vMsg);
|
||||||
mapAlreadyAskedFor.erase(inv);
|
mapAlreadyAskedFor.erase(inv);
|
||||||
vWorkQueue.push_back(inv.hash);
|
vWorkQueue.push_back(inv.hash);
|
||||||
@ -3729,7 +3729,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
CTxUndo txundo;
|
CTxUndo txundo;
|
||||||
if (!tx.UpdateCoins(viewTemp, txundo, pindexPrev->nHeight+1))
|
uint256 hash = tx.GetHash();
|
||||||
|
if (!tx.UpdateCoins(viewTemp, txundo, pindexPrev->nHeight+1, hash))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// push changes from the second layer cache to the first one
|
// push changes from the second layer cache to the first one
|
||||||
@ -3749,7 +3750,6 @@ CBlock* CreateNewBlock(CReserveKey& reservekey)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add transactions that depend on this one to the priority queue
|
// Add transactions that depend on this one to the priority queue
|
||||||
uint256 hash = tx.GetHash();
|
|
||||||
if (mapDependers.count(hash))
|
if (mapDependers.count(hash))
|
||||||
{
|
{
|
||||||
BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
|
BOOST_FOREACH(COrphan* porphan, mapDependers[hash])
|
||||||
|
10
src/main.h
10
src/main.h
@ -91,7 +91,7 @@ class CCoinsView;
|
|||||||
|
|
||||||
void RegisterWallet(CWallet* pwalletIn);
|
void RegisterWallet(CWallet* pwalletIn);
|
||||||
void UnregisterWallet(CWallet* pwalletIn);
|
void UnregisterWallet(CWallet* pwalletIn);
|
||||||
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false);
|
void SyncWithWallets(const uint256 &hash, const CTransaction& tx, const CBlock* pblock = NULL, bool fUpdate = false);
|
||||||
bool ProcessBlock(CNode* pfrom, CBlock* pblock);
|
bool ProcessBlock(CNode* pfrom, CBlock* pblock);
|
||||||
bool CheckDiskSpace(uint64 nAdditionalBytes=0);
|
bool CheckDiskSpace(uint64 nAdditionalBytes=0);
|
||||||
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
|
FILE* OpenBlockFile(const CDiskBlockPos &pos, bool fReadOnly = false);
|
||||||
@ -577,7 +577,7 @@ public:
|
|||||||
bool CheckInputs(CCoinsView &view, enum CheckSig_mode csmode, bool fStrictPayToScriptHash=true, bool fStrictEncodings=true) const;
|
bool CheckInputs(CCoinsView &view, enum CheckSig_mode csmode, bool fStrictPayToScriptHash=true, bool fStrictEncodings=true) const;
|
||||||
|
|
||||||
// Apply the effects of this transaction on the UTXO set represented by view
|
// Apply the effects of this transaction on the UTXO set represented by view
|
||||||
bool UpdateCoins(CCoinsView &view, CTxUndo &txundo, int nHeight) const;
|
bool UpdateCoins(CCoinsView &view, CTxUndo &txundo, int nHeight, const uint256 &txhash) const;
|
||||||
|
|
||||||
// Context-independent validity checks
|
// Context-independent validity checks
|
||||||
bool CheckTransaction() const;
|
bool CheckTransaction() const;
|
||||||
@ -1111,6 +1111,12 @@ public:
|
|||||||
return (vMerkleTree.empty() ? 0 : vMerkleTree.back());
|
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
|
std::vector<uint256> GetMerkleBranch(int nIndex) const
|
||||||
{
|
{
|
||||||
if (vMerkleTree.empty())
|
if (vMerkleTree.empty())
|
||||||
|
@ -517,7 +517,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
|
|||||||
// Not in block, but already in the memory pool; will drop
|
// Not in block, but already in the memory pool; will drop
|
||||||
// through to re-relay it.
|
// through to re-relay it.
|
||||||
} else {
|
} else {
|
||||||
SyncWithWallets(tx, NULL, true);
|
SyncWithWallets(hashTx, tx, NULL, true);
|
||||||
}
|
}
|
||||||
RelayMessage(CInv(MSG_TX, hashTx), tx);
|
RelayMessage(CInv(MSG_TX, hashTx), tx);
|
||||||
|
|
||||||
|
@ -479,9 +479,8 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
|
|||||||
// Add a transaction to the wallet, or update it.
|
// 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.
|
// 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.
|
// 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);
|
LOCK(cs_wallet);
|
||||||
bool fExisted = mapWallet.count(hash);
|
bool fExisted = mapWallet.count(hash);
|
||||||
@ -756,7 +755,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
|||||||
block.ReadFromDisk(pindex, true);
|
block.ReadFromDisk(pindex, true);
|
||||||
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
BOOST_FOREACH(CTransaction& tx, block.vtx)
|
||||||
{
|
{
|
||||||
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
|
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
|
||||||
ret++;
|
ret++;
|
||||||
}
|
}
|
||||||
pindex = pindex->pnext;
|
pindex = pindex->pnext;
|
||||||
|
@ -162,7 +162,7 @@ public:
|
|||||||
|
|
||||||
void MarkDirty();
|
void MarkDirty();
|
||||||
bool AddToWallet(const CWalletTx& wtxIn);
|
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);
|
bool EraseFromWallet(uint256 hash);
|
||||||
void WalletUpdateSpent(const CTransaction& prevout);
|
void WalletUpdateSpent(const CTransaction& prevout);
|
||||||
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
|
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
|
||||||
|
Loading…
Reference in New Issue
Block a user