Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 676 Lines • ▼ Show 20 Lines | static bool AcceptToMemoryPoolWorker( | ||||
const Config &config, CTxMemPool &pool, CValidationState &state, | const Config &config, CTxMemPool &pool, CValidationState &state, | ||||
const CTransactionRef &ptx, bool fLimitFree, bool *pfMissingInputs, | const CTransactionRef &ptx, bool fLimitFree, bool *pfMissingInputs, | ||||
int64_t nAcceptTime, std::list<CTransactionRef> *plTxnReplaced, | int64_t nAcceptTime, std::list<CTransactionRef> *plTxnReplaced, | ||||
bool fOverrideMempoolLimit, const Amount nAbsurdFee, | bool fOverrideMempoolLimit, const Amount nAbsurdFee, | ||||
std::vector<COutPoint> &coins_to_uncache) { | std::vector<COutPoint> &coins_to_uncache) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
const uint256 txid = tx.GetId(); | const uint256 txid = tx.GetHash(); | ||||
if (pfMissingInputs) { | if (pfMissingInputs) { | ||||
*pfMissingInputs = false; | *pfMissingInputs = false; | ||||
} | } | ||||
// Coinbase is only valid in a block, not as a loose transaction. | // Coinbase is only valid in a block, not as a loose transaction. | ||||
if (!CheckRegularTransaction(tx, state, true)) { | if (!CheckRegularTransaction(tx, state, true)) { | ||||
// state filled in by CheckRegularTransaction. | // state filled in by CheckRegularTransaction. | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 372 Lines • ▼ Show 20 Lines | if (fTxIndex) { | ||||
file >> header; | file >> header; | ||||
fseek(file.Get(), postx.nTxOffset, SEEK_CUR); | fseek(file.Get(), postx.nTxOffset, SEEK_CUR); | ||||
file >> txOut; | file >> txOut; | ||||
} catch (const std::exception &e) { | } catch (const std::exception &e) { | ||||
return error("%s: Deserialize or I/O error - %s", __func__, | return error("%s: Deserialize or I/O error - %s", __func__, | ||||
e.what()); | e.what()); | ||||
} | } | ||||
hashBlock = header.GetHash(); | hashBlock = header.GetHash(); | ||||
if (txOut->GetId() != txid) | if (txOut->GetHash() != txid) | ||||
return error("%s: txid mismatch", __func__); | return error("%s: txid mismatch", __func__); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
// use coin database to locate block that contains transaction, and scan it | // use coin database to locate block that contains transaction, and scan it | ||||
if (fAllowSlow) { | if (fAllowSlow) { | ||||
const Coin &coin = AccessByTxid(*pcoinsTip, txid); | const Coin &coin = AccessByTxid(*pcoinsTip, txid); | ||||
if (!coin.IsSpent()) { | if (!coin.IsSpent()) { | ||||
pindexSlow = chainActive[coin.GetHeight()]; | pindexSlow = chainActive[coin.GetHeight()]; | ||||
} | } | ||||
} | } | ||||
if (pindexSlow) { | if (pindexSlow) { | ||||
auto ¶ms = config.GetChainParams().GetConsensus(); | auto ¶ms = config.GetChainParams().GetConsensus(); | ||||
CBlock block; | CBlock block; | ||||
if (ReadBlockFromDisk(block, pindexSlow, params)) { | if (ReadBlockFromDisk(block, pindexSlow, params)) { | ||||
for (const auto &tx : block.vtx) { | for (const auto &tx : block.vtx) { | ||||
if (tx->GetId() == txid) { | if (tx->GetHash() == txid) { | ||||
txOut = tx; | txOut = tx; | ||||
hashBlock = pindexSlow->GetBlockHash(); | hashBlock = pindexSlow->GetBlockHash(); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 556 Lines • ▼ Show 20 Lines | if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) { | ||||
error("DisconnectBlock(): block and undo data inconsistent"); | error("DisconnectBlock(): block and undo data inconsistent"); | ||||
return DISCONNECT_FAILED; | return DISCONNECT_FAILED; | ||||
} | } | ||||
// Undo transactions in reverse order. | // Undo transactions in reverse order. | ||||
size_t i = block.vtx.size(); | size_t i = block.vtx.size(); | ||||
while (i-- > 0) { | while (i-- > 0) { | ||||
const CTransaction &tx = *(block.vtx[i]); | const CTransaction &tx = *(block.vtx[i]); | ||||
uint256 txid = tx.GetId(); | uint256 txid = tx.GetHash(); | ||||
// Check that all outputs are available and match the outputs in the | // Check that all outputs are available and match the outputs in the | ||||
// block itself exactly. | // block itself exactly. | ||||
for (size_t o = 0; o < tx.vout.size(); o++) { | for (size_t o = 0; o < tx.vout.size(); o++) { | ||||
if (tx.vout[o].scriptPubKey.IsUnspendable()) { | if (tx.vout[o].scriptPubKey.IsUnspendable()) { | ||||
continue; | continue; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 396 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < block.vtx.size(); i++) { | ||||
// consult the cache, though). | // consult the cache, though). | ||||
bool fCacheResults = fJustCheck; | bool fCacheResults = fJustCheck; | ||||
std::vector<CScriptCheck> vChecks; | std::vector<CScriptCheck> vChecks; | ||||
if (!CheckInputs(tx, state, view, fScriptChecks, flags, | if (!CheckInputs(tx, state, view, fScriptChecks, flags, | ||||
fCacheResults, fCacheResults, | fCacheResults, fCacheResults, | ||||
PrecomputedTransactionData(tx), &vChecks)) { | PrecomputedTransactionData(tx), &vChecks)) { | ||||
return error("ConnectBlock(): CheckInputs on %s failed with %s", | return error("ConnectBlock(): CheckInputs on %s failed with %s", | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetHash().ToString(), | ||||
FormatStateMessage(state)); | |||||
} | } | ||||
control.Add(vChecks); | control.Add(vChecks); | ||||
} | } | ||||
CTxUndo undoDummy; | CTxUndo undoDummy; | ||||
if (i > 0) { | if (i > 0) { | ||||
blockundo.vtxundo.push_back(CTxUndo()); | blockundo.vtxundo.push_back(CTxUndo()); | ||||
} | } | ||||
UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), | UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), | ||||
pindex->nHeight); | pindex->nHeight); | ||||
vPos.push_back(std::make_pair(tx.GetId(), 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 nTime3 = GetTimeMicros(); | int64_t nTime3 = GetTimeMicros(); | ||||
nTimeConnect += nTime3 - nTime2; | nTimeConnect += nTime3 - nTime2; | ||||
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, " | LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, " | ||||
"%.3fms/txin) [%.2fs]\n", | "%.3fms/txin) [%.2fs]\n", | ||||
(unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), | (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | static bool ConnectBlock(const Config &config, const CBlock &block, | ||||
int64_t nTime5 = GetTimeMicros(); | int64_t nTime5 = GetTimeMicros(); | ||||
nTimeIndex += nTime5 - nTime4; | nTimeIndex += nTime5 - nTime4; | ||||
LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", | LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", | ||||
0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); | 0.001 * (nTime5 - nTime4), nTimeIndex * 0.000001); | ||||
// Watch for changes to the previous coinbase transaction. | // Watch for changes to the previous coinbase transaction. | ||||
static uint256 hashPrevBestCoinBase; | static uint256 hashPrevBestCoinBase; | ||||
GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); | GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); | ||||
hashPrevBestCoinBase = block.vtx[0]->GetId(); | hashPrevBestCoinBase = block.vtx[0]->GetHash(); | ||||
int64_t nTime6 = GetTimeMicros(); | int64_t nTime6 = GetTimeMicros(); | ||||
nTimeCallbacks += nTime6 - nTime5; | nTimeCallbacks += nTime6 - nTime5; | ||||
LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", | LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", | ||||
0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001); | 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 282 Lines • ▼ Show 20 Lines | if (!fBare) { | ||||
for (const auto &it : block.vtx) { | for (const auto &it : block.vtx) { | ||||
const CTransaction &tx = *it; | const CTransaction &tx = *it; | ||||
// ignore validation errors in resurrected transactions | // ignore validation errors in resurrected transactions | ||||
CValidationState stateDummy; | CValidationState stateDummy; | ||||
if (tx.IsCoinBase() || | if (tx.IsCoinBase() || | ||||
!AcceptToMemoryPool(config, mempool, stateDummy, it, false, | !AcceptToMemoryPool(config, mempool, stateDummy, it, false, | ||||
nullptr, nullptr, true)) { | nullptr, nullptr, true)) { | ||||
mempool.removeRecursive(tx, MemPoolRemovalReason::REORG); | mempool.removeRecursive(tx, MemPoolRemovalReason::REORG); | ||||
} else if (mempool.exists(tx.GetId())) { | } else if (mempool.exists(tx.GetHash())) { | ||||
vHashUpdate.push_back(tx.GetId()); | vHashUpdate.push_back(tx.GetHash()); | ||||
} | } | ||||
} | } | ||||
// AcceptToMemoryPool/addUnchecked all assume that new mempool entries | // AcceptToMemoryPool/addUnchecked all assume that new mempool entries | ||||
// have no in-mempool children, which is generally not true when adding | // have no in-mempool children, which is generally not true when adding | ||||
// previously-confirmed transactions back to the mempool. | // previously-confirmed transactions back to the mempool. | ||||
// UpdateTransactionsFromBlock finds descendants of any transactions in | // UpdateTransactionsFromBlock finds descendants of any transactions in | ||||
// this block that were added back and cleans up the mempool state. | // this block that were added back and cleans up the mempool state. | ||||
mempool.UpdateTransactionsFromBlock(vHashUpdate); | mempool.UpdateTransactionsFromBlock(vHashUpdate); | ||||
▲ Show 20 Lines • Show All 779 Lines • ▼ Show 20 Lines | if (currentBlockSize > nMaxBlockSize) { | ||||
"size limits failed"); | "size limits failed"); | ||||
} | } | ||||
// And a valid coinbase. | // And a valid coinbase. | ||||
if (!CheckCoinbase(*block.vtx[0], state, false)) { | if (!CheckCoinbase(*block.vtx[0], state, false)) { | ||||
return state.Invalid(false, state.GetRejectCode(), | return state.Invalid(false, state.GetRejectCode(), | ||||
state.GetRejectReason(), | state.GetRejectReason(), | ||||
strprintf("Coinbase check failed (txid %s) %s", | strprintf("Coinbase check failed (txid %s) %s", | ||||
block.vtx[0]->GetId().ToString(), | block.vtx[0]->GetHash().ToString(), | ||||
state.GetDebugMessage())); | state.GetDebugMessage())); | ||||
} | } | ||||
// Keep track of the sigops count. | // Keep track of the sigops count. | ||||
uint64_t nSigOps = 0; | uint64_t nSigOps = 0; | ||||
auto nMaxSigOpsCount = GetMaxBlockSigOpsCount(currentBlockSize); | auto nMaxSigOpsCount = GetMaxBlockSigOpsCount(currentBlockSize); | ||||
// Check transactions | // Check transactions | ||||
Show All 21 Lines | while (true) { | ||||
// Check that the transaction is valid. because this check differs for | // Check that the transaction is valid. because this check differs for | ||||
// the coinbase, the loos is arranged such as this only runs after at | // the coinbase, the loos is arranged such as this only runs after at | ||||
// least one increment. | // least one increment. | ||||
tx = block.vtx[i].get(); | tx = block.vtx[i].get(); | ||||
if (!CheckRegularTransaction(*tx, state, false)) { | if (!CheckRegularTransaction(*tx, state, false)) { | ||||
return state.Invalid( | return state.Invalid( | ||||
false, state.GetRejectCode(), state.GetRejectReason(), | false, state.GetRejectCode(), state.GetRejectReason(), | ||||
strprintf("Transaction check failed (txid %s) %s", | strprintf("Transaction check failed (txid %s) %s", | ||||
tx->GetId().ToString(), state.GetDebugMessage())); | tx->GetHash().ToString(), state.GetDebugMessage())); | ||||
} | } | ||||
} | } | ||||
if (fCheckPOW && fCheckMerkleRoot) { | if (fCheckPOW && fCheckMerkleRoot) { | ||||
block.fChecked = true; | block.fChecked = true; | ||||
} | } | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 1,624 Lines • ▼ Show 20 Lines | try { | ||||
int64_t nTime; | int64_t nTime; | ||||
int64_t nFeeDelta; | int64_t nFeeDelta; | ||||
file >> tx; | file >> tx; | ||||
file >> nTime; | file >> nTime; | ||||
file >> nFeeDelta; | file >> nFeeDelta; | ||||
Amount amountdelta = nFeeDelta; | Amount amountdelta = nFeeDelta; | ||||
if (amountdelta != 0) { | if (amountdelta != 0) { | ||||
mempool.PrioritiseTransaction(tx->GetId(), | mempool.PrioritiseTransaction(tx->GetHash(), | ||||
tx->GetId().ToString(), | tx->GetHash().ToString(), | ||||
prioritydummy, amountdelta); | prioritydummy, amountdelta); | ||||
} | } | ||||
CValidationState state; | CValidationState state; | ||||
if (nTime + nExpiryTimeout > nNow) { | if (nTime + nExpiryTimeout > nNow) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
AcceptToMemoryPoolWithTime(config, mempool, state, tx, true, | AcceptToMemoryPoolWithTime(config, mempool, state, tx, true, | ||||
nullptr, nTime); | nullptr, nTime); | ||||
if (state.IsValid()) { | if (state.IsValid()) { | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | try { | ||||
uint64_t version = MEMPOOL_DUMP_VERSION; | uint64_t version = MEMPOOL_DUMP_VERSION; | ||||
file << version; | file << version; | ||||
file << (uint64_t)vinfo.size(); | file << (uint64_t)vinfo.size(); | ||||
for (const auto &i : vinfo) { | for (const auto &i : vinfo) { | ||||
file << *(i.tx); | file << *(i.tx); | ||||
file << (int64_t)i.nTime; | file << (int64_t)i.nTime; | ||||
file << (int64_t)i.nFeeDelta.GetSatoshis(); | file << (int64_t)i.nFeeDelta.GetSatoshis(); | ||||
mapDeltas.erase(i.tx->GetId()); | mapDeltas.erase(i.tx->GetHash()); | ||||
} | } | ||||
file << mapDeltas; | file << mapDeltas; | ||||
FileCommit(file.Get()); | FileCommit(file.Get()); | ||||
file.fclose(); | file.fclose(); | ||||
RenameOver(GetDataDir() / "mempool.dat.new", | RenameOver(GetDataDir() / "mempool.dat.new", | ||||
GetDataDir() / "mempool.dat"); | GetDataDir() / "mempool.dat"); | ||||
int64_t last = GetTimeMicros(); | int64_t last = GetTimeMicros(); | ||||
Show All 36 Lines |