Skip to content

Commit 3c40bc6

Browse files
committed
Merge #15921: validation: Tidy up ValidationState interface
3004d5a [validation] Remove fMissingInputs from AcceptToMemoryPool() (John Newbery) c428622 [validation] Remove unused first_invalid parameter from ProcessNewBlockHeaders() (John Newbery) 7204c64 [validation] Remove useless ret parameter from Invalid() (John Newbery) 1a37de4 [validation] Remove error() calls from Invalid() calls (John Newbery) 067981e [validation] Tidy Up ValidationResult class (John Newbery) a27a295 [validation] Add CValidationState subclasses (John Newbery) Pull request description: Carries out some remaining tidy-ups remaining after PR 15141: - split ValidationState into TxValidationState and BlockValidationState (commit from ajtowns) - various minor code style tidy-ups to the ValidationState class - remove the useless `ret` parameter from `ValidationState::Invalid()` - remove the now unused `first_invalid` parameter from `ProcessNewBlockHeaders()` - remove the `fMissingInputs` parameter from `AcceptToMemoryPool()`, and deal with missing inputs the same way as other errors by using the `TxValidationState` object. Tip for reviewers (thanks ryanofsky!): The first commit ("[validation] Add CValidationState subclasses" ) is huge and can be easier to start reviewing if you revert the rote, mechanical changes: Substitute the commit hash of commit "[validation] Add CValidationState subclasses" for <CommitHash> in the commands below. ```sh git checkout <CommitHash> git grep -l ValidationState | xargs sed -i 's/BlockValidationState\|TxValidationState/CValidationState/g' git grep -l ValidationResult | xargs sed -i 's/BlockValidationResult\|TxValidationResult/ValidationInvalidReason/g' git grep -l MaybePunish | xargs sed -i 's/MaybePunishNode\(ForBlock\|ForTx\)/MaybePunishNode/g' git diff HEAD^ ``` After that it's possible to easily see the mechanical changes with: ```sh git log -p -n1 -U0 --word-diff-regex=. <CommitHash> ``` ACKs for top commit: laanwj: ACK 3004d5a amitiuttarwar: code review ACK 3004d5a. Also built & ran tests locally. fjahr: Code review ACK 3004d5a . Only nit style change and pure virtual destructor added since my last review. ryanofsky: Code review ACK 3004d5a. Just whitespace change and pure virtual destructor added since last review. Tree-SHA512: 511de1fb380a18bec1944ea82b513b6192df632ee08bb16344a2df3c40811a88f3872f04df24bc93a41643c96c48f376a04551840fd804a961490d6c702c3d36
2 parents cab94cc + 3004d5a commit 3c40bc6

34 files changed

+432
-409
lines changed

src/bench/block_assemble.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ static void AssembleBlock(benchmark::State& state)
3838
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
3939

4040
for (const auto& txr : txs) {
41-
CValidationState state;
42-
bool ret{::AcceptToMemoryPool(::mempool, state, txr, nullptr /* pfMissingInputs */, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
41+
TxValidationState state;
42+
bool ret{::AcceptToMemoryPool(::mempool, state, txr, nullptr /* plTxnReplaced */, false /* bypass_limits */, /* nAbsurdFee */ 0)};
4343
assert(ret);
4444
}
4545
}

src/bench/checkblock.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static void DeserializeAndCheckBlockTest(benchmark::State& state)
4242
bool rewound = stream.Rewind(benchmark::data::block413567.size());
4343
assert(rewound);
4444

45-
CValidationState validationState;
45+
BlockValidationState validationState;
4646
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus());
4747
assert(checked);
4848
}

src/bench/duplicate_inputs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static void DuplicateInputs(benchmark::State& state)
5454
block.hashMerkleRoot = BlockMerkleRoot(block);
5555

5656
while (state.KeepRunning()) {
57-
CValidationState cvstate{};
57+
BlockValidationState cvstate{};
5858
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
5959
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
6060
}

src/blockencodings.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,13 +197,13 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
197197
if (vtx_missing.size() != tx_missing_offset)
198198
return READ_STATUS_INVALID;
199199

200-
CValidationState state;
200+
BlockValidationState state;
201201
if (!CheckBlock(block, state, Params().GetConsensus())) {
202202
// TODO: We really want to just check merkle tree manually here,
203203
// but that is expensive, and CheckBlock caches a block's
204204
// "checked-status" (in the CBlock?). CBlock should be able to
205205
// check its own merkle root and cache that check.
206-
if (state.GetReason() == ValidationInvalidReason::BLOCK_MUTATED)
206+
if (state.GetResult() == BlockValidationResult::BLOCK_MUTATED)
207207
return READ_STATUS_FAILED; // Possible Short ID collision
208208
return READ_STATUS_CHECKBLOCK_FAILED;
209209
}

src/consensus/tx_check.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,28 @@
77
#include <primitives/transaction.h>
88
#include <consensus/validation.h>
99

10-
bool CheckTransaction(const CTransaction& tx, CValidationState& state)
10+
bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
1111
{
1212
// Basic checks that don't depend on any context
1313
if (tx.vin.empty())
14-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vin-empty");
14+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vin-empty");
1515
if (tx.vout.empty())
16-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-empty");
16+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-empty");
1717
// Size limits (this doesn't take the witness into account, as that hasn't been checked for malleability)
1818
if (::GetSerializeSize(tx, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
19-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-oversize");
19+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-oversize");
2020

2121
// Check for negative or overflow output values (see CVE-2010-5139)
2222
CAmount nValueOut = 0;
2323
for (const auto& txout : tx.vout)
2424
{
2525
if (txout.nValue < 0)
26-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-negative");
26+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-negative");
2727
if (txout.nValue > MAX_MONEY)
28-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-vout-toolarge");
28+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-vout-toolarge");
2929
nValueOut += txout.nValue;
3030
if (!MoneyRange(nValueOut))
31-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-txouttotal-toolarge");
31+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txouttotal-toolarge");
3232
}
3333

3434
// Check for duplicate inputs (see CVE-2018-17144)
@@ -39,19 +39,19 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
3939
std::set<COutPoint> vInOutPoints;
4040
for (const auto& txin : tx.vin) {
4141
if (!vInOutPoints.insert(txin.prevout).second)
42-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputs-duplicate");
42+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputs-duplicate");
4343
}
4444

4545
if (tx.IsCoinBase())
4646
{
4747
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
48-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-cb-length");
48+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cb-length");
4949
}
5050
else
5151
{
5252
for (const auto& txin : tx.vin)
5353
if (txin.prevout.IsNull())
54-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-prevout-null");
54+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-prevout-null");
5555
}
5656

5757
return true;

src/consensus/tx_check.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
*/
1414

1515
class CTransaction;
16-
class CValidationState;
16+
class TxValidationState;
1717

18-
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
18+
bool CheckTransaction(const CTransaction& tx, TxValidationState& state);
1919

2020
#endif // BITCOIN_CONSENSUS_TX_CHECK_H

src/consensus/tx_verify.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,11 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
156156
return nSigOps;
157157
}
158158

159-
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
159+
bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
160160
{
161161
// are the actual inputs available?
162162
if (!inputs.HaveInputs(tx)) {
163-
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent",
163+
return state.Invalid(TxValidationResult::TX_MISSING_INPUTS, "bad-txns-inputs-missingorspent",
164164
strprintf("%s: inputs missing/spent", __func__));
165165
}
166166

@@ -172,27 +172,27 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
172172

173173
// If prev is coinbase, check that it's matured
174174
if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
175-
return state.Invalid(ValidationInvalidReason::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase",
175+
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase",
176176
strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
177177
}
178178

179179
// Check for negative or overflow input values
180180
nValueIn += coin.out.nValue;
181181
if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
182-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-inputvalues-outofrange");
182+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-inputvalues-outofrange");
183183
}
184184
}
185185

186186
const CAmount value_out = tx.GetValueOut();
187187
if (nValueIn < value_out) {
188-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-in-belowout",
188+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
189189
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
190190
}
191191

192192
// Tally transaction fees
193193
const CAmount txfee_aux = nValueIn - value_out;
194194
if (!MoneyRange(txfee_aux)) {
195-
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, "bad-txns-fee-outofrange");
195+
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
196196
}
197197

198198
txfee = txfee_aux;

src/consensus/tx_verify.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
class CBlockIndex;
1414
class CCoinsViewCache;
1515
class CTransaction;
16-
class CValidationState;
16+
class TxValidationState;
1717

1818
/** Transaction validation functions */
1919

@@ -24,7 +24,7 @@ namespace Consensus {
2424
* @param[out] txfee Set to the transaction fee if successful.
2525
* Preconditions: tx.IsCoinBase() is false.
2626
*/
27-
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
27+
bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
2828
} // namespace Consensus
2929

3030
/** Auxiliary functions for transaction validation (ideally should not be exposed) */

src/consensus/validation.h

Lines changed: 91 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,22 @@
1212
#include <primitives/transaction.h>
1313
#include <primitives/block.h>
1414

15-
/** A "reason" why something was invalid, suitable for determining whether the
16-
* provider of the object should be banned/ignored/disconnected/etc.
15+
/** A "reason" why a transaction was invalid, suitable for determining whether the
16+
* provider of the transaction should be banned/ignored/disconnected/etc.
1717
*/
18-
enum class ValidationInvalidReason {
19-
// txn and blocks:
20-
NONE, //!< not actually invalid
21-
CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
18+
enum class TxValidationResult {
19+
TX_RESULT_UNSET, //!< initial value. Tx has not yet been rejected
20+
TX_CONSENSUS, //!< invalid by consensus rules
2221
/**
2322
* Invalid by a change to consensus rules more recent than SegWit.
2423
* Currently unused as there are no such consensus rule changes, and any download
2524
* sources realistically need to support SegWit in order to provide useful data,
2625
* so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
2726
* is uninteresting.
2827
*/
29-
RECENT_CONSENSUS_CHANGE,
30-
// Only blocks (or headers):
31-
CACHED_INVALID, //!< this object was cached as being invalid, but we don't know why
32-
BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
33-
BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
34-
BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
35-
BLOCK_INVALID_PREV, //!< A block this one builds on is invalid
36-
BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
37-
BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
38-
// Only loose txn:
28+
TX_RECENT_CONSENSUS_CHANGE,
3929
TX_NOT_STANDARD, //!< didn't meet our local policy rules
40-
TX_MISSING_INPUTS, //!< a transaction was missing some of its inputs
30+
TX_MISSING_INPUTS, //!< transaction was missing some of its inputs
4131
TX_PREMATURE_SPEND, //!< transaction spends a coinbase too early, or violates locktime/sequence locks
4232
/**
4333
* Transaction might be missing a witness, have a witness prior to SegWit
@@ -48,82 +38,107 @@ enum class ValidationInvalidReason {
4838
/**
4939
* Tx already in mempool or conflicts with a tx in the chain
5040
* (if it conflicts with another tx in mempool, we use MEMPOOL_POLICY as it failed to reach the RBF threshold)
51-
* TODO: Currently this is only used if the transaction already exists in the mempool or on chain,
52-
* TODO: ATMP's fMissingInputs and a valid CValidationState being used to indicate missing inputs
41+
* Currently this is only used if the transaction already exists in the mempool or on chain.
5342
*/
5443
TX_CONFLICT,
5544
TX_MEMPOOL_POLICY, //!< violated mempool's fee/size/descendant/RBF/etc limits
5645
};
5746

58-
inline bool IsTransactionReason(ValidationInvalidReason r)
59-
{
60-
return r == ValidationInvalidReason::NONE ||
61-
r == ValidationInvalidReason::CONSENSUS ||
62-
r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
63-
r == ValidationInvalidReason::TX_NOT_STANDARD ||
64-
r == ValidationInvalidReason::TX_PREMATURE_SPEND ||
65-
r == ValidationInvalidReason::TX_MISSING_INPUTS ||
66-
r == ValidationInvalidReason::TX_WITNESS_MUTATED ||
67-
r == ValidationInvalidReason::TX_CONFLICT ||
68-
r == ValidationInvalidReason::TX_MEMPOOL_POLICY;
69-
}
47+
/** A "reason" why a block was invalid, suitable for determining whether the
48+
* provider of the block should be banned/ignored/disconnected/etc.
49+
* These are much more granular than the rejection codes, which may be more
50+
* useful for some other use-cases.
51+
*/
52+
enum class BlockValidationResult {
53+
BLOCK_RESULT_UNSET, //!< initial value. Block has not yet been rejected
54+
BLOCK_CONSENSUS, //!< invalid by consensus rules (excluding any below reasons)
55+
/**
56+
* Invalid by a change to consensus rules more recent than SegWit.
57+
* Currently unused as there are no such consensus rule changes, and any download
58+
* sources realistically need to support SegWit in order to provide useful data,
59+
* so differentiating between always-invalid and invalid-by-pre-SegWit-soft-fork
60+
* is uninteresting.
61+
*/
62+
BLOCK_RECENT_CONSENSUS_CHANGE,
63+
BLOCK_CACHED_INVALID, //!< this block was cached as being invalid and we didn't store the reason why
64+
BLOCK_INVALID_HEADER, //!< invalid proof of work or time too old
65+
BLOCK_MUTATED, //!< the block's data didn't match the data committed to by the PoW
66+
BLOCK_MISSING_PREV, //!< We don't have the previous block the checked one is built on
67+
BLOCK_INVALID_PREV, //!< A block this one builds on is invalid
68+
BLOCK_TIME_FUTURE, //!< block timestamp was > 2 hours in the future (or our clock is bad)
69+
BLOCK_CHECKPOINT, //!< the block failed to meet one of our checkpoints
70+
};
7071

71-
inline bool IsBlockReason(ValidationInvalidReason r)
72-
{
73-
return r == ValidationInvalidReason::NONE ||
74-
r == ValidationInvalidReason::CONSENSUS ||
75-
r == ValidationInvalidReason::RECENT_CONSENSUS_CHANGE ||
76-
r == ValidationInvalidReason::CACHED_INVALID ||
77-
r == ValidationInvalidReason::BLOCK_INVALID_HEADER ||
78-
r == ValidationInvalidReason::BLOCK_MUTATED ||
79-
r == ValidationInvalidReason::BLOCK_MISSING_PREV ||
80-
r == ValidationInvalidReason::BLOCK_INVALID_PREV ||
81-
r == ValidationInvalidReason::BLOCK_TIME_FUTURE ||
82-
r == ValidationInvalidReason::BLOCK_CHECKPOINT;
83-
}
8472

85-
/** Capture information about block/transaction validation */
86-
class CValidationState {
73+
74+
/** Base class for capturing information about block/transaction validation. This is subclassed
75+
* by TxValidationState and BlockValidationState for validation information on transactions
76+
* and blocks respectively. */
77+
class ValidationState {
8778
private:
8879
enum mode_state {
8980
MODE_VALID, //!< everything ok
9081
MODE_INVALID, //!< network rule violation (DoS value may be set)
9182
MODE_ERROR, //!< run-time error
92-
} mode;
93-
ValidationInvalidReason m_reason;
94-
std::string strRejectReason;
95-
std::string strDebugMessage;
96-
public:
97-
CValidationState() : mode(MODE_VALID), m_reason(ValidationInvalidReason::NONE) {}
98-
bool Invalid(ValidationInvalidReason reasonIn, bool ret = false,
99-
const std::string &strRejectReasonIn="",
100-
const std::string &strDebugMessageIn="") {
101-
m_reason = reasonIn;
102-
strRejectReason = strRejectReasonIn;
103-
strDebugMessage = strDebugMessageIn;
104-
if (mode == MODE_ERROR)
105-
return ret;
106-
mode = MODE_INVALID;
107-
return ret;
83+
} m_mode;
84+
std::string m_reject_reason;
85+
std::string m_debug_message;
86+
protected:
87+
void Invalid(const std::string &reject_reason="",
88+
const std::string &debug_message="")
89+
{
90+
m_reject_reason = reject_reason;
91+
m_debug_message = debug_message;
92+
if (m_mode != MODE_ERROR) m_mode = MODE_INVALID;
10893
}
109-
bool Error(const std::string& strRejectReasonIn) {
110-
if (mode == MODE_VALID)
111-
strRejectReason = strRejectReasonIn;
112-
mode = MODE_ERROR;
94+
public:
95+
// ValidationState is abstract. Have a pure virtual destructor.
96+
virtual ~ValidationState() = 0;
97+
98+
ValidationState() : m_mode(MODE_VALID) {}
99+
bool Error(const std::string& reject_reason)
100+
{
101+
if (m_mode == MODE_VALID)
102+
m_reject_reason = reject_reason;
103+
m_mode = MODE_ERROR;
113104
return false;
114105
}
115-
bool IsValid() const {
116-
return mode == MODE_VALID;
117-
}
118-
bool IsInvalid() const {
119-
return mode == MODE_INVALID;
106+
bool IsValid() const { return m_mode == MODE_VALID; }
107+
bool IsInvalid() const { return m_mode == MODE_INVALID; }
108+
bool IsError() const { return m_mode == MODE_ERROR; }
109+
std::string GetRejectReason() const { return m_reject_reason; }
110+
std::string GetDebugMessage() const { return m_debug_message; }
111+
};
112+
113+
inline ValidationState::~ValidationState() {};
114+
115+
class TxValidationState : public ValidationState {
116+
private:
117+
TxValidationResult m_result;
118+
public:
119+
bool Invalid(TxValidationResult result,
120+
const std::string &reject_reason="",
121+
const std::string &debug_message="")
122+
{
123+
m_result = result;
124+
ValidationState::Invalid(reject_reason, debug_message);
125+
return false;
120126
}
121-
bool IsError() const {
122-
return mode == MODE_ERROR;
127+
TxValidationResult GetResult() const { return m_result; }
128+
};
129+
130+
class BlockValidationState : public ValidationState {
131+
private:
132+
BlockValidationResult m_result;
133+
public:
134+
bool Invalid(BlockValidationResult result,
135+
const std::string &reject_reason="",
136+
const std::string &debug_message="") {
137+
m_result = result;
138+
ValidationState::Invalid(reject_reason, debug_message);
139+
return false;
123140
}
124-
ValidationInvalidReason GetReason() const { return m_reason; }
125-
std::string GetRejectReason() const { return strRejectReason; }
126-
std::string GetDebugMessage() const { return strDebugMessage; }
141+
BlockValidationResult GetResult() const { return m_result; }
127142
};
128143

129144
// These implement the weight = (stripped_size * 4) + witness_size formula,

src/init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ static void ThreadImport(std::vector<fs::path> vImportFiles)
710710
}
711711

712712
// scan for better chains in the block chain database, that are not yet connected in the active best chain
713-
CValidationState state;
713+
BlockValidationState state;
714714
if (!ActivateBestChain(state, chainparams)) {
715715
LogPrintf("Failed to connect best block (%s)\n", FormatStateMessage(state));
716716
StartShutdown();

0 commit comments

Comments
 (0)