mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-18 06:00:43 +02:00
[validation] Add CValidationState subclasses
Split CValidationState into TxValidationState and BlockValidationState to store validation results for transactions and blocks respectively.
This commit is contained in:
parent
48cb468ce3
commit
a27a2957ed
@ -38,7 +38,7 @@ static void AssembleBlock(benchmark::State& state)
|
|||||||
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
|
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
|
||||||
|
|
||||||
for (const auto& txr : txs) {
|
for (const auto& txr : txs) {
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
bool ret{::AcceptToMemoryPool(::mempool, state, txr, nullptr /* pfMissingInputs */, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
|
bool ret{::AcceptToMemoryPool(::mempool, state, txr, nullptr /* pfMissingInputs */, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
|
||||||
assert(ret);
|
assert(ret);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ static void DeserializeAndCheckBlockTest(benchmark::State& state)
|
|||||||
bool rewound = stream.Rewind(benchmark::data::block413567.size());
|
bool rewound = stream.Rewind(benchmark::data::block413567.size());
|
||||||
assert(rewound);
|
assert(rewound);
|
||||||
|
|
||||||
CValidationState validationState;
|
BlockValidationState validationState;
|
||||||
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus());
|
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus());
|
||||||
assert(checked);
|
assert(checked);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ static void DuplicateInputs(benchmark::State& state)
|
|||||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||||
|
|
||||||
while (state.KeepRunning()) {
|
while (state.KeepRunning()) {
|
||||||
CValidationState cvstate{};
|
BlockValidationState cvstate{};
|
||||||
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
|
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
|
||||||
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
|
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
|
||||||
}
|
}
|
||||||
|
@ -197,13 +197,13 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
|
|||||||
if (vtx_missing.size() != tx_missing_offset)
|
if (vtx_missing.size() != tx_missing_offset)
|
||||||
return READ_STATUS_INVALID;
|
return READ_STATUS_INVALID;
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!CheckBlock(block, state, Params().GetConsensus())) {
|
if (!CheckBlock(block, state, Params().GetConsensus())) {
|
||||||
// TODO: We really want to just check merkle tree manually here,
|
// TODO: We really want to just check merkle tree manually here,
|
||||||
// but that is expensive, and CheckBlock caches a block's
|
// but that is expensive, and CheckBlock caches a block's
|
||||||
// "checked-status" (in the CBlock?). CBlock should be able to
|
// "checked-status" (in the CBlock?). CBlock should be able to
|
||||||
// check its own merkle root and cache that check.
|
// check its own merkle root and cache that check.
|
||||||
if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED)
|
if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED)
|
||||||
return READ_STATUS_FAILED; // Possible Short ID collision
|
return READ_STATUS_FAILED; // Possible Short ID collision
|
||||||
return READ_STATUS_CHECKBLOCK_FAILED;
|
return READ_STATUS_CHECKBLOCK_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -7,28 +7,28 @@
|
|||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <consensus/validation.h>
|
#include <consensus/validation.h>
|
||||||
|
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
|
||||||
{
|
{
|
||||||
// Basic checks that don't depend on any context
|
// Basic checks that don't depend on any context
|
||||||
if (tx.vin.empty())
|
if (tx.vin.empty())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vin-empty");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-vin-empty");
|
||||||
if (tx.vout.empty())
|
if (tx.vout.empty())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-empty");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-vout-empty");
|
||||||
// Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
|
// Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
|
||||||
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
|
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-oversize");
|
||||||
|
|
||||||
// Check for negative or overflow output values (see CVE-2010-5139)
|
// Check for negative or overflow output values (see CVE-2010-5139)
|
||||||
CAmount nValueOut = 0;
|
CAmount nValueOut = 0;
|
||||||
for (const auto& txout : tx.vout)
|
for (const auto& txout : tx.vout)
|
||||||
{
|
{
|
||||||
if (txout.nValue < 0)
|
if (txout.nValue < 0)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-negative");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-vout-negative");
|
||||||
if (txout.nValue > MAX_MONEY)
|
if (txout.nValue > MAX_MONEY)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-toolarge");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-vout-toolarge");
|
||||||
nValueOut += txout.nValue;
|
nValueOut += txout.nValue;
|
||||||
if (!MoneyRange(nValueOut))
|
if (!MoneyRange(nValueOut))
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-txouttotal-toolarge");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-txouttotal-toolarge");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate inputs (see CVE-2018-17144)
|
// Check for duplicate inputs (see CVE-2018-17144)
|
||||||
@ -39,19 +39,19 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
|
|||||||
std::set<COutPoint> vInOutPoints;
|
std::set<COutPoint> vInOutPoints;
|
||||||
for (const auto& txin : tx.vin) {
|
for (const auto& txin : tx.vin) {
|
||||||
if (!vInOutPoints.insert(txin.prevout).second)
|
if (!vInOutPoints.insert(txin.prevout).second)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-inputs-duplicate");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tx.IsCoinBase())
|
if (tx.IsCoinBase())
|
||||||
{
|
{
|
||||||
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
|
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-length");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-cb-length");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (const auto& txin : tx.vin)
|
for (const auto& txin : tx.vin)
|
||||||
if (txin.prevout.IsNull())
|
if (txin.prevout.IsNull())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-prevout-null");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-prevout-null");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
|
|
||||||
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
bool CheckTransaction(const CTransaction& tx, TxValidationState& state);
|
||||||
|
|
||||||
#endif // BITCOIN_CONSENSUS_TX_CHECK_H
|
#endif // BITCOIN_CONSENSUS_TX_CHECK_H
|
||||||
|
@ -156,11 +156,11 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
|
|||||||
return nSigOps;
|
return nSigOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
|
bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
|
||||||
{
|
{
|
||||||
// are the actual inputs available?
|
// are the actual inputs available?
|
||||||
if (!inputs.HaveInputs(tx)) {
|
if (!inputs.HaveInputs(tx)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent",
|
return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent",
|
||||||
strprintf("%s: inputs missing/spent", __func__));
|
strprintf("%s: inputs missing/spent", __func__));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,27 +172,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
|
|||||||
|
|
||||||
// If prev is coinbase, check that it's matured
|
// If prev is coinbase, check that it's matured
|
||||||
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
|
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase",
|
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase",
|
||||||
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
|
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for negative or overflow input values
|
// Check for negative or overflow input values
|
||||||
nValueIn += coin.out.nValue;
|
nValueIn += coin.out.nValue;
|
||||||
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
|
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputvalues-outofrange");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-inputvalues-outofrange");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CAmount value_out = tx.GetValueOut();
|
const CAmount value_out = tx.GetValueOut();
|
||||||
if (nValueIn < value_out) {
|
if (nValueIn < value_out) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-in-belowout",
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-in-belowout",
|
||||||
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
|
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tally transaction fees
|
// Tally transaction fees
|
||||||
const CAmount txfee_aux = nValueIn - value_out;
|
const CAmount txfee_aux = nValueIn - value_out;
|
||||||
if (!MoneyRange(txfee_aux)) {
|
if (!MoneyRange(txfee_aux)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-fee-outofrange");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-fee-outofrange");
|
||||||
}
|
}
|
||||||
|
|
||||||
txfee = txfee_aux;
|
txfee = txfee_aux;
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CCoinsViewCache;
|
class CCoinsViewCache;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
|
|
||||||
/** Transaction validation functions */
|
/** Transaction validation functions */
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ namespace Consensus {
|
|||||||
* @param[out] txfee Set to the transaction fee if successful.
|
* @param[out] txfee Set to the transaction fee if successful.
|
||||||
* Preconditions: tx.IsCoinBase() is false.
|
* Preconditions: tx.IsCoinBase() is false.
|
||||||
*/
|
*/
|
||||||
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
|
bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
|
||||||
} // namespace Consensus
|
} // namespace Consensus
|
||||||
|
|
||||||
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
|
/** Auxiliary functions for transaction validation (ideally should not be exposed) */
|
||||||
|
@ -12,13 +12,12 @@
|
|||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
|
|
||||||
/** A "reason" why something was invalid, suitable for determining whether the
|
/** A "reason" why a transaction was invalid, suitable for determining whether the
|
||||||
* provider of the object should be banned/ignored/disconnected/etc.
|
* provider of the transaction should be banned/ignored/disconnected/etc.
|
||||||
*/
|
*/
|
||||||
enum class ValidationInvalidReason {
|
enum class TxValidationResult {
|
||||||
// txn and blocks:
|
TX_RESULT_UNSET, //!< initial value. Tx has not yet been rejected
|
||||||
NONE, //!< not actually invalid
|
TX_CONSENSUS, //!< invalid by consensus rules
|
||||||
CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
|
|
||||||
/**
|
/**
|
||||||
* Invalid by a change to consensus rules more recent than SegWit.
|
* Invalid by a change to consensus rules more recent than SegWit.
|
||||||
* Currently unused as there are no such consensus rule changes, and any download
|
* Currently unused as there are no such consensus rule changes, and any download
|
||||||
@ -26,18 +25,14 @@ enum class ValidationInvalidReason {
|
|||||||
* so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
|
* so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
|
||||||
* is uninteresting.
|
* is uninteresting.
|
||||||
*/
|
*/
|
||||||
RECENT_CONSENSUS_CHANGE,
|
TX_RECENT_CONSENSUS_CHANGE,
|
||||||
// Only blocks (or headers):
|
|
||||||
CACHED_INVALID, //!< this object was cached as being invalid, but we don't know why
|
|
||||||
BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
|
|
||||||
BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
|
|
||||||
BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
|
|
||||||
BLOCK_INVALID_PREV, //!< A block this one builds on is invalid
|
|
||||||
BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
|
|
||||||
BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
|
|
||||||
// Only loose txn:
|
|
||||||
TX_NOT_STANDARD, //!< didn't meet our local policy rules
|
TX_NOT_STANDARD, //!< didn't meet our local policy rules
|
||||||
TX_MISSING_INPUTS, //!< a transaction was missing some of its inputs
|
/**
|
||||||
|
* transaction was missing some of its inputs
|
||||||
|
* TODO: ATMP uses fMissingInputs and a valid ValidationState to indicate missing inputs.
|
||||||
|
* Change ATMP to use TX_MISSING_INPUTS.
|
||||||
|
*/
|
||||||
|
TX_MISSING_INPUTS,
|
||||||
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
|
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
|
||||||
/**
|
/**
|
||||||
* Transaction might be missing a witness, have a witness prior to SegWit
|
* Transaction might be missing a witness, have a witness prior to SegWit
|
||||||
@ -48,57 +43,55 @@ enum class ValidationInvalidReason {
|
|||||||
/**
|
/**
|
||||||
* Tx already in mempool or conflicts with a tx in the chain
|
* Tx already in mempool or conflicts with a tx in the chain
|
||||||
* (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)
|
* (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)
|
||||||
* TODO: Currently this is only used if the transaction already exists in the mempool or on chain,
|
* Currently this is only used if the transaction already exists in the mempool or on chain.
|
||||||
* TODO: ATMP's fMissingInputs and a valid CValidationState being used to indicate missing inputs
|
|
||||||
*/
|
*/
|
||||||
TX_CONFLICT,
|
TX_CONFLICT,
|
||||||
TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/RBF/etc limits
|
TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/RBF/etc limits
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool IsTransactionReason(ValidationInvalidReason r)
|
/** A "reason" why a block was invalid, suitable for determining whether the
|
||||||
{
|
* provider of the block should be banned/ignored/disconnected/etc.
|
||||||
return r == ValidationInvalidReason::NONE ||
|
* These are much more granular than the rejection codes, which may be more
|
||||||
r == ValidationInvalidReason::CONSENSUS ||
|
* useful for some other use-cases.
|
||||||
r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
|
*/
|
||||||
r == ValidationInvalidReason::TX_NOT_STANDARD ||
|
enum class BlockValidationResult {
|
||||||
r == ValidationInvalidReason::TX_PREMATURE_SPEND ||
|
BLOCK_RESULT_UNSET, //!< initial value. Block has not yet been rejected
|
||||||
r == ValidationInvalidReason::TX_MISSING_INPUTS ||
|
BLOCK_CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
|
||||||
r == ValidationInvalidReason::TX_WITNESS_MUTATED ||
|
/**
|
||||||
r == ValidationInvalidReason::TX_CONFLICT ||
|
* Invalid by a change to consensus rules more recent than SegWit.
|
||||||
r == ValidationInvalidReason::TX_MEMPOOL_POLICY;
|
* Currently unused as there are no such consensus rule changes, and any download
|
||||||
}
|
* sources realistically need to support SegWit in order to provide useful data,
|
||||||
|
* so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
|
||||||
|
* is uninteresting.
|
||||||
|
*/
|
||||||
|
BLOCK_RECENT_CONSENSUS_CHANGE,
|
||||||
|
BLOCK_CACHED_INVALID, //!< this block was cached as being invalid and we didn't store the reason why
|
||||||
|
BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
|
||||||
|
BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
|
||||||
|
BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
|
||||||
|
BLOCK_INVALID_PREV, //!< A block this one builds on is invalid
|
||||||
|
BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
|
||||||
|
BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
|
||||||
|
};
|
||||||
|
|
||||||
inline bool IsBlockReason(ValidationInvalidReason r)
|
|
||||||
{
|
|
||||||
return r == ValidationInvalidReason::NONE ||
|
|
||||||
r == ValidationInvalidReason::CONSENSUS ||
|
|
||||||
r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
|
|
||||||
r == ValidationInvalidReason::CACHED_INVALID ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_INVALID_HEADER ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_MUTATED ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_MISSING_PREV ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_INVALID_PREV ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_TIME_FUTURE ||
|
|
||||||
r == ValidationInvalidReason::BLOCK_CHECKPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Capture information about block/transaction validation */
|
|
||||||
class CValidationState {
|
/** Base class for capturing information about block/transaction validation. This is subclassed
|
||||||
|
* by TxValidationState and BlockValidationState for validation information on transactions
|
||||||
|
* and blocks respectively. */
|
||||||
|
class ValidationState {
|
||||||
private:
|
private:
|
||||||
enum mode_state {
|
enum mode_state {
|
||||||
MODE_VALID, //!< everything ok
|
MODE_VALID, //!< everything ok
|
||||||
MODE_INVALID, //!< network rule violation (DoS value may be set)
|
MODE_INVALID, //!< network rule violation (DoS value may be set)
|
||||||
MODE_ERROR, //!< run-time error
|
MODE_ERROR, //!< run-time error
|
||||||
} mode;
|
} mode;
|
||||||
ValidationInvalidReason m_reason;
|
|
||||||
std::string strRejectReason;
|
std::string strRejectReason;
|
||||||
std::string strDebugMessage;
|
std::string strDebugMessage;
|
||||||
public:
|
protected:
|
||||||
CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE) {}
|
bool Invalid(bool ret = false,
|
||||||
bool Invalid(ValidationInvalidReason reasonIn, bool ret = false,
|
|
||||||
const std::string &strRejectReasonIn="",
|
const std::string &strRejectReasonIn="",
|
||||||
const std::string &strDebugMessageIn="") {
|
const std::string &strDebugMessageIn="") {
|
||||||
m_reason = reasonIn;
|
|
||||||
strRejectReason = strRejectReasonIn;
|
strRejectReason = strRejectReasonIn;
|
||||||
strDebugMessage = strDebugMessageIn;
|
strDebugMessage = strDebugMessageIn;
|
||||||
if (mode == MODE_ERROR)
|
if (mode == MODE_ERROR)
|
||||||
@ -106,6 +99,11 @@ public:
|
|||||||
mode = MODE_INVALID;
|
mode = MODE_INVALID;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
// ValidationState is abstract. Have a pure virtual destructor.
|
||||||
|
virtual ~ValidationState() = 0;
|
||||||
|
|
||||||
|
ValidationState() : mode(MODE_VALID) {}
|
||||||
bool Error(const std::string& strRejectReasonIn) {
|
bool Error(const std::string& strRejectReasonIn) {
|
||||||
if (mode == MODE_VALID)
|
if (mode == MODE_VALID)
|
||||||
strRejectReason = strRejectReasonIn;
|
strRejectReason = strRejectReasonIn;
|
||||||
@ -121,11 +119,38 @@ public:
|
|||||||
bool IsError() const {
|
bool IsError() const {
|
||||||
return mode == MODE_ERROR;
|
return mode == MODE_ERROR;
|
||||||
}
|
}
|
||||||
ValidationInvalidReason GetReason() const { return m_reason; }
|
|
||||||
std::string GetRejectReason() const { return strRejectReason; }
|
std::string GetRejectReason() const { return strRejectReason; }
|
||||||
std::string GetDebugMessage() const { return strDebugMessage; }
|
std::string GetDebugMessage() const { return strDebugMessage; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline ValidationState::~ValidationState() {};
|
||||||
|
|
||||||
|
class TxValidationState : public ValidationState {
|
||||||
|
private:
|
||||||
|
TxValidationResult m_result;
|
||||||
|
public:
|
||||||
|
bool Invalid(TxValidationResult result, bool ret = false,
|
||||||
|
const std::string &_strRejectReason="",
|
||||||
|
const std::string &_strDebugMessage="") {
|
||||||
|
m_result = result;
|
||||||
|
return ValidationState::Invalid(ret, _strRejectReason, _strDebugMessage);
|
||||||
|
}
|
||||||
|
TxValidationResult GetResult() const { return m_result; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class BlockValidationState : public ValidationState {
|
||||||
|
private:
|
||||||
|
BlockValidationResult m_result;
|
||||||
|
public:
|
||||||
|
bool Invalid(BlockValidationResult result, bool ret = false,
|
||||||
|
const std::string &_strRejectReason="",
|
||||||
|
const std::string &_strDebugMessage="") {
|
||||||
|
m_result = result;
|
||||||
|
return ValidationState::Invalid(ret, _strRejectReason, _strDebugMessage);
|
||||||
|
}
|
||||||
|
BlockValidationResult GetResult() const { return m_result; }
|
||||||
|
};
|
||||||
|
|
||||||
// These implement the weight = (stripped_size * 4) + witness_size formula,
|
// These implement the weight = (stripped_size * 4) + witness_size formula,
|
||||||
// using only serialization with and without witness data. As witness_size
|
// using only serialization with and without witness data. As witness_size
|
||||||
// is equal to total_size - stripped_size, this formula is identical to:
|
// is equal to total_size - stripped_size, this formula is identical to:
|
||||||
|
@ -712,7 +712,7 @@ static void ThreadImport(std::vector<fs::path> vImportFiles)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// scan for better chains in the block chain database, that are not yet connected in the active best chain
|
// scan for better chains in the block chain database, that are not yet connected in the active best chain
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!ActivateBestChain(state, chainparams)) {
|
if (!ActivateBestChain(state, chainparams)) {
|
||||||
LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
|
LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
|
||||||
StartShutdown();
|
StartShutdown();
|
||||||
|
@ -18,7 +18,6 @@ class CBlock;
|
|||||||
class CFeeRate;
|
class CFeeRate;
|
||||||
class CRPCCommand;
|
class CRPCCommand;
|
||||||
class CScheduler;
|
class CScheduler;
|
||||||
class CValidationState;
|
|
||||||
class Coin;
|
class Coin;
|
||||||
class uint256;
|
class uint256;
|
||||||
enum class RBFTransactionState;
|
enum class RBFTransactionState;
|
||||||
|
@ -162,7 +162,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
|
|||||||
pblock->nNonce = 0;
|
pblock->nNonce = 0;
|
||||||
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
|
pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
|
if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) {
|
||||||
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
|
throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state)));
|
||||||
}
|
}
|
||||||
|
@ -982,14 +982,12 @@ void Misbehaving(NodeId pnode, int howmuch, const std::string& message) EXCLUSIV
|
|||||||
* banning/disconnecting us. We use this to determine which unaccepted
|
* banning/disconnecting us. We use this to determine which unaccepted
|
||||||
* transactions from a whitelisted peer that we can safely relay.
|
* transactions from a whitelisted peer that we can safely relay.
|
||||||
*/
|
*/
|
||||||
static bool TxRelayMayResultInDisconnect(const CValidationState& state)
|
static bool TxRelayMayResultInDisconnect(const TxValidationState& state) {
|
||||||
{
|
return state.GetResult() == TxValidationResult::TX_CONSENSUS;
|
||||||
assert(IsTransactionReason(state.GetReason()));
|
|
||||||
return state.GetReason() == ValidationInvalidReason::CONSENSUS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Potentially ban a node based on the contents of a CValidationState object
|
* Potentially ban a node based on the contents of a BlockValidationState object
|
||||||
*
|
*
|
||||||
* @param[in] via_compact_block: this bool is passed in because net_processing should
|
* @param[in] via_compact_block: this bool is passed in because net_processing should
|
||||||
* punish peers differently depending on whether the data was provided in a compact
|
* punish peers differently depending on whether the data was provided in a compact
|
||||||
@ -997,23 +995,21 @@ static bool TxRelayMayResultInDisconnect(const CValidationState& state)
|
|||||||
* txs, the peer should not be punished. See BIP 152.
|
* txs, the peer should not be punished. See BIP 152.
|
||||||
*
|
*
|
||||||
* @return Returns true if the peer was punished (probably disconnected)
|
* @return Returns true if the peer was punished (probably disconnected)
|
||||||
*
|
|
||||||
* Changes here may need to be reflected in TxRelayMayResultInDisconnect().
|
|
||||||
*/
|
*/
|
||||||
static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool via_compact_block, const std::string& message = "") {
|
static bool MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state, bool via_compact_block, const std::string& message = "") {
|
||||||
switch (state.GetReason()) {
|
switch (state.GetResult()) {
|
||||||
case ValidationInvalidReason::NONE:
|
case BlockValidationResult::BLOCK_RESULT_UNSET:
|
||||||
break;
|
break;
|
||||||
// The node is providing invalid data:
|
// The node is providing invalid data:
|
||||||
case ValidationInvalidReason::CONSENSUS:
|
case BlockValidationResult::BLOCK_CONSENSUS:
|
||||||
case ValidationInvalidReason::BLOCK_MUTATED:
|
case BlockValidationResult::BLOCK_MUTATED:
|
||||||
if (!via_compact_block) {
|
if (!via_compact_block) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
Misbehaving(nodeid, 100, message);
|
Misbehaving(nodeid, 100, message);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ValidationInvalidReason::CACHED_INVALID:
|
case BlockValidationResult::BLOCK_CACHED_INVALID:
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CNodeState *node_state = State(nodeid);
|
CNodeState *node_state = State(nodeid);
|
||||||
@ -1029,30 +1025,24 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ValidationInvalidReason::BLOCK_INVALID_HEADER:
|
case BlockValidationResult::BLOCK_INVALID_HEADER:
|
||||||
case ValidationInvalidReason::BLOCK_CHECKPOINT:
|
case BlockValidationResult::BLOCK_CHECKPOINT:
|
||||||
case ValidationInvalidReason::BLOCK_INVALID_PREV:
|
case BlockValidationResult::BLOCK_INVALID_PREV:
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
Misbehaving(nodeid, 100, message);
|
Misbehaving(nodeid, 100, message);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
// Conflicting (but not necessarily invalid) data or different policy:
|
// Conflicting (but not necessarily invalid) data or different policy:
|
||||||
case ValidationInvalidReason::BLOCK_MISSING_PREV:
|
case BlockValidationResult::BLOCK_MISSING_PREV:
|
||||||
{
|
{
|
||||||
// TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
|
// TODO: Handle this much more gracefully (10 DoS points is super arbitrary)
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
Misbehaving(nodeid, 10, message);
|
Misbehaving(nodeid, 10, message);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
case ValidationInvalidReason::RECENT_CONSENSUS_CHANGE:
|
case BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE:
|
||||||
case ValidationInvalidReason::BLOCK_TIME_FUTURE:
|
case BlockValidationResult::BLOCK_TIME_FUTURE:
|
||||||
case ValidationInvalidReason::TX_NOT_STANDARD:
|
|
||||||
case ValidationInvalidReason::TX_MISSING_INPUTS:
|
|
||||||
case ValidationInvalidReason::TX_PREMATURE_SPEND:
|
|
||||||
case ValidationInvalidReason::TX_WITNESS_MUTATED:
|
|
||||||
case ValidationInvalidReason::TX_CONFLICT:
|
|
||||||
case ValidationInvalidReason::TX_MEMPOOL_POLICY:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (message != "") {
|
if (message != "") {
|
||||||
@ -1061,6 +1051,39 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Potentially ban a node based on the contents of a TxValidationState object
|
||||||
|
*
|
||||||
|
* @return Returns true if the peer was punished (probably disconnected)
|
||||||
|
*
|
||||||
|
* Changes here may need to be reflected in TxRelayMayResultInDisconnect().
|
||||||
|
*/
|
||||||
|
static bool MaybePunishNodeForTx(NodeId nodeid, const TxValidationState& state, const std::string& message = "") {
|
||||||
|
switch (state.GetResult()) {
|
||||||
|
case TxValidationResult::TX_RESULT_UNSET:
|
||||||
|
break;
|
||||||
|
// The node is providing invalid data:
|
||||||
|
case TxValidationResult::TX_CONSENSUS:
|
||||||
|
{
|
||||||
|
LOCK(cs_main);
|
||||||
|
Misbehaving(nodeid, 100, message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Conflicting (but not necessarily invalid) data or different policy:
|
||||||
|
case TxValidationResult::TX_RECENT_CONSENSUS_CHANGE:
|
||||||
|
case TxValidationResult::TX_NOT_STANDARD:
|
||||||
|
case TxValidationResult::TX_MISSING_INPUTS:
|
||||||
|
case TxValidationResult::TX_PREMATURE_SPEND:
|
||||||
|
case TxValidationResult::TX_WITNESS_MUTATED:
|
||||||
|
case TxValidationResult::TX_CONFLICT:
|
||||||
|
case TxValidationResult::TX_MEMPOOL_POLICY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (message != "") {
|
||||||
|
LogPrint(BCLog::NET, "peer=%d: %s\n", nodeid, message);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1229,7 +1252,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
|
|||||||
* Handle invalid block rejection and consequent peer banning, maintain which
|
* Handle invalid block rejection and consequent peer banning, maintain which
|
||||||
* peers announce compact blocks.
|
* peers announce compact blocks.
|
||||||
*/
|
*/
|
||||||
void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) {
|
void PeerLogicValidation::BlockChecked(const CBlock& block, const BlockValidationState& state) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
const uint256 hash(block.GetHash());
|
const uint256 hash(block.GetHash());
|
||||||
@ -1240,7 +1263,7 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
|
|||||||
if (state.IsInvalid() &&
|
if (state.IsInvalid() &&
|
||||||
it != mapBlockSource.end() &&
|
it != mapBlockSource.end() &&
|
||||||
State(it->second.first)) {
|
State(it->second.first)) {
|
||||||
MaybePunishNode(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
MaybePunishNodeForBlock(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
|
||||||
}
|
}
|
||||||
// Check that:
|
// Check that:
|
||||||
// 1. The block is valid
|
// 1. The block is valid
|
||||||
@ -1378,7 +1401,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
|
|||||||
}
|
}
|
||||||
} // release cs_main before calling ActivateBestChain
|
} // release cs_main before calling ActivateBestChain
|
||||||
if (need_activate_chain) {
|
if (need_activate_chain) {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!ActivateBestChain(state, Params(), a_recent_block)) {
|
if (!ActivateBestChain(state, Params(), a_recent_block)) {
|
||||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
@ -1674,11 +1697,11 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
CBlockHeader first_invalid_header;
|
CBlockHeader first_invalid_header;
|
||||||
if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
|
if (!ProcessNewBlockHeaders(headers, state, chainparams, &pindexLast, &first_invalid_header)) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
MaybePunishNode(pfrom->GetId(), state, via_compact_block, "invalid header received");
|
MaybePunishNodeForBlock(pfrom->GetId(), state, via_compact_block, "invalid header received");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1815,10 +1838,10 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
|
|||||||
const CTransaction& orphanTx = *porphanTx;
|
const CTransaction& orphanTx = *porphanTx;
|
||||||
NodeId fromPeer = orphan_it->second.fromPeer;
|
NodeId fromPeer = orphan_it->second.fromPeer;
|
||||||
bool fMissingInputs2 = false;
|
bool fMissingInputs2 = false;
|
||||||
// Use a new CValidationState because orphans come from different peers (and we call
|
// Use a new TxValidationState because orphans come from different peers (and we call
|
||||||
// MaybePunishNode based on the source peer from the orphan map, not based on the peer
|
// MaybePunishNodeForTx based on the source peer from the orphan map, not based on the peer
|
||||||
// that relayed the previous transaction).
|
// that relayed the previous transaction).
|
||||||
CValidationState orphan_state;
|
TxValidationState orphan_state;
|
||||||
|
|
||||||
if (setMisbehaving.count(fromPeer)) continue;
|
if (setMisbehaving.count(fromPeer)) continue;
|
||||||
if (AcceptToMemoryPool(mempool, orphan_state, porphanTx, &fMissingInputs2, &removed_txn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
if (AcceptToMemoryPool(mempool, orphan_state, porphanTx, &fMissingInputs2, &removed_txn, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||||
@ -1837,7 +1860,7 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
|
|||||||
} else if (!fMissingInputs2) {
|
} else if (!fMissingInputs2) {
|
||||||
if (orphan_state.IsInvalid()) {
|
if (orphan_state.IsInvalid()) {
|
||||||
// Punish peer that gave us an invalid orphan tx
|
// Punish peer that gave us an invalid orphan tx
|
||||||
if (MaybePunishNode(fromPeer, orphan_state, /*via_compact_block*/ false)) {
|
if (MaybePunishNodeForTx(fromPeer, orphan_state)) {
|
||||||
setMisbehaving.insert(fromPeer);
|
setMisbehaving.insert(fromPeer);
|
||||||
}
|
}
|
||||||
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
|
LogPrint(BCLog::MEMPOOL, " invalid orphan tx %s\n", orphanHash.ToString());
|
||||||
@ -1845,8 +1868,7 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
|
|||||||
// Has inputs but not accepted to mempool
|
// Has inputs but not accepted to mempool
|
||||||
// Probably non-standard or insufficient fee
|
// Probably non-standard or insufficient fee
|
||||||
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
|
LogPrint(BCLog::MEMPOOL, " removed orphan tx %s\n", orphanHash.ToString());
|
||||||
assert(IsTransactionReason(orphan_state.GetReason()));
|
if (!orphanTx.HasWitness() && orphan_state.GetResult() != TxValidationResult::TX_WITNESS_MUTATED) {
|
||||||
if (!orphanTx.HasWitness() && orphan_state.GetReason() != ValidationInvalidReason::TX_WITNESS_MUTATED) {
|
|
||||||
// Do not use rejection cache for witness transactions or
|
// Do not use rejection cache for witness transactions or
|
||||||
// witness-stripped transactions, as they can have been malleated.
|
// witness-stripped transactions, as they can have been malleated.
|
||||||
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
|
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
|
||||||
@ -2291,7 +2313,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||||||
LOCK(cs_most_recent_block);
|
LOCK(cs_most_recent_block);
|
||||||
a_recent_block = most_recent_block;
|
a_recent_block = most_recent_block;
|
||||||
}
|
}
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!ActivateBestChain(state, Params(), a_recent_block)) {
|
if (!ActivateBestChain(state, Params(), a_recent_block)) {
|
||||||
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
LogPrint(BCLog::NET, "failed to activate chain (%s)\n", FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
@ -2472,7 +2494,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||||||
LOCK2(cs_main, g_cs_orphans);
|
LOCK2(cs_main, g_cs_orphans);
|
||||||
|
|
||||||
bool fMissingInputs = false;
|
bool fMissingInputs = false;
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
|
|
||||||
CNodeState* nodestate = State(pfrom->GetId());
|
CNodeState* nodestate = State(pfrom->GetId());
|
||||||
nodestate->m_tx_download.m_tx_announced.erase(inv.hash);
|
nodestate->m_tx_download.m_tx_announced.erase(inv.hash);
|
||||||
@ -2537,8 +2559,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||||||
recentRejects->insert(tx.GetHash());
|
recentRejects->insert(tx.GetHash());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(IsTransactionReason(state.GetReason()));
|
if (!tx.HasWitness() && state.GetResult() != TxValidationResult::TX_WITNESS_MUTATED) {
|
||||||
if (!tx.HasWitness() && state.GetReason() != ValidationInvalidReason::TX_WITNESS_MUTATED) {
|
|
||||||
// Do not use rejection cache for witness transactions or
|
// Do not use rejection cache for witness transactions or
|
||||||
// witness-stripped transactions, as they can have been malleated.
|
// witness-stripped transactions, as they can have been malleated.
|
||||||
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
|
// See https://github.com/bitcoin/bitcoin/issues/8279 for details.
|
||||||
@ -2593,7 +2614,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||||||
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
|
LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
|
||||||
pfrom->GetId(),
|
pfrom->GetId(),
|
||||||
FormatStateMessage(state));
|
FormatStateMessage(state));
|
||||||
MaybePunishNode(pfrom->GetId(), state, /*via_compact_block*/ false);
|
MaybePunishNodeForTx(pfrom->GetId(), state);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2627,10 +2648,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CBlockIndex *pindex = nullptr;
|
const CBlockIndex *pindex = nullptr;
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
|
if (!ProcessNewBlockHeaders({cmpctblock.header}, state, chainparams, &pindex)) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
MaybePunishNode(pfrom->GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
|
MaybePunishNodeForBlock(pfrom->GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Overridden from CValidationInterface.
|
* Overridden from CValidationInterface.
|
||||||
*/
|
*/
|
||||||
void BlockChecked(const CBlock& block, const CValidationState& state) override;
|
void BlockChecked(const CBlock& block, const BlockValidationState& state) override;
|
||||||
/**
|
/**
|
||||||
* Overridden from CValidationInterface.
|
* Overridden from CValidationInterface.
|
||||||
*/
|
*/
|
||||||
|
@ -36,7 +36,7 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, std::string& err
|
|||||||
}
|
}
|
||||||
if (!mempool.exists(hashTx)) {
|
if (!mempool.exists(hashTx)) {
|
||||||
// Transaction is not already in the mempool. Submit it.
|
// Transaction is not already in the mempool. Submit it.
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
bool fMissingInputs;
|
bool fMissingInputs;
|
||||||
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
|
if (!AcceptToMemoryPool(mempool, state, std::move(tx), &fMissingInputs,
|
||||||
nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
|
nullptr /* plTxnReplaced */, false /* bypass_limits */, max_tx_fee)) {
|
||||||
|
@ -1470,7 +1470,7 @@ static UniValue preciousblock(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
PreciousBlock(state, Params(), pblockindex);
|
PreciousBlock(state, Params(), pblockindex);
|
||||||
|
|
||||||
if (!state.IsValid()) {
|
if (!state.IsValid()) {
|
||||||
@ -1495,7 +1495,7 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
|
|||||||
}.Check(request);
|
}.Check(request);
|
||||||
|
|
||||||
uint256 hash(ParseHashV(request.params[0], "blockhash"));
|
uint256 hash(ParseHashV(request.params[0], "blockhash"));
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
|
|
||||||
CBlockIndex* pblockindex;
|
CBlockIndex* pblockindex;
|
||||||
{
|
{
|
||||||
@ -1545,7 +1545,7 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
|
|||||||
ResetBlockFailureFlags(pblockindex);
|
ResetBlockFailureFlags(pblockindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
ActivateBestChain(state, Params());
|
ActivateBestChain(state, Params());
|
||||||
|
|
||||||
if (!state.IsValid()) {
|
if (!state.IsValid()) {
|
||||||
|
@ -252,7 +252,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
|
|||||||
|
|
||||||
|
|
||||||
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
|
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
|
||||||
static UniValue BIP22ValidationResult(const CValidationState& state)
|
static UniValue BIP22ValidationResult(const BlockValidationState& state)
|
||||||
{
|
{
|
||||||
if (state.IsValid())
|
if (state.IsValid())
|
||||||
return NullUniValue;
|
return NullUniValue;
|
||||||
@ -401,7 +401,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
|
|||||||
// TestBlockValidity only supports blocks built on the current Tip
|
// TestBlockValidity only supports blocks built on the current Tip
|
||||||
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
|
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
|
||||||
return "inconclusive-not-best-prevblk";
|
return "inconclusive-not-best-prevblk";
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
TestBlockValidity(state, Params(), block, pindexPrev, false, true);
|
TestBlockValidity(state, Params(), block, pindexPrev, false, true);
|
||||||
return BIP22ValidationResult(state);
|
return BIP22ValidationResult(state);
|
||||||
}
|
}
|
||||||
@ -668,12 +668,12 @@ class submitblock_StateCatcher : public CValidationInterface
|
|||||||
public:
|
public:
|
||||||
uint256 hash;
|
uint256 hash;
|
||||||
bool found;
|
bool found;
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
|
|
||||||
explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
|
explicit submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
|
void BlockChecked(const CBlock& block, const BlockValidationState& stateIn) override {
|
||||||
if (block.GetHash() != hash)
|
if (block.GetHash() != hash)
|
||||||
return;
|
return;
|
||||||
found = true;
|
found = true;
|
||||||
@ -772,7 +772,7 @@ static UniValue submitheader(const JSONRPCRequest& request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
ProcessNewBlockHeaders({h}, state, Params(), /* ppindex */ nullptr, /* first_invalid */ nullptr);
|
ProcessNewBlockHeaders({h}, state, Params(), /* ppindex */ nullptr, /* first_invalid */ nullptr);
|
||||||
if (state.IsValid()) return NullUniValue;
|
if (state.IsValid()) return NullUniValue;
|
||||||
if (state.IsError()) {
|
if (state.IsError()) {
|
||||||
|
@ -893,7 +893,7 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
|
|||||||
UniValue result_0(UniValue::VOBJ);
|
UniValue result_0(UniValue::VOBJ);
|
||||||
result_0.pushKV("txid", tx_hash.GetHex());
|
result_0.pushKV("txid", tx_hash.GetHex());
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
bool missing_inputs;
|
bool missing_inputs;
|
||||||
bool test_accept_res;
|
bool test_accept_res;
|
||||||
{
|
{
|
||||||
|
@ -102,7 +102,7 @@ static bool BuildChain(const CBlockIndex* pindex, const CScript& coinbase_script
|
|||||||
block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
|
block = std::make_shared<CBlock>(CreateBlock(pindex, no_txns, coinbase_script_pub_key));
|
||||||
CBlockHeader header = block->GetBlockHeader();
|
CBlockHeader header = block->GetBlockHeader();
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) {
|
if (!ProcessNewBlockHeaders({header}, state, Params(), &pindex, nullptr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state_with_dupe_check;
|
TxValidationState state_with_dupe_check;
|
||||||
(void)CheckTransaction(tx, state_with_dupe_check);
|
(void)CheckTransaction(tx, state_with_dupe_check);
|
||||||
|
|
||||||
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
|
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
|
||||||
|
@ -95,7 +95,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
|
|||||||
throw std::runtime_error("LoadGenesisBlock failed.");
|
throw std::runtime_error("LoadGenesisBlock failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!ActivateBestChain(state, chainparams)) {
|
if (!ActivateBestChain(state, chainparams)) {
|
||||||
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
|
throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", FormatStateMessage(state)));
|
||||||
}
|
}
|
||||||
|
@ -193,7 +193,7 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
|
|||||||
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream stream(ParseHex(raw_tx), SER_NETWORK, PROTOCOL_VERSION);
|
||||||
stream >> tx;
|
stream >> tx;
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);
|
BOOST_CHECK_MESSAGE(CheckTransaction(*tx, state), strTest);
|
||||||
BOOST_CHECK(state.IsValid());
|
BOOST_CHECK(state.IsValid());
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
|
|||||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION);
|
||||||
CTransaction tx(deserialize, stream);
|
CTransaction tx(deserialize, stream);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
|
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest);
|
||||||
BOOST_CHECK(state.IsValid());
|
BOOST_CHECK(state.IsValid());
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
|
|||||||
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION );
|
CDataStream stream(ParseHex(transaction), SER_NETWORK, PROTOCOL_VERSION );
|
||||||
CTransaction tx(deserialize, stream);
|
CTransaction tx(deserialize, stream);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
fValid = CheckTransaction(tx, state) && state.IsValid();
|
fValid = CheckTransaction(tx, state) && state.IsValid();
|
||||||
|
|
||||||
PrecomputedTransactionData txdata(tx);
|
PrecomputedTransactionData txdata(tx);
|
||||||
@ -274,7 +274,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
|
|||||||
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
|
CDataStream stream(vch, SER_DISK, CLIENT_VERSION);
|
||||||
CMutableTransaction tx;
|
CMutableTransaction tx;
|
||||||
stream >> tx;
|
stream >> tx;
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid.");
|
BOOST_CHECK_MESSAGE(CheckTransaction(CTransaction(tx), state) && state.IsValid(), "Simple deserialized transaction should be valid.");
|
||||||
|
|
||||||
// Check that duplicate txins fail
|
// Check that duplicate txins fail
|
||||||
|
@ -30,7 +30,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
|||||||
|
|
||||||
BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
|
BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
|
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
|
|||||||
// Check that the validation state reflects the unsuccessful attempt.
|
// Check that the validation state reflects the unsuccessful attempt.
|
||||||
BOOST_CHECK(state.IsInvalid());
|
BOOST_CHECK(state.IsInvalid());
|
||||||
BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
|
BOOST_CHECK_EQUAL(state.GetRejectReason(), "coinbase");
|
||||||
BOOST_CHECK(state.GetReason() == ValidationInvalidReason::CONSENSUS);
|
BOOST_CHECK(state.GetResult() == TxValidationResult::TX_CONSENSUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include <boost/test/unit_test.hpp>
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
|
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
|
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ ToMemPool(const CMutableTransaction& tx)
|
|||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */,
|
return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), nullptr /* pfMissingInputs */,
|
||||||
nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */);
|
nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */);
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
|
|||||||
// If we add many more flags, this loop can get too expensive, but we can
|
// If we add many more flags, this loop can get too expensive, but we can
|
||||||
// rewrite in the future to randomly pick a set of flags to evaluate.
|
// rewrite in the future to randomly pick a set of flags to evaluate.
|
||||||
for (uint32_t test_flags=0; test_flags < (1U << 16); test_flags += 1) {
|
for (uint32_t test_flags=0; test_flags < (1U << 16); test_flags += 1) {
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
// Filter out incompatible flag choices
|
// Filter out incompatible flag choices
|
||||||
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
if ((test_flags & SCRIPT_VERIFY_CLEANSTACK)) {
|
||||||
// CLEANSTACK requires P2SH and WITNESS, see VerifyScript() in
|
// CLEANSTACK requires P2SH and WITNESS, see VerifyScript() in
|
||||||
@ -201,7 +201,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
PrecomputedTransactionData ptd_spend_tx(spend_tx);
|
PrecomputedTransactionData ptd_spend_tx(spend_tx);
|
||||||
|
|
||||||
BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
|
BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
|
||||||
@ -270,7 +270,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||||||
|
|
||||||
// Make it valid, and check again
|
// Make it valid, and check again
|
||||||
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
PrecomputedTransactionData txdata(invalid_with_cltv_tx);
|
PrecomputedTransactionData txdata(invalid_with_cltv_tx);
|
||||||
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, ::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
|
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, ::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
|
||||||
}
|
}
|
||||||
@ -298,7 +298,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||||||
|
|
||||||
// Make it valid, and check again
|
// Make it valid, and check again
|
||||||
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
PrecomputedTransactionData txdata(invalid_with_csv_tx);
|
PrecomputedTransactionData txdata(invalid_with_csv_tx);
|
||||||
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
|
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
|
||||||
}
|
}
|
||||||
@ -359,7 +359,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||||||
// Invalidate vin[1]
|
// Invalidate vin[1]
|
||||||
tx.vin[1].scriptWitness.SetNull();
|
tx.vin[1].scriptWitness.SetNull();
|
||||||
|
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
PrecomputedTransactionData txdata(tx);
|
PrecomputedTransactionData txdata(tx);
|
||||||
// This transaction is now invalid under segwit, because of the second input.
|
// This transaction is now invalid under segwit, because of the second input.
|
||||||
BOOST_CHECK(!CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
|
BOOST_CHECK(!CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
|
||||||
|
@ -151,7 +151,7 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ignored;
|
bool ignored;
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
std::vector<CBlockHeader> headers;
|
std::vector<CBlockHeader> headers;
|
||||||
std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
|
std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
|
|||||||
// Add the txs to the tx pool
|
// Add the txs to the tx pool
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
std::list<CTransactionRef> plTxnReplaced;
|
std::list<CTransactionRef> plTxnReplaced;
|
||||||
for (const auto& tx : txs) {
|
for (const auto& tx : txs) {
|
||||||
BOOST_REQUIRE(AcceptToMemoryPool(
|
BOOST_REQUIRE(AcceptToMemoryPool(
|
||||||
|
@ -591,9 +591,9 @@ void CTxMemPool::clear()
|
|||||||
|
|
||||||
static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t spendheight)
|
static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& mempoolDuplicate, const int64_t spendheight)
|
||||||
{
|
{
|
||||||
CValidationState state;
|
TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass
|
||||||
CAmount txfee = 0;
|
CAmount txfee = 0;
|
||||||
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, state, mempoolDuplicate, spendheight, txfee);
|
bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee);
|
||||||
assert(fCheckResult);
|
assert(fCheckResult);
|
||||||
UpdateCoins(tx, mempoolDuplicate, std::numeric_limits<int>::max());
|
UpdateCoins(tx, mempoolDuplicate, std::numeric_limits<int>::max());
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
#include <consensus/validation.h>
|
#include <consensus/validation.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
|
|
||||||
/** Convert CValidationState to a human-readable message for logging */
|
/** Convert ValidationState to a human-readable message for logging */
|
||||||
std::string FormatStateMessage(const CValidationState &state)
|
std::string FormatStateMessage(const ValidationState &state)
|
||||||
{
|
{
|
||||||
return strprintf("%s%s",
|
return strprintf("%s%s",
|
||||||
state.GetRejectReason(),
|
state.GetRejectReason(),
|
||||||
|
@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class CValidationState;
|
class ValidationState;
|
||||||
|
|
||||||
/** Convert CValidationState to a human-readable message for logging */
|
/** Convert ValidationState to a human-readable message for logging */
|
||||||
std::string FormatStateMessage(const CValidationState &state);
|
std::string FormatStateMessage(const ValidationState &state);
|
||||||
|
|
||||||
extern const std::string strMessageMagic;
|
extern const std::string strMessageMagic;
|
||||||
|
|
||||||
|
@ -181,7 +181,7 @@ std::unique_ptr<CBlockTreeDB> pblocktree;
|
|||||||
// See definition for documentation
|
// See definition for documentation
|
||||||
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
|
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
|
||||||
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
|
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
|
||||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
|
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
|
||||||
static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false);
|
static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false);
|
||||||
static FlatFileSeq BlockFileSeq();
|
static FlatFileSeq BlockFileSeq();
|
||||||
static FlatFileSeq UndoFileSeq();
|
static FlatFileSeq UndoFileSeq();
|
||||||
@ -363,7 +363,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool,
|
|||||||
auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin();
|
auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin();
|
||||||
while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
|
while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
|
||||||
// ignore validation errors in resurrected transactions
|
// ignore validation errors in resurrected transactions
|
||||||
CValidationState stateDummy;
|
TxValidationState stateDummy;
|
||||||
if (!fAddToMempool || (*it)->IsCoinBase() ||
|
if (!fAddToMempool || (*it)->IsCoinBase() ||
|
||||||
!AcceptToMemoryPool(mempool, stateDummy, *it, nullptr /* pfMissingInputs */,
|
!AcceptToMemoryPool(mempool, stateDummy, *it, nullptr /* pfMissingInputs */,
|
||||||
nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
nullptr /* plTxnReplaced */, true /* bypass_limits */, 0 /* nAbsurdFee */)) {
|
||||||
@ -391,7 +391,7 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool,
|
|||||||
|
|
||||||
// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
|
// Used to avoid mempool polluting consensus critical paths if CCoinsViewMempool
|
||||||
// were somehow broken and returning the wrong scriptPubKeys
|
// were somehow broken and returning the wrong scriptPubKeys
|
||||||
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool,
|
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool,
|
||||||
unsigned int flags, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
|
unsigned int flags, PrecomputedTransactionData& txdata) EXCLUSIVE_LOCKS_REQUIRED(cs_main) {
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
@ -441,7 +441,7 @@ public:
|
|||||||
// around easier.
|
// around easier.
|
||||||
struct ATMPArgs {
|
struct ATMPArgs {
|
||||||
const CChainParams& m_chainparams;
|
const CChainParams& m_chainparams;
|
||||||
CValidationState &m_state;
|
TxValidationState &m_state;
|
||||||
bool* m_missing_inputs;
|
bool* m_missing_inputs;
|
||||||
const int64_t m_accept_time;
|
const int64_t m_accept_time;
|
||||||
std::list<CTransactionRef>* m_replaced_transactions;
|
std::list<CTransactionRef>* m_replaced_transactions;
|
||||||
@ -502,15 +502,15 @@ private:
|
|||||||
bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
|
bool Finalize(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
|
||||||
|
|
||||||
// Compare a package's feerate against minimum allowed.
|
// Compare a package's feerate against minimum allowed.
|
||||||
bool CheckFeeRate(size_t package_size, CAmount package_fee, CValidationState& state)
|
bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state)
|
||||||
{
|
{
|
||||||
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
|
CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
|
||||||
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
|
if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
|
if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -537,7 +537,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
const uint256& hash = ws.m_hash;
|
const uint256& hash = ws.m_hash;
|
||||||
|
|
||||||
// Copy/alias what we need out of args
|
// Copy/alias what we need out of args
|
||||||
CValidationState &state = args.m_state;
|
TxValidationState &state = args.m_state;
|
||||||
bool* pfMissingInputs = args.m_missing_inputs;
|
bool* pfMissingInputs = args.m_missing_inputs;
|
||||||
const int64_t nAcceptTime = args.m_accept_time;
|
const int64_t nAcceptTime = args.m_accept_time;
|
||||||
const bool bypass_limits = args.m_bypass_limits;
|
const bool bypass_limits = args.m_bypass_limits;
|
||||||
@ -563,29 +563,29 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
|
|
||||||
// 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 (tx.IsCoinBase())
|
if (tx.IsCoinBase())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "coinbase");
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "coinbase");
|
||||||
|
|
||||||
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
|
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
|
||||||
std::string reason;
|
std::string reason;
|
||||||
if (fRequireStandard && !IsStandardTx(tx, reason))
|
if (fRequireStandard && !IsStandardTx(tx, reason))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, reason);
|
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, false, reason);
|
||||||
|
|
||||||
// Do not work on transactions that are too small.
|
// Do not work on transactions that are too small.
|
||||||
// A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes.
|
// A transaction with 1 segwit input and 1 P2WPHK output has non-witness size of 82 bytes.
|
||||||
// Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying
|
// Transactions smaller than this are not relayed to mitigate CVE-2017-12842 by not relaying
|
||||||
// 64-byte transactions.
|
// 64-byte transactions.
|
||||||
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE)
|
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) < MIN_STANDARD_TX_NONWITNESS_SIZE)
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "tx-size-small");
|
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, false, "tx-size-small");
|
||||||
|
|
||||||
// Only accept nLockTime-using transactions that can be mined in the next
|
// Only accept nLockTime-using transactions that can be mined in the next
|
||||||
// block; we don't want our mempool filled up with transactions that can't
|
// block; we don't want our mempool filled up with transactions that can't
|
||||||
// be mined yet.
|
// be mined yet.
|
||||||
if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
|
if (!CheckFinalTx(tx, STANDARD_LOCKTIME_VERIFY_FLAGS))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-final");
|
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, false, "non-final");
|
||||||
|
|
||||||
// is it already in the memory pool?
|
// is it already in the memory pool?
|
||||||
if (m_pool.exists(hash)) {
|
if (m_pool.exists(hash)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-in-mempool");
|
return state.Invalid(TxValidationResult::TX_CONFLICT, false, "txn-already-in-mempool");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for conflicts with in-memory transactions
|
// Check for conflicts with in-memory transactions
|
||||||
@ -617,7 +617,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fReplacementOptOut) {
|
if (fReplacementOptOut) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "txn-mempool-conflict");
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "txn-mempool-conflict");
|
||||||
}
|
}
|
||||||
|
|
||||||
setConflicts.insert(ptxConflicting->GetHash());
|
setConflicts.insert(ptxConflicting->GetHash());
|
||||||
@ -643,7 +643,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
for (size_t out = 0; out < tx.vout.size(); out++) {
|
for (size_t out = 0; out < tx.vout.size(); out++) {
|
||||||
// Optimistically just do efficient check of cache for outputs
|
// Optimistically just do efficient check of cache for outputs
|
||||||
if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) {
|
if (coins_cache.HaveCoinInCache(COutPoint(hash, out))) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, "txn-already-known");
|
return state.Invalid(TxValidationResult::TX_CONFLICT, false, "txn-already-known");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise assume this might be an orphan tx for which we just haven't seen parents yet
|
// Otherwise assume this might be an orphan tx for which we just haven't seen parents yet
|
||||||
@ -668,7 +668,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
|
// Must keep pool.cs for this unless we change CheckSequenceLocks to take a
|
||||||
// CoinsViewCache instead of create its own
|
// CoinsViewCache instead of create its own
|
||||||
if (!CheckSequenceLocks(m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
|
if (!CheckSequenceLocks(m_pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, &lp))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "non-BIP68-final");
|
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, false, "non-BIP68-final");
|
||||||
|
|
||||||
CAmount nFees = 0;
|
CAmount nFees = 0;
|
||||||
if (!Consensus::CheckTxInputs(tx, state, m_view, GetSpendHeight(m_view), nFees)) {
|
if (!Consensus::CheckTxInputs(tx, state, m_view, GetSpendHeight(m_view), nFees)) {
|
||||||
@ -677,11 +677,11 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
|
|
||||||
// Check for non-standard pay-to-script-hash in inputs
|
// Check for non-standard pay-to-script-hash in inputs
|
||||||
if (fRequireStandard && !AreInputsStandard(tx, m_view))
|
if (fRequireStandard && !AreInputsStandard(tx, m_view))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-nonstandard-inputs");
|
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, false, "bad-txns-nonstandard-inputs");
|
||||||
|
|
||||||
// Check for non-standard witness in P2WSH
|
// Check for non-standard witness in P2WSH
|
||||||
if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, m_view))
|
if (tx.HasWitness() && fRequireStandard && !IsWitnessStandard(tx, m_view))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_WITNESS_MUTATED, false, "bad-witness-nonstandard");
|
return state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, false, "bad-witness-nonstandard");
|
||||||
|
|
||||||
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
|
int64_t nSigOpsCost = GetTransactionSigOpCost(tx, m_view, STANDARD_SCRIPT_VERIFY_FLAGS);
|
||||||
|
|
||||||
@ -705,7 +705,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
unsigned int nSize = entry->GetTxSize();
|
unsigned int nSize = entry->GetTxSize();
|
||||||
|
|
||||||
if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
|
if (nSigOpsCost > MAX_STANDARD_TX_SIGOPS_COST)
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, "bad-txns-too-many-sigops",
|
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, false, "bad-txns-too-many-sigops",
|
||||||
strprintf("%d", nSigOpsCost));
|
strprintf("%d", nSigOpsCost));
|
||||||
|
|
||||||
// No transactions are allowed below minRelayTxFee except from disconnected
|
// No transactions are allowed below minRelayTxFee except from disconnected
|
||||||
@ -713,7 +713,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false;
|
if (!bypass_limits && !CheckFeeRate(nSize, nModifiedFees, state)) return false;
|
||||||
|
|
||||||
if (nAbsurdFee && nFees > nAbsurdFee)
|
if (nAbsurdFee && nFees > nAbsurdFee)
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false,
|
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, false,
|
||||||
"absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee));
|
"absurdly-high-fee", strprintf("%d > %d", nFees, nAbsurdFee));
|
||||||
|
|
||||||
const CTxMemPool::setEntries setIterConflicting = m_pool.GetIterSet(setConflicts);
|
const CTxMemPool::setEntries setIterConflicting = m_pool.GetIterSet(setConflicts);
|
||||||
@ -771,7 +771,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
// this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
|
// this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html
|
||||||
if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT ||
|
if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT ||
|
||||||
!m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) {
|
!m_pool.CalculateMemPoolAncestors(*entry, setAncestors, 2, m_limit_ancestor_size, m_limit_descendants + 1, m_limit_descendant_size + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "too-long-mempool-chain", errString);
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "too-long-mempool-chain", errString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,7 +784,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
const uint256 &hashAncestor = ancestorIt->GetTx().GetHash();
|
const uint256 &hashAncestor = ancestorIt->GetTx().GetHash();
|
||||||
if (setConflicts.count(hashAncestor))
|
if (setConflicts.count(hashAncestor))
|
||||||
{
|
{
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-spends-conflicting-tx",
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, "bad-txns-spends-conflicting-tx",
|
||||||
strprintf("%s spends conflicting transaction %s",
|
strprintf("%s spends conflicting transaction %s",
|
||||||
hash.ToString(),
|
hash.ToString(),
|
||||||
hashAncestor.ToString()));
|
hashAncestor.ToString()));
|
||||||
@ -824,7 +824,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
|
CFeeRate oldFeeRate(mi->GetModifiedFee(), mi->GetTxSize());
|
||||||
if (newFeeRate <= oldFeeRate)
|
if (newFeeRate <= oldFeeRate)
|
||||||
{
|
{
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "insufficient fee",
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "insufficient fee",
|
||||||
strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
|
strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
|
||||||
hash.ToString(),
|
hash.ToString(),
|
||||||
newFeeRate.ToString(),
|
newFeeRate.ToString(),
|
||||||
@ -852,7 +852,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
nConflictingSize += it->GetTxSize();
|
nConflictingSize += it->GetTxSize();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "too many potential replacements",
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "too many potential replacements",
|
||||||
strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n",
|
strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n",
|
||||||
hash.ToString(),
|
hash.ToString(),
|
||||||
nConflictingCount,
|
nConflictingCount,
|
||||||
@ -876,7 +876,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
// it's cheaper to just check if the new input refers to a
|
// it's cheaper to just check if the new input refers to a
|
||||||
// tx that's in the mempool.
|
// tx that's in the mempool.
|
||||||
if (m_pool.exists(tx.vin[j].prevout.hash)) {
|
if (m_pool.exists(tx.vin[j].prevout.hash)) {
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "replacement-adds-unconfirmed",
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "replacement-adds-unconfirmed",
|
||||||
strprintf("replacement %s adds unconfirmed input, idx %d",
|
strprintf("replacement %s adds unconfirmed input, idx %d",
|
||||||
hash.ToString(), j));
|
hash.ToString(), j));
|
||||||
}
|
}
|
||||||
@ -888,7 +888,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
// transactions would not be paid for.
|
// transactions would not be paid for.
|
||||||
if (nModifiedFees < nConflictingFees)
|
if (nModifiedFees < nConflictingFees)
|
||||||
{
|
{
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "insufficient fee",
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "insufficient fee",
|
||||||
strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
|
strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
|
||||||
hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)));
|
hash.ToString(), FormatMoney(nModifiedFees), FormatMoney(nConflictingFees)));
|
||||||
}
|
}
|
||||||
@ -898,7 +898,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||||||
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
|
CAmount nDeltaFees = nModifiedFees - nConflictingFees;
|
||||||
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
|
if (nDeltaFees < ::incrementalRelayFee.GetFee(nSize))
|
||||||
{
|
{
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "insufficient fee",
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "insufficient fee",
|
||||||
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
|
strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
|
||||||
hash.ToString(),
|
hash.ToString(),
|
||||||
FormatMoney(nDeltaFees),
|
FormatMoney(nDeltaFees),
|
||||||
@ -912,7 +912,7 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
|
|||||||
{
|
{
|
||||||
const CTransaction& tx = *ws.m_ptx;
|
const CTransaction& tx = *ws.m_ptx;
|
||||||
|
|
||||||
CValidationState &state = args.m_state;
|
TxValidationState &state = args.m_state;
|
||||||
|
|
||||||
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
|
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
|
||||||
|
|
||||||
@ -922,14 +922,13 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
|
|||||||
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
||||||
// need to turn both off, and compare against just turning off CLEANSTACK
|
// need to turn both off, and compare against just turning off CLEANSTACK
|
||||||
// to see if the failure is specifically due to witness validation.
|
// to see if the failure is specifically due to witness validation.
|
||||||
CValidationState stateDummy; // Want reported failures to be from first CheckInputs
|
TxValidationState state_dummy; // Want reported failures to be from first CheckInputs
|
||||||
if (!tx.HasWitness() && CheckInputs(tx, stateDummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
|
if (!tx.HasWitness() && CheckInputs(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
|
||||||
!CheckInputs(tx, stateDummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
|
!CheckInputs(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
|
||||||
// Only the witness is missing, so the transaction itself may be fine.
|
// Only the witness is missing, so the transaction itself may be fine.
|
||||||
state.Invalid(ValidationInvalidReason::TX_WITNESS_MUTATED, false,
|
state.Invalid(TxValidationResult::TX_WITNESS_MUTATED, false,
|
||||||
state.GetRejectReason(), state.GetDebugMessage());
|
state.GetRejectReason(), state.GetDebugMessage());
|
||||||
}
|
}
|
||||||
assert(IsTransactionReason(state.GetReason()));
|
|
||||||
return false; // state filled in by CheckInputs
|
return false; // state filled in by CheckInputs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,7 +940,7 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, Precomp
|
|||||||
const CTransaction& tx = *ws.m_ptx;
|
const CTransaction& tx = *ws.m_ptx;
|
||||||
const uint256& hash = ws.m_hash;
|
const uint256& hash = ws.m_hash;
|
||||||
|
|
||||||
CValidationState &state = args.m_state;
|
TxValidationState &state = args.m_state;
|
||||||
const CChainParams& chainparams = args.m_chainparams;
|
const CChainParams& chainparams = args.m_chainparams;
|
||||||
|
|
||||||
// Check again against the current block tip's script verification
|
// Check again against the current block tip's script verification
|
||||||
@ -972,7 +971,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
|
|||||||
{
|
{
|
||||||
const CTransaction& tx = *ws.m_ptx;
|
const CTransaction& tx = *ws.m_ptx;
|
||||||
const uint256& hash = ws.m_hash;
|
const uint256& hash = ws.m_hash;
|
||||||
CValidationState &state = args.m_state;
|
TxValidationState &state = args.m_state;
|
||||||
const bool bypass_limits = args.m_bypass_limits;
|
const bool bypass_limits = args.m_bypass_limits;
|
||||||
|
|
||||||
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting;
|
CTxMemPool::setEntries& allConflicting = ws.m_all_conflicting;
|
||||||
@ -1010,7 +1009,7 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
|
|||||||
if (!bypass_limits) {
|
if (!bypass_limits) {
|
||||||
LimitMempoolSize(m_pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
|
LimitMempoolSize(m_pool, gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, std::chrono::hours{gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)});
|
||||||
if (!m_pool.exists(hash))
|
if (!m_pool.exists(hash))
|
||||||
return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, "mempool full");
|
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, false, "mempool full");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1047,7 +1046,7 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
|
|||||||
} // anon namespace
|
} // anon namespace
|
||||||
|
|
||||||
/** (try to) add transaction to memory pool with a specified acceptance time **/
|
/** (try to) add transaction to memory pool with a specified acceptance time **/
|
||||||
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
|
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
|
||||||
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
|
bool* pfMissingInputs, int64_t nAcceptTime, std::list<CTransactionRef>* plTxnReplaced,
|
||||||
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
{
|
{
|
||||||
@ -1064,12 +1063,12 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
|
|||||||
::ChainstateActive().CoinsTip().Uncache(hashTx);
|
::ChainstateActive().CoinsTip().Uncache(hashTx);
|
||||||
}
|
}
|
||||||
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
|
// After we've (potentially) uncached entries, ensure our coins cache is still within its size limits
|
||||||
CValidationState stateDummy;
|
BlockValidationState state_dummy;
|
||||||
::ChainstateActive().FlushStateToDisk(chainparams, stateDummy, FlushStateMode::PERIODIC);
|
::ChainstateActive().FlushStateToDisk(chainparams, state_dummy, FlushStateMode::PERIODIC);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
|
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
|
||||||
bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
|
bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
|
||||||
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept)
|
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept)
|
||||||
{
|
{
|
||||||
@ -1419,8 +1418,8 @@ void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(c
|
|||||||
CheckForkWarningConditions();
|
CheckForkWarningConditions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
|
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const BlockValidationState &state) {
|
||||||
if (state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) {
|
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
|
||||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||||
m_blockman.m_failed_blocks.insert(pindex);
|
m_blockman.m_failed_blocks.insert(pindex);
|
||||||
setDirtyBlockIndex.insert(pindex);
|
setDirtyBlockIndex.insert(pindex);
|
||||||
@ -1493,7 +1492,7 @@ void InitScriptExecutionCache() {
|
|||||||
*
|
*
|
||||||
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
|
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
|
||||||
*/
|
*/
|
||||||
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
{
|
{
|
||||||
if (tx.IsCoinBase()) return true;
|
if (tx.IsCoinBase()) return true;
|
||||||
|
|
||||||
@ -1545,10 +1544,10 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||||||
CScriptCheck check2(coin.out, tx, i,
|
CScriptCheck check2(coin.out, tx, i,
|
||||||
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
|
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
|
||||||
if (check2())
|
if (check2())
|
||||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, false, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, false, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
|
||||||
}
|
}
|
||||||
// MANDATORY flag failures correspond to
|
// MANDATORY flag failures correspond to
|
||||||
// ValidationInvalidReason::CONSENSUS. Because CONSENSUS
|
// TxValidationResult::TX_CONSENSUS. Because CONSENSUS
|
||||||
// failures are the most serious case of validation
|
// failures are the most serious case of validation
|
||||||
// failures, we may need to consider using
|
// failures, we may need to consider using
|
||||||
// RECENT_CONSENSUS_CHANGE for any script failure that
|
// RECENT_CONSENSUS_CHANGE for any script failure that
|
||||||
@ -1556,7 +1555,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
|
|||||||
// support, to avoid splitting the network (but this
|
// support, to avoid splitting the network (but this
|
||||||
// depends on the details of how net_processing handles
|
// depends on the details of how net_processing handles
|
||||||
// such errors).
|
// such errors).
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
|
return state.Invalid(TxValidationResult::TX_CONSENSUS, false, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1641,7 +1640,7 @@ static bool AbortNode(const std::string& strMessage, const std::string& userMess
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0)
|
static bool AbortNode(BlockValidationState& state, const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0)
|
||||||
{
|
{
|
||||||
AbortNode(strMessage, userMessage, prefix);
|
AbortNode(strMessage, userMessage, prefix);
|
||||||
return state.Error(strMessage);
|
return state.Error(strMessage);
|
||||||
@ -1755,9 +1754,9 @@ void static FlushBlockFile(bool fFinalize = false)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize);
|
static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize);
|
||||||
|
|
||||||
static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, CValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
|
static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
|
||||||
{
|
{
|
||||||
// Write undo information to disk
|
// Write undo information to disk
|
||||||
if (pindex->GetUndoPos().IsNull()) {
|
if (pindex->GetUndoPos().IsNull()) {
|
||||||
@ -1896,7 +1895,7 @@ static int64_t nBlocksTotal = 0;
|
|||||||
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
|
/** Apply the effects of this block (with given index) on the UTXO set represented by coins.
|
||||||
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
|
* Validity checks that depend on the UTXO set are also done; ConnectBlock()
|
||||||
* can fail if those validity checks fail (among other reasons). */
|
* can fail if those validity checks fail (among other reasons). */
|
||||||
bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
|
bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex,
|
||||||
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck)
|
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
@ -1918,7 +1917,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
// re-enforce that rule here (at least until we make it impossible for
|
// re-enforce that rule here (at least until we make it impossible for
|
||||||
// GetAdjustedTime() to go backward).
|
// GetAdjustedTime() to go backward).
|
||||||
if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck)) {
|
if (!CheckBlock(block, state, chainparams.GetConsensus(), !fJustCheck, !fJustCheck)) {
|
||||||
if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED) {
|
if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED) {
|
||||||
// We don't write down blocks to disk if they may have been
|
// We don't write down blocks to disk if they may have been
|
||||||
// corrupted, so this should be impossible unless we're having hardware
|
// corrupted, so this should be impossible unless we're having hardware
|
||||||
// problems.
|
// problems.
|
||||||
@ -2058,7 +2057,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
for (const auto& tx : block.vtx) {
|
for (const auto& tx : block.vtx) {
|
||||||
for (size_t o = 0; o < tx->vout.size(); o++) {
|
for (size_t o = 0; o < tx->vout.size(); o++) {
|
||||||
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
|
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"),
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"),
|
||||||
"bad-txns-BIP30");
|
"bad-txns-BIP30");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2097,20 +2096,16 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
if (!tx.IsCoinBase())
|
if (!tx.IsCoinBase())
|
||||||
{
|
{
|
||||||
CAmount txfee = 0;
|
CAmount txfee = 0;
|
||||||
if (!Consensus::CheckTxInputs(tx, state, view, pindex->nHeight, txfee)) {
|
TxValidationState tx_state;
|
||||||
if (!IsBlockReason(state.GetReason())) {
|
if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee)) {
|
||||||
// CheckTxInputs may return MISSING_INPUTS or
|
// Any transaction validation failure in ConnectBlock is a block consensus failure
|
||||||
// PREMATURE_SPEND but we can't return that, as it's not
|
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false,
|
||||||
// defined for a block, so we reset the reason flag to
|
tx_state.GetRejectReason(), tx_state.GetDebugMessage());
|
||||||
// CONSENSUS here.
|
|
||||||
state.Invalid(ValidationInvalidReason::CONSENSUS, false,
|
|
||||||
state.GetRejectReason(), state.GetDebugMessage());
|
|
||||||
}
|
|
||||||
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
|
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
nFees += txfee;
|
nFees += txfee;
|
||||||
if (!MoneyRange(nFees)) {
|
if (!MoneyRange(nFees)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__),
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__),
|
||||||
"bad-txns-accumulated-fee-outofrange");
|
"bad-txns-accumulated-fee-outofrange");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2123,7 +2118,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
|
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__),
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__),
|
||||||
"bad-txns-nonfinal");
|
"bad-txns-nonfinal");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2134,7 +2129,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
// * witness (when witness enabled in flags and excludes coinbase)
|
// * witness (when witness enabled in flags and excludes coinbase)
|
||||||
nSigOpsCost += GetTransactionSigOpCost(tx, view, flags);
|
nSigOpsCost += GetTransactionSigOpCost(tx, view, flags);
|
||||||
if (nSigOpsCost > MAX_BLOCK_SIGOPS_COST)
|
if (nSigOpsCost > MAX_BLOCK_SIGOPS_COST)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): too many sigops"),
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, error("ConnectBlock(): too many sigops"),
|
||||||
"bad-blk-sigops");
|
"bad-blk-sigops");
|
||||||
|
|
||||||
txdata.emplace_back(tx);
|
txdata.emplace_back(tx);
|
||||||
@ -2142,17 +2137,11 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
{
|
{
|
||||||
std::vector<CScriptCheck> vChecks;
|
std::vector<CScriptCheck> vChecks;
|
||||||
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
|
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
|
||||||
if (fScriptChecks && !CheckInputs(tx, state, view, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr)) {
|
TxValidationState tx_state;
|
||||||
if (state.GetReason() == ValidationInvalidReason::TX_NOT_STANDARD) {
|
if (fScriptChecks && !CheckInputs(tx, tx_state, view, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr)) {
|
||||||
// CheckInputs may return NOT_STANDARD for extra flags we passed,
|
// Any transaction validation failure in ConnectBlock is a block consensus failure
|
||||||
// but we can't return that, as it's not defined for a block, so
|
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false,
|
||||||
// we reset the reason flag to CONSENSUS here.
|
tx_state.GetRejectReason(), tx_state.GetDebugMessage());
|
||||||
// In the event of a future soft-fork, we may need to
|
|
||||||
// consider whether rewriting to CONSENSUS or
|
|
||||||
// RECENT_CONSENSUS_CHANGE would be more appropriate.
|
|
||||||
state.Invalid(ValidationInvalidReason::CONSENSUS, false,
|
|
||||||
state.GetRejectReason(), state.GetDebugMessage());
|
|
||||||
}
|
|
||||||
return error("ConnectBlock(): CheckInputs on %s failed with %s",
|
return error("ConnectBlock(): CheckInputs on %s failed with %s",
|
||||||
tx.GetHash().ToString(), FormatStateMessage(state));
|
tx.GetHash().ToString(), FormatStateMessage(state));
|
||||||
}
|
}
|
||||||
@ -2170,13 +2159,13 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
|
|
||||||
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
|
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
|
||||||
if (block.vtx[0]->GetValueOut() > blockReward)
|
if (block.vtx[0]->GetValueOut() > blockReward)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS,
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
|
||||||
error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)",
|
error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)",
|
||||||
block.vtx[0]->GetValueOut(), blockReward),
|
block.vtx[0]->GetValueOut(), blockReward),
|
||||||
"bad-cb-amount");
|
"bad-cb-amount");
|
||||||
|
|
||||||
if (!control.Wait())
|
if (!control.Wait())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, error("%s: CheckQueue failed", __func__), "block-validation-failed");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, error("%s: CheckQueue failed", __func__), "block-validation-failed");
|
||||||
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
|
int64_t nTime4 = GetTimeMicros(); nTimeVerify += nTime4 - nTime2;
|
||||||
LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
|
LogPrint(BCLog::BENCH, " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", nInputs - 1, MILLI * (nTime4 - nTime2), nInputs <= 1 ? 0 : MILLI * (nTime4 - nTime2) / (nInputs-1), nTimeVerify * MICRO, nTimeVerify * MILLI / nBlocksTotal);
|
||||||
|
|
||||||
@ -2206,7 +2195,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
|
|||||||
|
|
||||||
bool CChainState::FlushStateToDisk(
|
bool CChainState::FlushStateToDisk(
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
CValidationState &state,
|
BlockValidationState &state,
|
||||||
FlushStateMode mode,
|
FlushStateMode mode,
|
||||||
int nManualPruneHeight)
|
int nManualPruneHeight)
|
||||||
{
|
{
|
||||||
@ -2317,7 +2306,7 @@ bool CChainState::FlushStateToDisk(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CChainState::ForceFlushStateToDisk() {
|
void CChainState::ForceFlushStateToDisk() {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
|
if (!this->FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
|
||||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
|
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
|
||||||
@ -2325,7 +2314,7 @@ void CChainState::ForceFlushStateToDisk() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CChainState::PruneAndFlush() {
|
void CChainState::PruneAndFlush() {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
fCheckForPruning = true;
|
fCheckForPruning = true;
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
|
|
||||||
@ -2411,7 +2400,7 @@ void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainPar
|
|||||||
* disconnectpool (note that the caller is responsible for mempool consistency
|
* disconnectpool (note that the caller is responsible for mempool consistency
|
||||||
* in any case).
|
* in any case).
|
||||||
*/
|
*/
|
||||||
bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
|
bool CChainState::DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
|
||||||
{
|
{
|
||||||
CBlockIndex *pindexDelete = m_chain.Tip();
|
CBlockIndex *pindexDelete = m_chain.Tip();
|
||||||
assert(pindexDelete);
|
assert(pindexDelete);
|
||||||
@ -2531,7 +2520,7 @@ public:
|
|||||||
*
|
*
|
||||||
* The block is added to connectTrace if connection succeeds.
|
* The block is added to connectTrace if connection succeeds.
|
||||||
*/
|
*/
|
||||||
bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
|
bool CChainState::ConnectTip(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
|
||||||
{
|
{
|
||||||
assert(pindexNew->pprev == m_chain.Tip());
|
assert(pindexNew->pprev == m_chain.Tip());
|
||||||
// Read block from disk.
|
// Read block from disk.
|
||||||
@ -2663,7 +2652,7 @@ void CChainState::PruneBlockIndexCandidates() {
|
|||||||
*
|
*
|
||||||
* @returns true unless a system error occurred
|
* @returns true unless a system error occurred
|
||||||
*/
|
*/
|
||||||
bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
|
bool CChainState::ActivateBestChainStep(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
@ -2710,10 +2699,10 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
|
|||||||
if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) {
|
if (!ConnectTip(state, chainparams, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connectTrace, disconnectpool)) {
|
||||||
if (state.IsInvalid()) {
|
if (state.IsInvalid()) {
|
||||||
// The block violates a consensus rule.
|
// The block violates a consensus rule.
|
||||||
if (state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) {
|
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
|
||||||
InvalidChainFound(vpindexToConnect.front());
|
InvalidChainFound(vpindexToConnect.front());
|
||||||
}
|
}
|
||||||
state = CValidationState();
|
state = BlockValidationState();
|
||||||
fInvalidFound = true;
|
fInvalidFound = true;
|
||||||
fContinue = false;
|
fContinue = false;
|
||||||
break;
|
break;
|
||||||
@ -2781,7 +2770,7 @@ static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
bool CChainState::ActivateBestChain(BlockValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
||||||
// Note that while we're often called here from ProcessNewBlock, this is
|
// Note that while we're often called here from ProcessNewBlock, this is
|
||||||
// far from a guarantee. Things in the P2P/RPC will often end up calling
|
// far from a guarantee. Things in the P2P/RPC will often end up calling
|
||||||
// us in the middle of ProcessNewBlock - do not assume pblock is set
|
// us in the middle of ProcessNewBlock - do not assume pblock is set
|
||||||
@ -2881,11 +2870,11 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
bool ActivateBestChain(BlockValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
|
||||||
return ::ChainstateActive().ActivateBestChain(state, chainparams, std::move(pblock));
|
return ::ChainstateActive().ActivateBestChain(state, chainparams, std::move(pblock));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
|
bool CChainState::PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex *pindex)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
@ -2913,11 +2902,11 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par
|
|||||||
|
|
||||||
return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
|
return ActivateBestChain(state, params, std::shared_ptr<const CBlock>());
|
||||||
}
|
}
|
||||||
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
|
bool PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
|
||||||
return ::ChainstateActive().PreciousBlock(state, params, pindex);
|
return ::ChainstateActive().PreciousBlock(state, params, pindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
|
bool CChainState::InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
|
||||||
{
|
{
|
||||||
CBlockIndex* to_mark_failed = pindex;
|
CBlockIndex* to_mark_failed = pindex;
|
||||||
bool pindex_was_in_chain = false;
|
bool pindex_was_in_chain = false;
|
||||||
@ -3053,7 +3042,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
|
bool InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
|
||||||
return ::ChainstateActive().InvalidateBlock(state, chainparams, pindex);
|
return ::ChainstateActive().InvalidateBlock(state, chainparams, pindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3227,7 +3216,7 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize)
|
static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize)
|
||||||
{
|
{
|
||||||
pos.nFile = nFile;
|
pos.nFile = nFile;
|
||||||
|
|
||||||
@ -3249,16 +3238,16 @@ static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, un
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true)
|
static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true)
|
||||||
{
|
{
|
||||||
// Check proof of work matches claimed amount
|
// Check proof of work matches claimed amount
|
||||||
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
|
if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams))
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "high-hash", "proof of work failed");
|
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, false, "high-hash", "proof of work failed");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot)
|
bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot)
|
||||||
{
|
{
|
||||||
// These are checks that are independent of context.
|
// These are checks that are independent of context.
|
||||||
|
|
||||||
@ -3275,13 +3264,13 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
|
|||||||
bool mutated;
|
bool mutated;
|
||||||
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
|
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
|
||||||
if (block.hashMerkleRoot != hashMerkleRoot2)
|
if (block.hashMerkleRoot != hashMerkleRoot2)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txnmrklroot", "hashMerkleRoot mismatch");
|
return state.Invalid(BlockValidationResult::BLOCK_MUTATED, false, "bad-txnmrklroot", "hashMerkleRoot mismatch");
|
||||||
|
|
||||||
// Check for merkle tree malleability (CVE-2012-2459): repeating sequences
|
// Check for merkle tree malleability (CVE-2012-2459): repeating sequences
|
||||||
// of transactions in a block without affecting the merkle root of a block,
|
// of transactions in a block without affecting the merkle root of a block,
|
||||||
// while still invalidating it.
|
// while still invalidating it.
|
||||||
if (mutated)
|
if (mutated)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-txns-duplicate", "duplicate transaction");
|
return state.Invalid(BlockValidationResult::BLOCK_MUTATED, false, "bad-txns-duplicate", "duplicate transaction");
|
||||||
}
|
}
|
||||||
|
|
||||||
// All potential-corruption validation must be done before we do any
|
// All potential-corruption validation must be done before we do any
|
||||||
@ -3292,28 +3281,34 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
|
|||||||
|
|
||||||
// Size limits
|
// Size limits
|
||||||
if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
|
if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-length", "size limits failed");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false, "bad-blk-length", "size limits failed");
|
||||||
|
|
||||||
// First transaction must be coinbase, the rest must not be
|
// First transaction must be coinbase, the rest must not be
|
||||||
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
|
if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-missing", "first tx is not coinbase");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false, "bad-cb-missing", "first tx is not coinbase");
|
||||||
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
for (unsigned int i = 1; i < block.vtx.size(); i++)
|
||||||
if (block.vtx[i]->IsCoinBase())
|
if (block.vtx[i]->IsCoinBase())
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-multiple", "more than one coinbase");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false, "bad-cb-multiple", "more than one coinbase");
|
||||||
|
|
||||||
// Check transactions
|
// Check transactions
|
||||||
for (const auto& tx : block.vtx)
|
// Must check for duplicate inputs (see CVE-2018-17144)
|
||||||
if (!CheckTransaction(*tx, state))
|
for (const auto& tx : block.vtx) {
|
||||||
return state.Invalid(state.GetReason(), false, state.GetRejectReason(),
|
TxValidationState tx_state;
|
||||||
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
|
if (!CheckTransaction(*tx, tx_state)) {
|
||||||
|
// CheckBlock() does context-free validation checks. The only
|
||||||
|
// possible failures are consensus failures.
|
||||||
|
assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS);
|
||||||
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false, tx_state.GetRejectReason(),
|
||||||
|
strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), tx_state.GetDebugMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
unsigned int nSigOps = 0;
|
unsigned int nSigOps = 0;
|
||||||
for (const auto& tx : block.vtx)
|
for (const auto& tx : block.vtx)
|
||||||
{
|
{
|
||||||
nSigOps += GetLegacySigOpCount(*tx);
|
nSigOps += GetLegacySigOpCount(*tx);
|
||||||
}
|
}
|
||||||
if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST)
|
if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST)
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount");
|
||||||
|
|
||||||
if (fCheckPOW && fCheckMerkleRoot)
|
if (fCheckPOW && fCheckMerkleRoot)
|
||||||
block.fChecked = true;
|
block.fChecked = true;
|
||||||
@ -3406,7 +3401,7 @@ static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOC
|
|||||||
* in ConnectBlock().
|
* in ConnectBlock().
|
||||||
* Note that -reindex-chainstate skips the validation that happens here!
|
* Note that -reindex-chainstate skips the validation that happens here!
|
||||||
*/
|
*/
|
||||||
static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||||
{
|
{
|
||||||
assert(pindexPrev != nullptr);
|
assert(pindexPrev != nullptr);
|
||||||
const int nHeight = pindexPrev->nHeight + 1;
|
const int nHeight = pindexPrev->nHeight + 1;
|
||||||
@ -3414,7 +3409,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
|
|||||||
// Check proof of work
|
// Check proof of work
|
||||||
const Consensus::Params& consensusParams = params.GetConsensus();
|
const Consensus::Params& consensusParams = params.GetConsensus();
|
||||||
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
|
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "bad-diffbits", "incorrect proof of work");
|
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, false, "bad-diffbits", "incorrect proof of work");
|
||||||
|
|
||||||
// Check against checkpoints
|
// Check against checkpoints
|
||||||
if (fCheckpointsEnabled) {
|
if (fCheckpointsEnabled) {
|
||||||
@ -3423,23 +3418,23 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
|
|||||||
// g_blockman.m_block_index.
|
// g_blockman.m_block_index.
|
||||||
CBlockIndex* pcheckpoint = GetLastCheckpoint(params.Checkpoints());
|
CBlockIndex* pcheckpoint = GetLastCheckpoint(params.Checkpoints());
|
||||||
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
|
if (pcheckpoint && nHeight < pcheckpoint->nHeight)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), "bad-fork-prior-to-checkpoint");
|
return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), "bad-fork-prior-to-checkpoint");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check timestamp against prev
|
// Check timestamp against prev
|
||||||
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, "time-too-old", "block's timestamp is too early");
|
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, false, "time-too-old", "block's timestamp is too early");
|
||||||
|
|
||||||
// Check timestamp
|
// Check timestamp
|
||||||
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
|
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, "time-too-new", "block timestamp too far in the future");
|
return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, false, "time-too-new", "block timestamp too far in the future");
|
||||||
|
|
||||||
// Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
|
// Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
|
||||||
// check for version 2, 3 and 4 upgrades
|
// check for version 2, 3 and 4 upgrades
|
||||||
if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
|
if((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) ||
|
||||||
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
|
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) ||
|
||||||
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height))
|
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height))
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_HEADER, false, strprintf("bad-version(0x%08x)", block.nVersion),
|
return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, false, strprintf("bad-version(0x%08x)", block.nVersion),
|
||||||
strprintf("rejected nVersion=0x%08x block", block.nVersion));
|
strprintf("rejected nVersion=0x%08x block", block.nVersion));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -3451,7 +3446,7 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
|
|||||||
* in ConnectBlock().
|
* in ConnectBlock().
|
||||||
* Note that -reindex-chainstate skips the validation that happens here!
|
* Note that -reindex-chainstate skips the validation that happens here!
|
||||||
*/
|
*/
|
||||||
static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
|
static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
|
||||||
{
|
{
|
||||||
const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
|
const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
|
||||||
|
|
||||||
@ -3469,7 +3464,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|||||||
// Check that all transactions are finalized
|
// Check that all transactions are finalized
|
||||||
for (const auto& tx : block.vtx) {
|
for (const auto& tx : block.vtx) {
|
||||||
if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) {
|
if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-nonfinal", "non-final transaction");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false, "bad-txns-nonfinal", "non-final transaction");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3479,7 +3474,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|||||||
CScript expect = CScript() << nHeight;
|
CScript expect = CScript() << nHeight;
|
||||||
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
|
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
|
||||||
!std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) {
|
!std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-height", "block height mismatch in coinbase");
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false, "bad-cb-height", "block height mismatch in coinbase");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3501,11 +3496,11 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|||||||
// already does not permit it, it is impossible to trigger in the
|
// already does not permit it, it is impossible to trigger in the
|
||||||
// witness tree.
|
// witness tree.
|
||||||
if (block.vtx[0]->vin[0].scriptWitness.stack.size() != 1 || block.vtx[0]->vin[0].scriptWitness.stack[0].size() != 32) {
|
if (block.vtx[0]->vin[0].scriptWitness.stack.size() != 1 || block.vtx[0]->vin[0].scriptWitness.stack[0].size() != 32) {
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-witness-nonce-size", strprintf("%s : invalid witness reserved value size", __func__));
|
return state.Invalid(BlockValidationResult::BLOCK_MUTATED, false, "bad-witness-nonce-size", strprintf("%s : invalid witness reserved value size", __func__));
|
||||||
}
|
}
|
||||||
CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->vin[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
|
CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->vin[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
|
||||||
if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) {
|
if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) {
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "bad-witness-merkle-match", strprintf("%s : witness merkle commitment mismatch", __func__));
|
return state.Invalid(BlockValidationResult::BLOCK_MUTATED, false, "bad-witness-merkle-match", strprintf("%s : witness merkle commitment mismatch", __func__));
|
||||||
}
|
}
|
||||||
fHaveWitness = true;
|
fHaveWitness = true;
|
||||||
}
|
}
|
||||||
@ -3515,7 +3510,7 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|||||||
if (!fHaveWitness) {
|
if (!fHaveWitness) {
|
||||||
for (const auto& tx : block.vtx) {
|
for (const auto& tx : block.vtx) {
|
||||||
if (tx->HasWitness()) {
|
if (tx->HasWitness()) {
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MUTATED, false, "unexpected-witness", strprintf("%s : unexpected witness data found", __func__));
|
return state.Invalid(BlockValidationResult::BLOCK_MUTATED, false, "unexpected-witness", strprintf("%s : unexpected witness data found", __func__));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3527,13 +3522,13 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
|
|||||||
// the block hash, so we couldn't mark the block as permanently
|
// the block hash, so we couldn't mark the block as permanently
|
||||||
// failed).
|
// failed).
|
||||||
if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT) {
|
if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT) {
|
||||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-blk-weight", strprintf("%s : weight limit failed", __func__));
|
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, false, "bad-blk-weight", strprintf("%s : weight limit failed", __func__));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
|
bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
// Check for duplicate
|
// Check for duplicate
|
||||||
@ -3547,7 +3542,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
|
|||||||
if (ppindex)
|
if (ppindex)
|
||||||
*ppindex = pindex;
|
*ppindex = pindex;
|
||||||
if (pindex->nStatus & BLOCK_FAILED_MASK)
|
if (pindex->nStatus & BLOCK_FAILED_MASK)
|
||||||
return state.Invalid(ValidationInvalidReason::CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), "duplicate");
|
return state.Invalid(BlockValidationResult::BLOCK_CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), "duplicate");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3558,10 +3553,10 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
|
|||||||
CBlockIndex* pindexPrev = nullptr;
|
CBlockIndex* pindexPrev = nullptr;
|
||||||
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
|
BlockMap::iterator mi = m_block_index.find(block.hashPrevBlock);
|
||||||
if (mi == m_block_index.end())
|
if (mi == m_block_index.end())
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), "prev-blk-not-found");
|
return state.Invalid(BlockValidationResult::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), "prev-blk-not-found");
|
||||||
pindexPrev = (*mi).second;
|
pindexPrev = (*mi).second;
|
||||||
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
|
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
|
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
|
||||||
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
|
if (!ContextualCheckBlockHeader(block, state, chainparams, pindexPrev, GetAdjustedTime()))
|
||||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
|
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
|
||||||
|
|
||||||
@ -3598,7 +3593,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
|
|||||||
setDirtyBlockIndex.insert(invalid_walk);
|
setDirtyBlockIndex.insert(invalid_walk);
|
||||||
invalid_walk = invalid_walk->pprev;
|
invalid_walk = invalid_walk->pprev;
|
||||||
}
|
}
|
||||||
return state.Invalid(ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
|
return state.Invalid(BlockValidationResult::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3613,7 +3608,7 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exposed wrapper for AcceptBlockHeader
|
// Exposed wrapper for AcceptBlockHeader
|
||||||
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid)
|
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid)
|
||||||
{
|
{
|
||||||
if (first_invalid != nullptr) first_invalid->SetNull();
|
if (first_invalid != nullptr) first_invalid->SetNull();
|
||||||
{
|
{
|
||||||
@ -3660,7 +3655,7 @@ static FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, const CChai
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
|
/** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
|
||||||
bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock)
|
bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock)
|
||||||
{
|
{
|
||||||
const CBlock& block = *pblock;
|
const CBlock& block = *pblock;
|
||||||
|
|
||||||
@ -3710,8 +3705,7 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
|
|||||||
|
|
||||||
if (!CheckBlock(block, state, chainparams.GetConsensus()) ||
|
if (!CheckBlock(block, state, chainparams.GetConsensus()) ||
|
||||||
!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
|
!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
|
||||||
assert(IsBlockReason(state.GetReason()));
|
if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
|
||||||
if (state.IsInvalid() && state.GetReason() != ValidationInvalidReason::BLOCK_MUTATED) {
|
|
||||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
pindex->nStatus |= BLOCK_FAILED_VALID;
|
||||||
setDirtyBlockIndex.insert(pindex);
|
setDirtyBlockIndex.insert(pindex);
|
||||||
}
|
}
|
||||||
@ -3750,7 +3744,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
|
|||||||
{
|
{
|
||||||
CBlockIndex *pindex = nullptr;
|
CBlockIndex *pindex = nullptr;
|
||||||
if (fNewBlock) *fNewBlock = false;
|
if (fNewBlock) *fNewBlock = false;
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
|
|
||||||
// CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race.
|
// CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race.
|
||||||
// Therefore, the following critical section must include the CheckBlock() call as well.
|
// Therefore, the following critical section must include the CheckBlock() call as well.
|
||||||
@ -3771,14 +3765,14 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
|
|||||||
|
|
||||||
NotifyHeaderTip();
|
NotifyHeaderTip();
|
||||||
|
|
||||||
CValidationState state; // Only used to report errors, not invalidity - ignore it
|
BlockValidationState state; // Only used to report errors, not invalidity - ignore it
|
||||||
if (!::ChainstateActive().ActivateBestChain(state, chainparams, pblock))
|
if (!::ChainstateActive().ActivateBestChain(state, chainparams, pblock))
|
||||||
return error("%s: ActivateBestChain failed (%s)", __func__, FormatStateMessage(state));
|
return error("%s: ActivateBestChain failed (%s)", __func__, FormatStateMessage(state));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot)
|
bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
assert(pindexPrev && pindexPrev == ::ChainActive().Tip());
|
assert(pindexPrev && pindexPrev == ::ChainActive().Tip());
|
||||||
@ -3889,7 +3883,7 @@ static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPr
|
|||||||
/* This function is called from the RPC code for pruneblockchain */
|
/* This function is called from the RPC code for pruneblockchain */
|
||||||
void PruneBlockFilesManual(int nManualPruneHeight)
|
void PruneBlockFilesManual(int nManualPruneHeight)
|
||||||
{
|
{
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
if (!::ChainstateActive().FlushStateToDisk(
|
if (!::ChainstateActive().FlushStateToDisk(
|
||||||
chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
|
chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) {
|
||||||
@ -4185,7 +4179,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
|
|||||||
CBlockIndex* pindex;
|
CBlockIndex* pindex;
|
||||||
CBlockIndex* pindexFailure = nullptr;
|
CBlockIndex* pindexFailure = nullptr;
|
||||||
int nGoodTransactions = 0;
|
int nGoodTransactions = 0;
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
int reportDone = 0;
|
int reportDone = 0;
|
||||||
LogPrintf("[0%%]..."); /* Continued */
|
LogPrintf("[0%%]..."); /* Continued */
|
||||||
for (pindex = ::ChainActive().Tip(); pindex && pindex->pprev; pindex = pindex->pprev) {
|
for (pindex = ::ChainActive().Tip(); pindex && pindex->pprev; pindex = pindex->pprev) {
|
||||||
@ -4429,7 +4423,7 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
|
|||||||
}
|
}
|
||||||
// nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
|
// nHeight is now the height of the first insufficiently-validated block, or tipheight + 1
|
||||||
|
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
// Loop until the tip is below nHeight, or we reach a pruned block.
|
// Loop until the tip is below nHeight, or we reach a pruned block.
|
||||||
while (!ShutdownRequested()) {
|
while (!ShutdownRequested()) {
|
||||||
{
|
{
|
||||||
@ -4497,7 +4491,7 @@ bool RewindBlockIndex(const CChainParams& params) {
|
|||||||
// FlushStateToDisk can possibly read ::ChainActive(). Be conservative
|
// FlushStateToDisk can possibly read ::ChainActive(). Be conservative
|
||||||
// and skip it here, we're about to -reindex-chainstate anyway, so
|
// and skip it here, we're about to -reindex-chainstate anyway, so
|
||||||
// it'll get called a bunch real soon.
|
// it'll get called a bunch real soon.
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!::ChainstateActive().FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
|
if (!::ChainstateActive().FlushStateToDisk(params, state, FlushStateMode::ALWAYS)) {
|
||||||
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
|
LogPrintf("RewindBlockIndex: unable to flush state to disk (%s)\n", FormatStateMessage(state));
|
||||||
return false;
|
return false;
|
||||||
@ -4649,7 +4643,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
|
|||||||
// process in case the block isn't known yet
|
// process in case the block isn't known yet
|
||||||
CBlockIndex* pindex = LookupBlockIndex(hash);
|
CBlockIndex* pindex = LookupBlockIndex(hash);
|
||||||
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
|
if (!pindex || (pindex->nStatus & BLOCK_HAVE_DATA) == 0) {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (::ChainstateActive().AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
|
if (::ChainstateActive().AcceptBlock(pblock, state, chainparams, nullptr, true, dbp, nullptr)) {
|
||||||
nLoaded++;
|
nLoaded++;
|
||||||
}
|
}
|
||||||
@ -4663,7 +4657,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
|
|||||||
|
|
||||||
// Activate the genesis block so normal node progress can continue
|
// Activate the genesis block so normal node progress can continue
|
||||||
if (hash == chainparams.GetConsensus().hashGenesisBlock) {
|
if (hash == chainparams.GetConsensus().hashGenesisBlock) {
|
||||||
CValidationState state;
|
BlockValidationState state;
|
||||||
if (!ActivateBestChain(state, chainparams)) {
|
if (!ActivateBestChain(state, chainparams)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -4686,7 +4680,7 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
|
|||||||
LogPrint(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
|
LogPrint(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
|
||||||
head.ToString());
|
head.ToString());
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
CValidationState dummy;
|
BlockValidationState dummy;
|
||||||
if (::ChainstateActive().AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
|
if (::ChainstateActive().AcceptBlock(pblockrecursive, dummy, chainparams, nullptr, true, &it->second, nullptr))
|
||||||
{
|
{
|
||||||
nLoaded++;
|
nLoaded++;
|
||||||
@ -4963,7 +4957,7 @@ bool LoadMempool(CTxMemPool& pool)
|
|||||||
if (amountdelta) {
|
if (amountdelta) {
|
||||||
pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
|
pool.PrioritiseTransaction(tx->GetHash(), amountdelta);
|
||||||
}
|
}
|
||||||
CValidationState state;
|
TxValidationState state;
|
||||||
if (nTime + nExpiryTimeout > nNow) {
|
if (nTime + nExpiryTimeout > nNow) {
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nullptr /* pfMissingInputs */, nTime,
|
AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, nullptr /* pfMissingInputs */, nTime,
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class CChainState;
|
class CChainState;
|
||||||
|
class BlockValidationState;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
class CBlockTreeDB;
|
class CBlockTreeDB;
|
||||||
class CBlockUndo;
|
class CBlockUndo;
|
||||||
@ -41,7 +42,7 @@ class CConnman;
|
|||||||
class CScriptCheck;
|
class CScriptCheck;
|
||||||
class CBlockPolicyEstimator;
|
class CBlockPolicyEstimator;
|
||||||
class CTxMemPool;
|
class CTxMemPool;
|
||||||
class CValidationState;
|
class TxValidationState;
|
||||||
struct ChainTxData;
|
struct ChainTxData;
|
||||||
|
|
||||||
struct DisconnectedBlockTransactions;
|
struct DisconnectedBlockTransactions;
|
||||||
@ -223,7 +224,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
|
|||||||
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
|
* @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
|
||||||
* @param[out] first_invalid First header that fails validation, if one exists
|
* @param[out] first_invalid First header that fails validation, if one exists
|
||||||
*/
|
*/
|
||||||
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, CValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr, CBlockHeader* first_invalid = nullptr) LOCKS_EXCLUDED(cs_main);
|
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr, CBlockHeader* first_invalid = nullptr) LOCKS_EXCLUDED(cs_main);
|
||||||
|
|
||||||
/** Open a block file (blk?????.dat) */
|
/** Open a block file (blk?????.dat) */
|
||||||
FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false);
|
FILE* OpenBlockFile(const FlatFilePos &pos, bool fReadOnly = false);
|
||||||
@ -248,7 +249,7 @@ bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::P
|
|||||||
* May not be called with cs_main held. May not be called in a
|
* May not be called with cs_main held. May not be called in a
|
||||||
* validationinterface callback.
|
* validationinterface callback.
|
||||||
*/
|
*/
|
||||||
bool ActivateBestChain(CValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
|
bool ActivateBestChain(BlockValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
|
||||||
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
|
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
|
||||||
|
|
||||||
/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
|
/** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
|
||||||
@ -272,7 +273,7 @@ void PruneBlockFilesManual(int nManualPruneHeight);
|
|||||||
|
|
||||||
/** (try to) add transaction to memory pool
|
/** (try to) add transaction to memory pool
|
||||||
* plTxnReplaced will be appended to with all transactions replaced from mempool **/
|
* plTxnReplaced will be appended to with all transactions replaced from mempool **/
|
||||||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransactionRef &tx,
|
bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTransactionRef &tx,
|
||||||
bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
|
bool* pfMissingInputs, std::list<CTransactionRef>* plTxnReplaced,
|
||||||
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool bypass_limits, const CAmount nAbsurdFee, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
@ -368,10 +369,10 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
|
|||||||
/** Functions for validating blocks and updating the block tree */
|
/** Functions for validating blocks and updating the block tree */
|
||||||
|
|
||||||
/** Context-independent validity checks */
|
/** Context-independent validity checks */
|
||||||
bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
|
||||||
|
|
||||||
/** Check a block is completely valid from start to finish (only works on top of our current best block) */
|
/** Check a block is completely valid from start to finish (only works on top of our current best block) */
|
||||||
bool TestBlockValidity(CValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool TestBlockValidity(BlockValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
/** Check whether witness commitments are required for a block, and whether to enforce NULLDUMMY (BIP 147) rules.
|
/** Check whether witness commitments are required for a block, and whether to enforce NULLDUMMY (BIP 147) rules.
|
||||||
* Note that transaction witness validation rules are always enforced when P2SH is enforced. */
|
* Note that transaction witness validation rules are always enforced when P2SH is enforced. */
|
||||||
@ -488,7 +489,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool AcceptBlockHeader(
|
bool AcceptBlockHeader(
|
||||||
const CBlockHeader& block,
|
const CBlockHeader& block,
|
||||||
CValidationState& state,
|
BlockValidationState& state,
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
};
|
};
|
||||||
@ -652,7 +653,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool FlushStateToDisk(
|
bool FlushStateToDisk(
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
CValidationState &state,
|
BlockValidationState &state,
|
||||||
FlushStateMode mode,
|
FlushStateMode mode,
|
||||||
int nManualPruneHeight = 0);
|
int nManualPruneHeight = 0);
|
||||||
|
|
||||||
@ -678,23 +679,23 @@ public:
|
|||||||
* @returns true unless a system error occurred
|
* @returns true unless a system error occurred
|
||||||
*/
|
*/
|
||||||
bool ActivateBestChain(
|
bool ActivateBestChain(
|
||||||
CValidationState& state,
|
BlockValidationState& state,
|
||||||
const CChainParams& chainparams,
|
const CChainParams& chainparams,
|
||||||
std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main);
|
std::shared_ptr<const CBlock> pblock) LOCKS_EXCLUDED(cs_main);
|
||||||
|
|
||||||
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
// Block (dis)connection on a given view:
|
// Block (dis)connection on a given view:
|
||||||
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
|
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
|
||||||
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex,
|
bool ConnectBlock(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex,
|
||||||
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
CCoinsViewCache& view, const CChainParams& chainparams, bool fJustCheck = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
// Apply the effects of a block disconnection on the UTXO set.
|
// Apply the effects of a block disconnection on the UTXO set.
|
||||||
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
|
bool DisconnectTip(BlockValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
|
||||||
|
|
||||||
// Manual block validity manipulation:
|
// Manual block validity manipulation:
|
||||||
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
bool PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
bool InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
/** Replay blocks that aren't fully applied to the database. */
|
/** Replay blocks that aren't fully applied to the database. */
|
||||||
@ -720,10 +721,10 @@ public:
|
|||||||
bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
|
bool ActivateBestChainStep(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
|
||||||
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
|
bool ConnectTip(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
|
||||||
|
|
||||||
void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void InvalidBlockFound(CBlockIndex *pindex, const BlockValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const FlatFilePos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
@ -738,10 +739,10 @@ private:
|
|||||||
* May not be called in a
|
* May not be called in a
|
||||||
* validationinterface callback.
|
* validationinterface callback.
|
||||||
*/
|
*/
|
||||||
bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main);
|
bool PreciousBlock(BlockValidationState& state, const CChainParams& params, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
|
|
||||||
/** Mark a block as invalid. */
|
/** Mark a block as invalid. */
|
||||||
bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
bool InvalidateBlock(BlockValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
|
||||||
|
|
||||||
/** Remove invalidity status from a block and its descendants. */
|
/** Remove invalidity status from a block and its descendants. */
|
||||||
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
void ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
@ -32,7 +32,7 @@ struct MainSignalsInstance {
|
|||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
|
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
|
||||||
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
|
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
|
||||||
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
||||||
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
|
boost::signals2::signal<void (const CBlock&, const BlockValidationState&)> BlockChecked;
|
||||||
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
|
||||||
|
|
||||||
// We are not allowed to assume the scheduler only runs in one thread,
|
// We are not allowed to assume the scheduler only runs in one thread,
|
||||||
@ -168,7 +168,7 @@ void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::BlockChecked(const CBlock& block, const CValidationState& state) {
|
void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
|
||||||
m_internals->BlockChecked(block, state);
|
m_internals->BlockChecked(block, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,12 +13,12 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
extern CCriticalSection cs_main;
|
extern CCriticalSection cs_main;
|
||||||
|
class BlockValidationState;
|
||||||
class CBlock;
|
class CBlock;
|
||||||
class CBlockIndex;
|
class CBlockIndex;
|
||||||
struct CBlockLocator;
|
struct CBlockLocator;
|
||||||
class CConnman;
|
class CConnman;
|
||||||
class CValidationInterface;
|
class CValidationInterface;
|
||||||
class CValidationState;
|
|
||||||
class uint256;
|
class uint256;
|
||||||
class CScheduler;
|
class CScheduler;
|
||||||
class CTxMemPool;
|
class CTxMemPool;
|
||||||
@ -134,11 +134,11 @@ protected:
|
|||||||
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
|
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
|
||||||
/**
|
/**
|
||||||
* Notifies listeners of a block validation result.
|
* Notifies listeners of a block validation result.
|
||||||
* If the provided CValidationState IsValid, the provided block
|
* If the provided BlockValidationState IsValid, the provided block
|
||||||
* is guaranteed to be the current best block at the time the
|
* is guaranteed to be the current best block at the time the
|
||||||
* callback was generated (not necessarily now)
|
* callback was generated (not necessarily now)
|
||||||
*/
|
*/
|
||||||
virtual void BlockChecked(const CBlock&, const CValidationState&) {}
|
virtual void BlockChecked(const CBlock&, const BlockValidationState&) {}
|
||||||
/**
|
/**
|
||||||
* Notifies listeners that a block which builds directly on our current tip
|
* Notifies listeners that a block which builds directly on our current tip
|
||||||
* has been received and connected to the headers tree, though not validated yet */
|
* has been received and connected to the headers tree, though not validated yet */
|
||||||
@ -180,7 +180,7 @@ public:
|
|||||||
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
|
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
|
||||||
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
|
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
|
||||||
void ChainStateFlushed(const CBlockLocator &);
|
void ChainStateFlushed(const CBlockLocator &);
|
||||||
void BlockChecked(const CBlock&, const CValidationState&);
|
void BlockChecked(const CBlock&, const BlockValidationState&);
|
||||||
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user