|
|
@ -130,8 +130,8 @@ namespace { |
|
|
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
namespace { |
|
|
|
struct CMainSignals { |
|
|
|
struct CMainSignals { |
|
|
|
// Notifies listeners of updated transaction data (passing hash, transaction, and optionally the block it is found in.
|
|
|
|
// Notifies listeners of updated transaction data (transaction, and optionally the block it is found in.
|
|
|
|
boost::signals2::signal<void (const uint256 &, const CTransaction &, const CBlock *)> SyncTransaction; |
|
|
|
boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction; |
|
|
|
// Notifies listeners of an erased transaction (currently disabled, requires transaction replacement).
|
|
|
|
// Notifies listeners of an erased transaction (currently disabled, requires transaction replacement).
|
|
|
|
boost::signals2::signal<void (const uint256 &)> EraseTransaction; |
|
|
|
boost::signals2::signal<void (const uint256 &)> EraseTransaction; |
|
|
|
// Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible).
|
|
|
|
// Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible).
|
|
|
@ -146,7 +146,7 @@ struct CMainSignals { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void RegisterWallet(CWalletInterface* pwalletIn) { |
|
|
|
void RegisterWallet(CWalletInterface* pwalletIn) { |
|
|
|
g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3)); |
|
|
|
g_signals.SyncTransaction.connect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2)); |
|
|
|
g_signals.EraseTransaction.connect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); |
|
|
|
g_signals.EraseTransaction.connect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); |
|
|
|
g_signals.UpdatedTransaction.connect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); |
|
|
|
g_signals.UpdatedTransaction.connect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); |
|
|
|
g_signals.SetBestChain.connect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); |
|
|
|
g_signals.SetBestChain.connect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); |
|
|
@ -160,7 +160,7 @@ void UnregisterWallet(CWalletInterface* pwalletIn) { |
|
|
|
g_signals.SetBestChain.disconnect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); |
|
|
|
g_signals.SetBestChain.disconnect(boost::bind(&CWalletInterface::SetBestChain, pwalletIn, _1)); |
|
|
|
g_signals.UpdatedTransaction.disconnect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); |
|
|
|
g_signals.UpdatedTransaction.disconnect(boost::bind(&CWalletInterface::UpdatedTransaction, pwalletIn, _1)); |
|
|
|
g_signals.EraseTransaction.disconnect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); |
|
|
|
g_signals.EraseTransaction.disconnect(boost::bind(&CWalletInterface::EraseFromWallet, pwalletIn, _1)); |
|
|
|
g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2, _3)); |
|
|
|
g_signals.SyncTransaction.disconnect(boost::bind(&CWalletInterface::SyncTransaction, pwalletIn, _1, _2)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void UnregisterAllWallets() { |
|
|
|
void UnregisterAllWallets() { |
|
|
@ -172,8 +172,8 @@ void UnregisterAllWallets() { |
|
|
|
g_signals.SyncTransaction.disconnect_all_slots(); |
|
|
|
g_signals.SyncTransaction.disconnect_all_slots(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void SyncWithWallets(const uint256 &hash, const CTransaction &tx, const CBlock *pblock) { |
|
|
|
void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) { |
|
|
|
g_signals.SyncTransaction(hash, tx, pblock); |
|
|
|
g_signals.SyncTransaction(tx, pblock); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
@ -952,7 +952,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa |
|
|
|
pool.addUnchecked(hash, entry); |
|
|
|
pool.addUnchecked(hash, entry); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
g_signals.SyncTransaction(hash, tx, NULL); |
|
|
|
g_signals.SyncTransaction(tx, NULL); |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
@ -1479,7 +1479,7 @@ void UpdateTime(CBlockHeader& block, const CBlockIndex* pindexPrev) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight, const uint256 &txhash) |
|
|
|
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) |
|
|
|
{ |
|
|
|
{ |
|
|
|
bool ret; |
|
|
|
bool ret; |
|
|
|
// mark inputs spent
|
|
|
|
// mark inputs spent
|
|
|
@ -1494,7 +1494,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// add outputs
|
|
|
|
// add outputs
|
|
|
|
ret = inputs.SetCoins(txhash, CCoins(tx, nHeight)); |
|
|
|
ret = inputs.SetCoins(tx.GetHash(), CCoins(tx, nHeight)); |
|
|
|
assert(ret); |
|
|
|
assert(ret); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1767,8 +1767,8 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C |
|
|
|
!((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) || |
|
|
|
!((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) { |
|
|
|
for (unsigned int i = 0; i < block.vtx.size(); i++) { |
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) { |
|
|
|
uint256 hash = block.GetTxHash(i); |
|
|
|
const uint256& hash = tx.GetHash(); |
|
|
|
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) |
|
|
|
if (view.HaveCoins(hash) && !view.GetCoins(hash).IsPruned()) |
|
|
|
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"), |
|
|
|
return state.DoS(100, error("ConnectBlock() : tried to overwrite transaction"), |
|
|
|
REJECT_INVALID, "bad-txns-BIP30"); |
|
|
|
REJECT_INVALID, "bad-txns-BIP30"); |
|
|
@ -1829,11 +1829,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
CTxUndo txundo; |
|
|
|
CTxUndo txundo; |
|
|
|
UpdateCoins(tx, state, view, txundo, pindex->nHeight, block.GetTxHash(i)); |
|
|
|
UpdateCoins(tx, state, view, txundo, pindex->nHeight); |
|
|
|
if (!tx.IsCoinBase()) |
|
|
|
if (!tx.IsCoinBase()) |
|
|
|
blockundo.vtxundo.push_back(txundo); |
|
|
|
blockundo.vtxundo.push_back(txundo); |
|
|
|
|
|
|
|
|
|
|
|
vPos.push_back(std::make_pair(block.GetTxHash(i), pos)); |
|
|
|
vPos.push_back(std::make_pair(tx.GetHash(), pos)); |
|
|
|
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); |
|
|
|
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); |
|
|
|
} |
|
|
|
} |
|
|
|
int64_t nTime = GetTimeMicros() - nStart; |
|
|
|
int64_t nTime = GetTimeMicros() - nStart; |
|
|
@ -1892,13 +1892,13 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C |
|
|
|
assert(ret); |
|
|
|
assert(ret); |
|
|
|
|
|
|
|
|
|
|
|
// Watch for transactions paying to me
|
|
|
|
// Watch for transactions paying to me
|
|
|
|
for (unsigned int i = 0; i < block.vtx.size(); i++) |
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) |
|
|
|
g_signals.SyncTransaction(block.GetTxHash(i), block.vtx[i], &block); |
|
|
|
g_signals.SyncTransaction(tx, &block); |
|
|
|
|
|
|
|
|
|
|
|
// Watch for changes to the previous coinbase transaction.
|
|
|
|
// Watch for changes to the previous coinbase transaction.
|
|
|
|
static uint256 hashPrevBestCoinBase; |
|
|
|
static uint256 hashPrevBestCoinBase; |
|
|
|
g_signals.UpdatedTransaction(hashPrevBestCoinBase); |
|
|
|
g_signals.UpdatedTransaction(hashPrevBestCoinBase); |
|
|
|
hashPrevBestCoinBase = block.GetTxHash(0); |
|
|
|
hashPrevBestCoinBase = block.vtx[0].GetHash(); |
|
|
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
@ -1996,7 +1996,7 @@ bool static DisconnectTip(CValidationState &state) { |
|
|
|
// Let wallets know transactions went from 1-confirmed to
|
|
|
|
// Let wallets know transactions went from 1-confirmed to
|
|
|
|
// 0-confirmed or conflicted:
|
|
|
|
// 0-confirmed or conflicted:
|
|
|
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
|
|
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
|
|
|
SyncWithWallets(tx.GetHash(), tx, NULL); |
|
|
|
SyncWithWallets(tx, NULL); |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
@ -2036,11 +2036,11 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) { |
|
|
|
// Tell wallet about transactions that went from mempool
|
|
|
|
// Tell wallet about transactions that went from mempool
|
|
|
|
// to conflicted:
|
|
|
|
// to conflicted:
|
|
|
|
BOOST_FOREACH(const CTransaction &tx, txConflicted) { |
|
|
|
BOOST_FOREACH(const CTransaction &tx, txConflicted) { |
|
|
|
SyncWithWallets(tx.GetHash(), tx, NULL); |
|
|
|
SyncWithWallets(tx, NULL); |
|
|
|
} |
|
|
|
} |
|
|
|
// ... and about transactions that got confirmed:
|
|
|
|
// ... and about transactions that got confirmed:
|
|
|
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
|
|
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
|
|
|
SyncWithWallets(tx.GetHash(), tx, &block); |
|
|
|
SyncWithWallets(tx, &block); |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
@ -2381,16 +2381,11 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo |
|
|
|
if (!CheckTransaction(tx, state)) |
|
|
|
if (!CheckTransaction(tx, state)) |
|
|
|
return error("CheckBlock() : CheckTransaction failed"); |
|
|
|
return error("CheckBlock() : CheckTransaction failed"); |
|
|
|
|
|
|
|
|
|
|
|
// Build the merkle tree already. We need it anyway later, and it makes the
|
|
|
|
|
|
|
|
// block cache the transaction hashes, which means they don't need to be
|
|
|
|
|
|
|
|
// recalculated many times during this block's validation.
|
|
|
|
|
|
|
|
block.BuildMerkleTree(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 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:
|
|
|
|
set<uint256> uniqueTx; |
|
|
|
set<uint256> uniqueTx; |
|
|
|
for (unsigned int i = 0; i < block.vtx.size(); i++) { |
|
|
|
BOOST_FOREACH(const CTransaction &tx, block.vtx) { |
|
|
|
uniqueTx.insert(block.GetTxHash(i)); |
|
|
|
uniqueTx.insert(tx.GetHash()); |
|
|
|
} |
|
|
|
} |
|
|
|
if (uniqueTx.size() != block.vtx.size()) |
|
|
|
if (uniqueTx.size() != block.vtx.size()) |
|
|
|
return state.DoS(100, error("CheckBlock() : duplicate transaction"), |
|
|
|
return state.DoS(100, error("CheckBlock() : duplicate transaction"), |
|
|
@ -2406,7 +2401,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo |
|
|
|
REJECT_INVALID, "bad-blk-sigops", true); |
|
|
|
REJECT_INVALID, "bad-blk-sigops", true); |
|
|
|
|
|
|
|
|
|
|
|
// Check merkle root
|
|
|
|
// Check merkle root
|
|
|
|
if (fCheckMerkleRoot && block.hashMerkleRoot != block.vMerkleTree.back()) |
|
|
|
if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree()) |
|
|
|
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"), |
|
|
|
return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"), |
|
|
|
REJECT_INVALID, "bad-txnmrklroot", true); |
|
|
|
REJECT_INVALID, "bad-txnmrklroot", true); |
|
|
|
|
|
|
|
|
|
|
@ -2682,8 +2677,8 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter) |
|
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < block.vtx.size(); i++) |
|
|
|
for (unsigned int i = 0; i < block.vtx.size(); i++) |
|
|
|
{ |
|
|
|
{ |
|
|
|
uint256 hash = block.vtx[i].GetHash(); |
|
|
|
const uint256& hash = block.vtx[i].GetHash(); |
|
|
|
if (filter.IsRelevantAndUpdate(block.vtx[i], hash)) |
|
|
|
if (filter.IsRelevantAndUpdate(block.vtx[i])) |
|
|
|
{ |
|
|
|
{ |
|
|
|
vMatch.push_back(true); |
|
|
|
vMatch.push_back(true); |
|
|
|
vMatchedTxn.push_back(make_pair(i, hash)); |
|
|
|
vMatchedTxn.push_back(make_pair(i, hash)); |
|
|
@ -3832,7 +3827,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) |
|
|
|
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) |
|
|
|
if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
mempool.check(pcoinsTip); |
|
|
|
mempool.check(pcoinsTip); |
|
|
|
RelayTransaction(tx, inv.hash); |
|
|
|
RelayTransaction(tx); |
|
|
|
mapAlreadyAskedFor.erase(inv); |
|
|
|
mapAlreadyAskedFor.erase(inv); |
|
|
|
vWorkQueue.push_back(inv.hash); |
|
|
|
vWorkQueue.push_back(inv.hash); |
|
|
|
vEraseQueue.push_back(inv.hash); |
|
|
|
vEraseQueue.push_back(inv.hash); |
|
|
@ -3862,7 +3857,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) |
|
|
|
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) |
|
|
|
if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); |
|
|
|
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); |
|
|
|
RelayTransaction(orphanTx, orphanHash); |
|
|
|
RelayTransaction(orphanTx); |
|
|
|
mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash)); |
|
|
|
mapAlreadyAskedFor.erase(CInv(MSG_TX, orphanHash)); |
|
|
|
vWorkQueue.push_back(orphanHash); |
|
|
|
vWorkQueue.push_back(orphanHash); |
|
|
|
vEraseQueue.push_back(orphanHash); |
|
|
|
vEraseQueue.push_back(orphanHash); |
|
|
@ -3947,7 +3942,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) |
|
|
|
CTransaction tx; |
|
|
|
CTransaction tx; |
|
|
|
bool fInMemPool = mempool.lookup(hash, tx); |
|
|
|
bool fInMemPool = mempool.lookup(hash, tx); |
|
|
|
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
|
|
|
|
if (!fInMemPool) continue; // another thread removed since queryHashes, maybe...
|
|
|
|
if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx, hash)) || |
|
|
|
if ((pfrom->pfilter && pfrom->pfilter->IsRelevantAndUpdate(tx)) || |
|
|
|
(!pfrom->pfilter)) |
|
|
|
(!pfrom->pfilter)) |
|
|
|
vInv.push_back(inv); |
|
|
|
vInv.push_back(inv); |
|
|
|
if (vInv.size() == MAX_INV_SZ) { |
|
|
|
if (vInv.size() == MAX_INV_SZ) { |
|
|
|