Skip to content

Instantly share code, notes, and snippets.

@jonatack
Last active October 30, 2019 18:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonatack/3d268e1e8fc8f095925bd2a523bf9306 to your computer and use it in GitHub Desktop.
Save jonatack/3d268e1e8fc8f095925bd2a523bf9306 to your computer and use it in GitHub Desktop.
~/projects/bitcoin/bitcoin ((HEAD detached at a27a2957ed))$ git log -p -n1 -U0 --word-diff-regex=. a27a2957ed9afbe5a96caa5f0f4cbec730d27460
commit a27a2957ed9afbe5a96caa5f0f4cbec730d27460 (HEAD)
Author: John Newbery <john@johnnewbery.com>
Date:   Thu Oct 24 11:35:42 2019 -0400

    [validation] Add CValidationState subclasses
    
    Split CValidationState into TxValidationState and BlockValidationState
    to store validation results for transactions and blocks respectively.

diff --git a/src/bench/block_assemble.cpp b/src/bench/block_assemble.cpp
index 157f936a95..a3a44e5dbc 100644
--- a/src/bench/block_assemble.cpp
+++ b/src/bench/block_assemble.cpp
@@ -41 +41 @@ static void AssembleBlock(benchmark::State& state)
            [-C-]{+Tx+}ValidationState state;
diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp
index 4b13381e16..edf43bd4dc 100644
--- a/src/bench/checkblock.cpp
+++ b/src/bench/checkblock.cpp
@@ -45 +45 @@ static void DeserializeAndCheckBlockTest(benchmark::State& state)
        [-C-]{+Block+}ValidationState validationState;
diff --git a/src/bench/duplicate_inputs.cpp b/src/bench/duplicate_inputs.cpp
index 6cfa3750d6..a783370b4e 100644
--- a/src/bench/duplicate_inputs.cpp
+++ b/src/bench/duplicate_inputs.cpp
@@ -57 +57 @@ static void DuplicateInputs(benchmark::State& state)
        [-C-]{+Block+}ValidationState cvstate{};
diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp
index f0fcf675eb..bf13297582 100644
--- a/src/blockencodings.cpp
+++ b/src/blockencodings.cpp
@@ -200 +200 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
    [-C-]{+Block+}ValidationState state;
@@ -206 +206 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
        if (state.GetRe[-a-]s[-on-]{+ult+}() == {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED)
diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp
index 6793f871cf..a9d5cec4ac 100644
--- a/src/consensus/tx_check.cpp
+++ b/src/consensus/tx_check.cpp
@@ -10 +10 @@
bool CheckTransaction(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state)
@@ -14 +14 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-vin-empty");
@@ -16 +16 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-vout-empty");
@@ -19 +19 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-oversize");
@@ -26 +26 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-vout-negative");
@@ -28 +28 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-vout-toolarge");
@@ -31 +31 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-txouttotal-toolarge");
@@ -42 +42 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-inputs-duplicate");
@@ -48 +48 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-cb-length");
@@ -54 +54 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state)
                return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-prevout-null");
diff --git a/src/consensus/tx_check.h b/src/consensus/tx_check.h
index 6f3f8fe969..b818a284f1 100644
--- a/src/consensus/tx_check.h
+++ b/src/consensus/tx_check.h
@@ -16 +16 @@ class CTransaction;
class [-C-]{+Tx+}ValidationState;
@@ -18 +18 @@ class CValidationState;
bool CheckTransaction(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state);
diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp
index ceeddc3f6d..47242aae93 100644
--- a/src/consensus/tx_verify.cpp
+++ b/src/consensus/tx_verify.cpp
@@ -159 +159 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
bool Consensus::CheckTxInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
@@ -163 +163 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent",
@@ -175 +175 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase",
@@ -182 +182 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-inputvalues-outofrange");
@@ -188 +188 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-in-belowout",
@@ -195 +195 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-fee-outofrange");
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index 3519fc555d..b6599f2878 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -16 +16 @@ class CTransaction;
class [-C-]{+Tx+}ValidationState;
@@ -27 +27 @@ namespace Consensus {
bool CheckTxInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 4920cdf881..c285817c0d 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -15,2 +15,2 @@
/** A "reason" why {+a tran+}s[-ome-]{+ac+}t[-h-]i{+o+}n[-g-] was invalid, suitable for determining whether the
  * provider of the [-obje-]{+transa+}ct{+ion+} should be banned/ignored/disconnected/etc.
@@ -18,4 +18,3 @@
enum class {+Tx+}Validation[-Invalid-]Re[-a-]s[-on {-]
[-    // -]{+ul+}t[-xn-] [-and blocks:-]{+{+}
    {+TX_RESULT_U+}N[-ON-]{+S+}E{+T+},         [-           -]//!< {+i+}n[-o-]{+i+}t{+ial+} {+v+}a[-ct-]{+l+}u{+e. Tx h+}a[-ll-]{+s not +}y{+et+} [-i-]{+bee+}n[-vali-]{+ rejecte+}d
    {+TX_+}CONSENSUS,            [-   -]//!< invalid by consensus rules[- (excluding any below reasons)-]
@@ -29,10 +28 @@ enum class ValidationInvalidReason {
    {+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:-]
@@ -40 +30,6 @@ enum class ValidationInvalidReason {
    [-TX_MISSING_INPUTS,  -]{+/**+}
     [- //!< a-]{+*+} 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,+}
@@ -51,2 +46 @@ enum class ValidationInvalidReason {
     * [-TODO: -]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-]{+.+}
@@ -58,12 +52,25 @@ enum class ValidationInvalidReason {
[-inline-]{+/**+} [-bool-]{+A+} [-IsT-]{+"+}r[-ansactionR-]eason[-(V-]{+" why +}a{+ b+}l[-id-]{+ock w+}a[-t-]{+s +}i[-onI-]nvalid[-Rea-]{+, +}s{+uitable f+}o{+r determini+}n{+g+} {+whethe+}r[-)-]
[-{-] {+the+}
  {+*+} {+p+}r{+ovid+}e[-tu-]r[-n-] [-r-]{+of the+} [-==-]{+block+} [-Va-]{+shou+}l[-i-]d{+ be b+}a[-tio-]n[-I-]n[-vali-]{+e+}d[-R-]{+/ignor+}e[-a-]{+d/di+}s{+c+}on[-::NONE ||-]
[-     -]{+nected/etc.+}
  {+*+} {+These+} {+are+} {+much+} {+mo+}r{+e+} [-== V-]{+gr+}a{+nu+}l[-id-]a{+r than the rejec+}tion[-Invali-]{+ co+}d[-R-]e[-a-]s[-on::CONSENSUS-]{+,+} [-||-]{+which may+} {+be+} {+more+}
  {+*+} {+useful+} {+for+} {+some+} {+other+} {+use-cases.+}
  [-r-]{+*/+}
{+enum+} [-==-]{+class+} {+Block+}Validation[-Invalid-]Re[-a-]s[-on::RE-]{+ult {+}
{+    BLO+}C{+K_R+}E[-NT_CONSEN-]SU[-S-]{+LT+}_[-CHA-]{+U+}N[-G-]{+S+}E[- ||-]
[-      -]{+T,+}     [-r-] [-==-]{+//!<+} [-Val-]i[-da-]{+ni+}ti[-onIn-]{+al +}val[-idR-]{+u+}e{+. Block h+}as{+ n+}o{+t yet bee+}n[-::TX_N-]{+ rejected+}
{+    BL+}O[-T-]{+CK+}_{+CON+}S[-TA-]{+E+}N[-DARD-]{+SUS, +} [-||-]       {+//!<+} {+invalid+} {+by+} {+co:
+++ b/src/consensus/tx_verify.cpp
@@ -159 +159 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
bool Consensus::CheckTxInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
@@ -163 +163 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent",
@@ -175 +175 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase",
@@ -182 +182 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-inputvalues-outofrange");
@@ -188 +188 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-in-belowout",
@@ -195 +195 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-fee-outofrange");
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index 3519fc555d..b6599f2878 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -16 +16 @@ class CTransaction;
class [-C-]{+Tx+}ValidationState;
@@ -27 +27 @@ namespace Consensus {
bool CheckTxInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 4920cdf881..c285817c0d 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -15,2 +15,2 @@
/** A "reason" why {+a tran+}s[-ome-]{+ac+}t[-h-]i{+o+}n[-g-] was invalid, suitable for determining whether the
  * provider of the [-obje-]{+transa+}ct{+ion+} should be banned/ignored/disconnected/etc.
@@ -18,4 +18,3 @@
enum class {+Tx+}Validation[-Invalid-]Re[-a-]s[-on {-]
[-    // -]{+ul+}t[-xn-] [-and blocks:-]{+{+}
    {+TX_RESULT_U+}N[-ON-]{+S+}E{+T+},         [-           -]//!< {+i+}n[-o-]{+i+}t{+ial+} {+v+}a[-ct-]{+l+}u{+e. Tx h+}a[-ll-]{+s not +}y{+et+} [-i-]{+bee+}n[-vali-]{+ rejecte+}d
    {+TX_+}CONSENSUS,            [-   -]//!< invalid by consensus rules[- (excluding any below reasons)-]
@@ -29,10 +28 @@ enum class ValidationInvalidReason {
    {+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:-]
@@ -40 +30,6 @@ enum class ValidationInvalidReason {
    [-TX_MISSING_INPUTS,  -]{+/**+}
     [- //!< a-]{+*+} 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,+}
@@ -51,2 +46 @@ enum class ValidationInvalidReason {
     * [-TODO: -]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-]{+.+}
@@ -58,12 +52,25 @@ enum class ValidationInvalidReason {
[-inline-]{+/**+} [-bool-]{+A+} [-IsT-]{+"+}r[-ansactionR-]eason[-(V-]{+" why +}a{+ b+}l[-id-]{+ock w+}a[-t-]{+s +}i[-onI-]nvalid[-Rea-]{+, +}s{+uitable f+}o{+r determini+}n{+g+} {+whethe+}r[-)-]
[-{-] {+the+}
  {+*+} {+p+}r{+ovid+}e[-tu-]r[-n-] [-r-]{+of the+} [-==-]{+block+} [-Va-]{+shou+}l[-i-]d{+ be b+}a[-tio-]n[-I-]n[-vali-]{+e+}d[-R-]{+/ignor+}e[-a-]{+d/di+}s{+c+}on[-::NONE ||-]
[-     -]{+nected/etc.+}
  {+*+} {+These+} {+are+} {+much+} {+mo+}r{+e+} [-== V-]{+gr+}a{+nu+}l[-id-]a{+r than the rejec+}tion[-Invali-]{+ co+}d[-R-]e[-a-]s[-on::CONSENSUS-]{+,+} [-||-]{+which may+} {+be+} {+more+}
  {+*+} {+useful+} {+for+} {+some+} {+other+} {+use-cases.+}
  [-r-]{+*/+}
{+enum+} [-==-]{+class+} {+Block+}Validation[-Invalid-]Re[-a-]s[-on::RE-]{+ult {+}
{+    BLO+}C{+K_R+}E[-NT_CONSEN-]SU[-S-]{+LT+}_[-CHA-]{+U+}N[-G-]{+S+}E[- ||-]
[-      -]{+T,+}     [-r-] [-==-]{+//!<+} [-Val-]i[-da-]{+ni+}ti[-onIn-]{+al +}val[-idR-]{+u+}e{+. Block h+}as{+ n+}o{+t yet bee+}n[-::TX_N-]{+ rejected+}
{+    BL+}O[-T-]{+CK+}_{+CON+}S[-TA-]{+E+}N[-DARD-]{+SUS, +} [-||-]       {+//!<+} {+invalid+} {+by+} {+consensus+} r{+ules+} [-== Va-]{+(exc+}l[-i-]{+u+}d[-at-]i[-o-]n[-Inv-]{+g +}a{+ny be+}l[-idR-]{+ow r+}eason[-::TX_PREMATURE_SPEND ||-]
[-   -]{+s)+}
    {+/**+}
    [-r-] [-==-]{+*+} [-V-]{+Inv+}alid{+ by a ch+}a{+nge +}t[-i-]{+o c+}on[-I-]{+se+}n[-va-]{+sus ru+}l[-idR-]e[-a-]s{+ m+}o{+re rece+}n[-::TX_MISSING_INPUTS-]{+t+} [-||-]{+than+} {+SegWit.+}
     {+*+} {+Currently+} {+unused+} {+as+} {+there+} {+a+}r{+e+} [-==-]{+no+} [-Valid-]{+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 h+}a{+ve +}t{+he prev+}io[-nInva-]{+us b+}l[-i-]{+ock the checke+}d[-R-]{+ on+}e[-a-]{+ i+}s{+ built +}on
[-::TX-]{+    BLOCK+}_[-W-]I[-T-]N[-ESS_MUT-]{+V+}A[-TE-]{+LI+}D[- ||-]
[-  -]{+_PREV,+}      {+//!<+} {+A+} {+block+} [-r-]{+this+} [-==-]{+one+} [-Val-]{+bu+}i{+l+}d[-ati-]{+s +}on[-I-]{+ is i+}nvalid
{+    BLOCK_TIME_FUTU+}R{+E,       //!< block tim+}e{+stamp w+}as{+ > 2 h+}o{+urs i+}n[-::TX-]{+ the future (or our clock is bad)+}
:
+++ b/src/consensus/tx_verify.cpp
@@ -159 +159 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
bool Consensus::CheckTxInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
@@ -163 +163 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MISSING_INPUTS, false, "bad-txns-inputs-missingorspent",
@@ -175 +175 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_PREMATURE_SPEND, false, "bad-txns-premature-spend-of-coinbase",
@@ -182 +182 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-inputvalues-outofrange");
@@ -188 +188 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-in-belowout",
@@ -195 +195 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-fee-outofrange");
diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h
index 3519fc555d..b6599f2878 100644
--- a/src/consensus/tx_verify.h
+++ b/src/consensus/tx_verify.h
@@ -16 +16 @@ class CTransaction;
class [-C-]{+Tx+}ValidationState;
@@ -27 +27 @@ namespace Consensus {
bool CheckTxInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
index 4920cdf881..c285817c0d 100644
--- a/src/consensus/validation.h
+++ b/src/consensus/validation.h
@@ -15,2 +15,2 @@
/** A "reason" why {+a tran+}s[-ome-]{+ac+}t[-h-]i{+o+}n[-g-] was invalid, suitable for determining whether the
  * provider of the [-obje-]{+transa+}ct{+ion+} should be banned/ignored/disconnected/etc.
@@ -18,4 +18,3 @@
enum class {+Tx+}Validation[-Invalid-]Re[-a-]s[-on {-]
[-    // -]{+ul+}t[-xn-] [-and blocks:-]{+{+}
    {+TX_RESULT_U+}N[-ON-]{+S+}E{+T+},         [-           -]//!< {+i+}n[-o-]{+i+}t{+ial+} {+v+}a[-ct-]{+l+}u{+e. Tx h+}a[-ll-]{+s not +}y{+et+} [-i-]{+bee+}n[-vali-]{+ rejecte+}d
    {+TX_+}CONSENSUS,            [-   -]//!< invalid by consensus rules[- (excluding any below reasons)-]
@@ -29,10 +28 @@ enum class ValidationInvalidReason {
    {+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:-]
@@ -40 +30,6 @@ enum class ValidationInvalidReason {
    [-TX_MISSING_INPUTS,  -]{+/**+}
     [- //!< a-]{+*+} 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,+}
@@ -51,2 +46 @@ enum class ValidationInvalidReason {
     * [-TODO: -]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-]{+.+}
@@ -58,12 +52,25 @@ enum class ValidationInvalidReason {
[-inline-]{+/**+} [-bool-]{+A+} [-IsT-]{+"+}r[-ansactionR-]eason[-(V-]{+" why +}a{+ b+}l[-id-]{+ock w+}a[-t-]{+s +}i[-onI-]nvalid[-Rea-]{+, +}s{+uitable f+}o{+r determini+}n{+g+} {+whethe+}r[-)-]
[-{-] {+the+}
  {+*+} {+p+}r{+ovid+}e[-tu-]r[-n-] [-r-]{+of the+} [-==-]{+block+} [-Va-]{+shou+}l[-i-]d{+ be b+}a[-tio-]n[-I-]n[-vali-]{+e+}d[-R-]{+/ignor+}e[-a-]{+d/di+}s{+c+}on[-::NONE ||-]
[-     -]{+nected/etc.+}
  {+*+} {+These+} {+are+} {+much+} {+mo+}r{+e+} [-== V-]{+gr+}a{+nu+}l[-id-]a{+r than the rejec+}tion[-Invali-]{+ co+}d[-R-]e[-a-]s[-on::CONSENSUS-]{+,+} [-||-]{+which may+} {+be+} {+more+}
  {+*+} {+useful+} {+for+} {+some+} {+other+} {+use-cases.+}
  [-r-]{+*/+}
{+enum+} [-==-]{+class+} {+Block+}Validation[-Invalid-]Re[-a-]s[-on::RE-]{+ult {+}
{+    BLO+}C{+K_R+}E[-NT_CONSEN-]SU[-S-]{+LT+}_[-CHA-]{+U+}N[-G-]{+S+}E[- ||-]
[-      -]{+T,+}     [-r-] [-==-]{+//!<+} [-Val-]i[-da-]{+ni+}ti[-onIn-]{+al +}val[-idR-]{+u+}e{+. Block h+}as{+ n+}o{+t yet bee+}n[-::TX_N-]{+ rejected+}
{+    BL+}O[-T-]{+CK+}_{+CON+}S[-TA-]{+E+}N[-DARD-]{+SUS, +} [-||-]       {+//!<+} {+invalid+} {+by+} {+consensus+} r{+ules+} [-== Va-]{+(exc+}l[-i-]{+u+}d[-at-]i[-o-]n[-Inv-]{+g +}a{+ny be+}l[-idR-]{+ow r+}eason[-::TX_PREMATURE_SPEND ||-]
[-   -]{+s)+}
    {+/**+}
    [-r-] [-==-]{+*+} [-V-]{+Inv+}alid{+ by a ch+}a{+nge +}t[-i-]{+o c+}on[-I-]{+se+}n[-va-]{+sus ru+}l[-idR-]e[-a-]s{+ m+}o{+re rece+}n[-::TX_MISSING_INPUTS-]{+t+} [-||-]{+than+} {+SegWit.+}
     {+*+} {+Currently+} {+unused+} {+as+} {+there+} {+a+}r{+e+} [-==-]{+no+} [-Valid-]{+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 h+}a{+ve +}t{+he prev+}io[-nInva-]{+us b+}l[-i-]{+ock the checke+}d[-R-]{+ on+}e[-a-]{+ i+}s{+ built +}on
[-::TX-]{+    BLOCK+}_[-W-]I[-T-]N[-ESS_MUT-]{+V+}A[-TE-]{+LI+}D[- ||-]
[-  -]{+_PREV,+}      {+//!<+} {+A+} {+block+} [-r-]{+this+} [-==-]{+one+} [-Val-]{+bu+}i{+l+}d[-ati-]{+s +}on[-I-]{+ is i+}nvalid
{+    BLOCK_TIME_FUTU+}R{+E,       //!< block tim+}e{+stamp w+}as{+ > 2 h+}o{+urs i+}n[-::TX-]{+ the future (or our clock is bad)+}
{+    BLOCK+}_C{+HECKP+}O[-NFL-]I[-C-]{+N+}T[- ||-]
[-  -]{+,+}        {+//!<+} [-r-]{+the+} [-==-]{+block+} [-V-]{+f+}a[-l-]i{+le+}d[-a-]{+ +}t[-i-]{+o meet +}on[-InvalidR-]e[-as-]{+ of our checkp+}o{+i+}n[-::TX_MEMPOOL_POLICY;-]{+ts+}
}{+;+}

@@ -71,13 +77,0 @@ inline bool IsTransactionReason(ValidationInvalidReason r)
[-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;-]
[-}-]
@@ -85,2 +79,4 @@ inline bool IsBlockReason(ValidationInvalidReason r)
/** [-C-]{+Base class for c+}aptur[-e-]{+ing+} information about block/transaction validation{+. This is subclassed+}
{+ *  by TxValidationState and BlockValidationState for validation information on transactions+}
{+ *  and blocks respectively.+} */
class [-C-]ValidationState {
@@ -93 +88,0 @@ private:
[-    ValidationInvalidReason m_reason;-]
@@ -96,3 +91,2 @@ private:
p[-ublic:-]
[-    CValidati-]{+r+}o[-nSta-]te[-() : mode(MODE_VALID), m_reason(Valida-]{+c+}t[-ionInvalidR-]e[-ason:-]{+d+}:[-NONE) {}-]
    bool Invalid([-ValidationInvalidReason reasonIn, -]bool ret = false,
@@ -101 +94,0 @@ public:
[-        m_reason = reasonIn;-]
@@ -108,0 +102,5 @@ public:
{+public:+}
{+    // ValidationState is abstract. Have a pure virtual destructor.+}
{+    virtual ~ValidationState() = 0;+}

{+    ValidationState() : mode(MODE_VALID) {}+}
@@ -124 +121,0 @@ public:
[-    ValidationInvalidReason GetReason() const { return m_reason; }-]
@@ -128,0 +126,28 @@ public:
{+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; }+}
{+};+}

diff --git a/src/init.cpp b/src/init.cpp
index 035725b090..01faf8f6c0 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -715 +715 @@ static void ThreadImport(std::vector<fs::path> vImportFiles)
    [-C-]{+Block+}ValidationState state;
diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h
index 73a78e21fb..d54a14022c 100644
--- a/src/interfaces/chain.h
+++ b/src/interfaces/chain.h
@@ -21 +20,0 @@ class CScheduler;
[-class CValidationState;-]
diff --git a/src/miner.cpp b/src/miner.cpp
index 4f51be8a08..1c9174ee07 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -165 +165 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
    [-C-]{+Block+}ValidationState state;
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 4a3076e3c7..38d0461b1f 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -985,4 +985,2 @@ void Misbehaving(NodeId pnode, int howmuch, const std::string& message) EXCLUSIV
static bool TxRelayMayResultInDisconnect(const [-C-]{+Tx+}ValidationState& state)[-{-]
[- -] [-  assert(IsTransactionReason(state.GetReason()));-]{+{+}
    return state.GetRe[-a-]s[-on-]{+ult+}() == {+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS;
@@ -992 +990 @@ static bool TxRelayMayResultInDisconnect(const CValidationState& state)
 * Potentially ban a node based on the contents of a [-C-]{+Block+}ValidationState object
@@ -1000,2 +997,0 @@ static bool TxRelayMayResultInDisconnect(const CValidationState& state)
[- *-]
[- * Changes here may need to be reflected in TxRelayMayResultInDisconnect().-]
@@ -1003,3 +999,3 @@ static bool TxRelayMayResultInDisconnect(const CValidationState& state)
static bool MaybePunishNode{+ForBlock+}(NodeId nodeid, const [-C-]{+Block+}ValidationState& state, bool via_compact_block, const std::string& message = "") {
    switch (state.GetRe[-a-]s[-on-]{+ult+}()) {
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::[-N-]{+BL+}O{+CK_RESULT_U+}N{+S+}E{+T+}:
@@ -1008,2 +1004,2 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS:
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED:
@@ -1016 +1012 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CACHED_INVALID:
@@ -1032,3 +1028,3 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_INVALID_HEADER:
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_CHECKPOINT:
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_INVALID_PREV:
@@ -1041 +1037 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MISSING_PREV:
@@ -1048,8 +1044,2 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}RECENT_CONSENSUS_CHANGE:
    case {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::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:-]
@@ -1063,0 +1054,33 @@ static bool MaybePunishNode(NodeId nodeid, const CValidationState& state, bool v
{+/**+}
{+ * 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;+}
{+}+}
@@ -1232 +1255 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB
void PeerLogicValidation::BlockChecked(const CBlock& block, const [-C-]{+Block+}ValidationState& state) {
@@ -1243 +1266 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
            MaybePunishNode{+ForBlock+}(/*nodeid=*/ it->second.first, state, /*via_compact_block=*/ !it->second.second);
@@ -1381 +1404 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
        [-C-]{+Block+}ValidationState state;
@@ -1677 +1700 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
    [-C-]{+Block+}ValidationState state;
@@ -1681 +1704 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve
            MaybePunishNode{+ForBlock+}(pfrom->GetId(), state, via_compact_block, "invalid header received");
@@ -1818,2 +1841,2 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
        // Use a new [-C-]{+Tx+}ValidationState because orphans come from different peers (and we call
        // MaybePunishNode{+ForTx+} based on the source peer from the orphan map, not based on the peer
@@ -1821 +1844 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
        [-C-]{+Tx+}ValidationState orphan_state;
@@ -1840 +1863 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
                if (MaybePunishNode{+ForTx+}(fromPeer, orphan_state[-, /*via_compact_block*/ false-])) {
@@ -1848,2 +1871 @@ void static ProcessOrphanTx(CConnman* connman, std::set<uint256>& orphan_work_se
            [-assert(IsTransactionReason(orphan_state.GetReason()));-]
[-            -]if (!orphanTx.HasWitness() && orphan_state.GetRe[-a-]s[-on-]{+ult+}() != {+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_WITNESS_MUTATED) {
@@ -2294 +2316 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
            [-C-]{+Block+}ValidationState state;
@@ -2475 +2497 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
        [-C-]{+Tx+}ValidationState state;
@@ -2540,2 +2562 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
            [-assert(IsTransactionReason(state.GetReason()));-]
[-            -]if (!tx.HasWitness() && state.GetRe[-a-]s[-on-]{+ult+}() != {+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_WITNESS_MUTATED) {
@@ -2596 +2617 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
            MaybePunishNode{+ForTx+}(pfrom->GetId(), state[-, /*via_compact_block*/ false-]);
@@ -2630 +2651 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
        [-C-]{+Block+}ValidationState state;
@@ -2633 +2654 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
                MaybePunishNode{+ForBlock+}(pfrom->GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
diff --git a/src/net_processing.h b/src/net_processing.h
index e8bc3580dd..4adb7d3a21 100644
--- a/src/net_processing.h
+++ b/src/net_processing.h
@@ -43 +43 @@ public:
    void BlockChecked(const CBlock& block, const [-C-]{+Block+}ValidationState& state) override;
diff --git a/src/node/transaction.cpp b/src/node/transaction.cpp
index 7783671a6c..4645baa3d7 100644
--- a/src/node/transaction.cpp
+++ b/src/node/transaction.cpp
@@ -39 +39 @@ TransactionError BroadcastTransaction(const CTransactionRef tx, std::string& err
        [-C-]{+Tx+}ValidationState state;
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp
index 4bbd4aaf64..c4ce561fe3 100644
--- a/src/rpc/blockchain.cpp
+++ b/src/rpc/blockchain.cpp
@@ -1473 +1473 @@ static UniValue preciousblock(const JSONRPCRequest& request)
    [-C-]{+Block+}ValidationState state;
@@ -1498 +1498 @@ static UniValue invalidateblock(const JSONRPCRequest& request)
    [-C-]{+Block+}ValidationState state;
@@ -1548 +1548 @@ static UniValue reconsiderblock(const JSONRPCRequest& request)
    [-C-]{+Block+}ValidationState state;
diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp
index 07c2958635..f294c815f6 100644
--- a/src/rpc/mining.cpp
+++ b/src/rpc/mining.cpp
@@ -255 +255 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
static UniValue BIP22ValidationResult(const [-C-]{+Block+}ValidationState& state)
@@ -404 +404 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
            [-C-]{+Block+}ValidationState state;
@@ -671 +671 @@ public:
    [-C-]{+Block+}ValidationState state;
@@ -676 +676 @@ protected:
    void BlockChecked(const CBlock& block, const [-C-]{+Block+}ValidationState& stateIn) override {
@@ -775 +775 @@ static UniValue submitheader(const JSONRPCRequest& request)
    [-C-]{+Block+}ValidationState state;
diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp
index cdcf0c9971..68024fbe2f 100644
--- a/src/rpc/rawtransaction.cpp
+++ b/src/rpc/rawtransaction.cpp
@@ -896 +896 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
    [-C-]{+Tx+}ValidationState state;
diff --git a/src/test/blockfilter_index_tests.cpp b/src/test/blockfilter_index_tests.cpp
index ba293b7836..2e40ed0dde 100644
--- a/src/test/blockfilter_index_tests.cpp
+++ b/src/test/blockfilter_index_tests.cpp
@@ -105 +105 @@ static bool BuildChain(const CBlockIndex* pindex, const CScript& coinbase_script
        [-C-]{+Block+}ValidationState state;
diff --git a/src/test/fuzz/transaction.cpp b/src/test/fuzz/transaction.cpp
index 383d879040..76b230ef3c 100644
--- a/src/test/fuzz/transaction.cpp
+++ b/src/test/fuzz/transaction.cpp
@@ -45 +45 @@ void test_one_input(const std::vector<uint8_t>& buffer)
    [-C-]{+Tx+}ValidationState state_with_dupe_check;
diff --git a/src/test/setup_common.cpp b/src/test/setup_common.cpp
index bbdf1ef830..d83668460f 100644
--- a/src/test/setup_common.cpp
+++ b/src/test/setup_common.cpp
@@ -98 +98 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
    [-C-]{+Block+}ValidationState state;
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index 15f8db899b..b18f9df72d 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -196 +196 @@ BOOST_AUTO_TEST_CASE(sighash_from_data)
          [-C-]{+Tx+}ValidationState state;
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 34192c6b6a..dac46879e8 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -155 +155 @@ BOOST_AUTO_TEST_CASE(tx_valid)
            [-C-]{+Tx+}ValidationState state;
@@ -242 +242 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
            [-C-]{+Tx+}ValidationState state;
@@ -277 +277 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
    [-C-]{+Tx+}ValidationState state;
diff --git a/src/test/txvalidation_tests.cpp b/src/test/txvalidation_tests.cpp
index 2356e0ccdc..1f781ca83a 100644
--- a/src/test/txvalidation_tests.cpp
+++ b/src/test/txvalidation_tests.cpp
@@ -33 +33 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
    [-C-]{+Tx+}ValidationState state;
@@ -53 +53 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
    BOOST_CHECK(state.GetRe[-a-]s[-on-]{+ult+}() == {+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS);
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index 193858cca9..ea2ef5546f 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -16 +16 @@
bool CheckInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
@@ -25 +25 @@ ToMemPool(const CMutableTransaction& tx)
    [-C-]{+Tx+}ValidationState state;
@@ -117 +117 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
        [-C-]{+Tx+}ValidationState state;
@@ -204 +204 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
        [-C-]{+Tx+}ValidationState state;
@@ -273 +273 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
        [-C-]{+Tx+}ValidationState state;
@@ -301 +301 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
        [-C-]{+Tx+}ValidationState state;
@@ -362 +362 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
        [-C-]{+Tx+}ValidationState state;
diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp
index b3368d44b6..cc1406c062 100644
--- a/src/test/validation_block_tests.cpp
+++ b/src/test/validation_block_tests.cpp
@@ -154 +154 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
    [-C-]{+Block+}ValidationState state;
@@ -281 +281 @@ BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
            [-C-]{+Tx+}ValidationState state;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index e4c1fd4bc6..64d270f4c6 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -594 +594 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m
    [-C-]{+Tx+}ValidationState {+dummy_+}state;{+ // Not used. CheckTxInputs() should always pass+}
@@ -596 +596 @@ static void CheckInputsAndUpdateCoins(const CTransaction& tx, CCoinsViewCache& m
    bool fCheckResult = tx.IsCoinBase() || Consensus::CheckTxInputs(tx, {+dummy_+}state, mempoolDuplicate, spendheight, txfee);
diff --git a/src/util/validation.cpp b/src/util/validation.cpp
index 9a0d889447..bd52f57751 100644
--- a/src/util/validation.cpp
+++ b/src/util/validation.cpp
@@ -11,2 +11,2 @@
/** Convert [-C-]ValidationState to a human-readable message for logging */
std::string FormatStateMessage(const [-C-]ValidationState &state)
diff --git a/src/util/validation.h b/src/util/validation.h
index 32559853ee..da2cf9f102 100644
--- a/src/util/validation.h
+++ b/src/util/validation.h
@@ -11 +11 @@
class [-C-]ValidationState;
@@ -13,2 +13,2 @@ class CValidationState;
/** Convert [-C-]ValidationState to a human-readable message for logging */
std::string FormatStateMessage(const [-C-]ValidationState &state);
diff --git a/src/validation.cpp b/src/validation.cpp
index 9301066c6a..4af2e9d3fc 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -184 +184 @@ static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfte
bool CheckInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
@@ -366 +366 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool,
        [-C-]{+Tx+}ValidationState stateDummy;
@@ -394 +394 @@ static void UpdateMempoolForReorg(DisconnectedBlockTransactions& disconnectpool,
static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, [-C-]{+Tx+}ValidationState& state, const CCoinsViewCache& view, const CTxMemPool& pool,
@@ -444 +444 @@ public:
        [-C-]{+Tx+}ValidationState &m_state;
@@ -505 +505 @@ private:
    bool CheckFeeRate(size_t package_size, CAmount package_fee, [-C-]{+Tx+}ValidationState& state)
@@ -509 +509 @@ private:
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
@@ -513 +513 @@ private:
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
@@ -540 +540 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
    [-C-]{+Tx+}ValidationState &state = args.m_state;
@@ -566 +566 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "coinbase");
@@ -571 +571 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_NOT_STANDARD, false, reason);
@@ -578 +578 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_NOT_STANDARD, false, "tx-size-small");
@@ -584 +584 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_PREMATURE_SPEND, false, "non-final");
@@ -588 +588 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_CONFLICT, false, "txn-already-in-mempool");
@@ -620 +620 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
                    return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "txn-mempool-conflict");
@@ -646 +646 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
                    return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_CONFLICT, false, "txn-already-known");
@@ -671 +671 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_PREMATURE_SPEND, false, "non-BIP68-final");
@@ -680 +680 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_NOT_STANDARD, false, "bad-txns-nonstandard-inputs");
@@ -684 +684 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_WITNESS_MUTATED, false, "bad-witness-nonstandard");
@@ -708 +708 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_NOT_STANDARD, false, "bad-txns-too-many-sigops",
@@ -716 +716 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
        return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_NOT_STANDARD, false,
@@ -774 +774 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "too-long-mempool-chain", errString);
@@ -787 +787 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, "bad-txns-spends-conflicting-tx",
@@ -827 +827 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
                return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "insufficient fee",
@@ -855 +855 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "too many potential replacements",
@@ -879 +879 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
                    return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "replacement-adds-unconfirmed",
@@ -891 +891 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "insufficient fee",
@@ -901 +901 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "insufficient fee",
@@ -915 +915 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
    [-C-]{+Tx+}ValidationState &state = args.m_state;
@@ -925,3 +925,3 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
        [-C-]{+Tx+}ValidationState state[-D-]{+_d+}ummy; // Want reported failures to be from first CheckInputs
        if (!tx.HasWitness() && CheckInputs(tx, state[-D-]{+_d+}ummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
                !CheckInputs(tx, state[-D-]{+_d+}ummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
@@ -929 +929 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
            state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_WITNESS_MUTATED, false,
@@ -932 +931,0 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
[-        assert(IsTransactionReason(state.GetReason()));-]
@@ -944 +943 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, Precomp
    [-C-]{+Tx+}ValidationState &state = args.m_state;
@@ -975 +974 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
    [-C-]{+Tx+}ValidationState &state = args.m_state;
@@ -1013 +1012 @@ bool MemPoolAccept::Finalize(ATMPArgs& args, Workspace& ws)
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_MEMPOOL_POLICY, false, "mempool full");
@@ -1050 +1049 @@ bool MemPoolAccept::AcceptSingleTransaction(const CTransactionRef& ptx, ATMPArgs
static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPool& pool, [-C-]{+Tx+}ValidationState &state, const CTransactionRef &tx,
@@ -1067,2 +1066,2 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
    [-C-]{+Block+}ValidationState state[-D-]{+_d+}ummy;
    ::ChainstateActive().FlushStateToDisk(chainparams, state[-D-]{+_d+}ummy, FlushStateMode::PERIODIC);
@@ -1072 +1071 @@ static bool AcceptToMemoryPoolWithTime(const CChainParams& chainparams, CTxMemPo
bool AcceptToMemoryPool(CTxMemPool& pool, [-C-]{+Tx+}ValidationState &state, const CTransactionRef &tx,
@@ -1422,2 +1421,2 @@ void static InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(c
void CChainState::InvalidBlockFound(CBlockIndex *pindex, const [-C-]{+Block+}ValidationState &state) {
    if (state.GetRe[-a-]s[-on-]{+ult+}() != {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED) {
@@ -1496 +1495 @@ void InitScriptExecutionCache() {
bool CheckInputs(const CTransaction& tx, [-C-]{+Tx+}ValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -1548 +1547 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
                    return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::TX_NOT_STANDARD, false, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(check.GetScriptError())));
@@ -1551 +1550 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
            // {+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS. Because CONSENSUS
@@ -1559 +1558 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
            return state.Invalid({+Tx+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+TX_+}CONSENSUS, false, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError())));
@@ -1644 +1643 @@ static bool AbortNode(const std::string& strMessage, const std::string& userMess
static bool AbortNode([-C-]{+Block+}ValidationState& state, const std::string& strMessage, const std::string& userMessage = "", unsigned int prefix = 0)
@@ -1758 +1757 @@ void static FlushBlockFile(bool fFinalize = false)
static bool FindUndoPos([-C-]{+Block+}ValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize);
@@ -1760 +1759 @@ static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, un
static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, [-C-]{+Block+}ValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
@@ -1899 +1898 @@ static int64_t nBlocksTotal = 0;
bool CChainState::ConnectBlock(const CBlock& block, [-C-]{+Block+}ValidationState& state, CBlockIndex* pindex,
@@ -1921 +1920 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
        if (state.GetRe[-a-]s[-on-]{+ult+}() == {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED) {
@@ -2061 +2060 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
                    return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"),
@@ -2100,9 +2099,5 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
            {+TxValidationState tx_state;+}
{+            +}if (!Consensus::CheckTxInputs(tx, {+tx_+}state, view, pindex->nHeight, txfee)) {
                [-if (!IsBlockReason(state.GetReason())) {-]
[-                    -]// [-CheckTxI-]{+A+}n[-puts ma-]y [-re-]t[-u-]r[-n MISSING_INPUTS or-]
[-                    // PREMATURE_SPEND but we c-]an[-'t re-]{+sac+}t[-ur-]{+io+}n [-th-]{+valid+}at[-,-]{+ion+} {+f+}a[-s -]i[-t's-]{+lure+} {+i+}n[-ot-]
[-                  -] [- // defi-]{+Con+}ne[-d f-]{+ctBl+}o[-r-]{+ck is+} a block[-,-] [-s-]{+c+}o[- we re-]{+n+}se[-t the reaso-]n{+sus+} f[-l-]a[-g to-]
[-                    // CONSENSUS he-]{+ilu+}re[-.-]
[-    -]
                state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, false,
                            {+tx_+}state.GetRejectReason(), {+tx_+}state.GetDebugMessage());[-                }-]
@@ -2113 +2108 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
                return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__),
@@ -2126 +2121 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
                return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__),
@@ -2137 +2132 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, error("ConnectBlock(): too many sigops"),
@@ -2145,11 +2140,5 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
            {+TxValidationState tx_state;+}
{+            +}if (fScriptChecks && !CheckInputs(tx, {+tx_+}state, view, flags, fCacheResults, fCacheResults, txdata[i], nScriptCheckThreads ? &vChecks : nullptr)) {
                [-if-]{+// Any+} [-(state.Ge-]t[-Re-]{+r+}a{+n+}s{+acti+}on[-() ==-] [-V-]{+v+}alidation[-Inv-]{+ f+}a[-l-]i[-dR-]{+lur+}e[-aso-]{+ i+}n[-::TX_NOT_STANDARD)-] [-{-]{+ConnectBlock+} {+is+} {+a+} {+block+} {+consensus+} {+failure+}
               [-//-] [-Ch-]{+stat+}e[-ck-]{+.+}In[-puts m-]{+valid(BlockValid+}a[-y re-]t[-ur-]{+io+}n[- N-]{+Result::BL+}O[-T-]{+CK+}_{+CON+}S[-TA-]{+E+}N[-DARD-]{+SUS,+} f[-or extr-]a[- f-]l[-ags we pas-]se[-d-],
                    [-// but we can't return that, as it's not defined for a block, so-]
[-                    // we reset the reason flag to CONSENSUS here.-]
[-       -]          [-   // In -]t[-he event of a future soft-fork, we may need to-]
[-                    // consider whether rewriting to CONSENSUS or-]
[-                    // RECENT_CONSENSUS-]{+x+}_[-CHANGE would be more appropriate.-]
[-                    state.Invalid(ValidationInvalidReason::CONSENSUS, false,-]
[-                              -]state.GetRejectReason(), {+tx_+}state.GetDebugMessage());[-                }-]
@@ -2173 +2162 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS,
@@ -2179 +2168 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, error("%s: CheckQueue failed", __func__), "block-validation-failed");
@@ -2209 +2198 @@ bool CChainState::FlushStateToDisk(
    [-C-]{+Block+}ValidationState &state,
@@ -2320 +2309 @@ void CChainState::ForceFlushStateToDisk() {
    [-C-]{+Block+}ValidationState state;
@@ -2328 +2317 @@ void CChainState::PruneAndFlush() {
    [-C-]{+Block+}ValidationState state;
@@ -2414 +2403 @@ void static UpdateTip(const CBlockIndex* pindexNew, const CChainParams& chainPar
bool CChainState::DisconnectTip([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool)
@@ -2534 +2523 @@ public:
bool CChainState::ConnectTip([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool)
@@ -2666 +2655 @@ void CChainState::PruneBlockIndexCandidates() {
bool CChainState::ActivateBestChainStep([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
@@ -2713 +2702 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
                    if (state.GetRe[-a-]s[-on-]{+ult+}() != {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED) {
@@ -2716 +2705 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
                    state = [-C-]{+Block+}ValidationState();
@@ -2784 +2773 @@ static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) {
bool CChainState::ActivateBestChain([-C-]{+Block+}ValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
@@ -2884 +2873 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
bool ActivateBestChain([-C-]{+Block+}ValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
@@ -2888 +2877 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
bool CChainState::PreciousBlock([-C-]{+Block+}ValidationState& state, const CChainParams& params, CBlockIndex *pindex)
@@ -2916 +2905 @@ bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& par
bool PreciousBlock([-C-]{+Block+}ValidationState& state, const CChainParams& params, CBlockIndex *pindex) {
@@ -2920 +2909 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
bool CChainState::InvalidateBlock([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
@@ -3056 +3045 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c
bool InvalidateBlock([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex) {
@@ -3230 +3219 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n
static bool FindUndoPos([-C-]{+Block+}ValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize)
@@ -3252 +3241 @@ static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, un
static bool CheckBlockHeader(const CBlockHeader& block, [-C-]{+Block+}ValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true)
@@ -3256 +3245 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state,
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_INVALID_HEADER, false, "high-hash", "proof of work failed");
@@ -3261 +3250 @@ static bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state,
bool CheckBlock(const CBlock& block, [-C-]{+Block+}ValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot)
@@ -3278 +3267 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED, false, "bad-txnmrklroot", "hashMerkleRoot mismatch");
@@ -3284 +3273 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED, false, "bad-txns-duplicate", "duplicate transaction");
@@ -3295 +3284 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, false, "bad-blk-length", "size limits failed");
@@ -3299 +3288 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, false, "bad-cb-missing", "first tx is not coinbase");
@@ -3302 +3291 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, false, "bad-cb-multiple", "more than one coinbase");
@@ -3305,5 +3294,11 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
    {+// Must check for duplicate inputs (see CVE-2018-17144)+}
{+    +}for (const auto& tx : block.vtx) {+{+}
{+        TxValidationState tx_state;+}
{+ +}       if (!CheckTransaction(*tx, {+tx_+}state)) {+{+}
           [-r-]{+ // Ch+}e[-turn-]{+ckBlock()+} {+doe+}s{+ con+}t{+ext-free valid+}at{+ion ch+}e{+cks+}.[-I-]{+ The o+}n[-v-]{+ly+}
{+            // possible f+}a{+i+}l{+ures are consensus fa+}i[-d-]{+lures.+}
{+            assert+}({+tx_+}state.GetRe[-a-]s{+ult() == TxValidati+}on[-(-]{+Result::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()));
{+        }+}
{+    }+}
@@ -3316 +3311 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, false, "bad-blk-sigops", "out-of-bounds SigOpCount");
@@ -3409 +3404 @@ static CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOC
static bool ContextualCheckBlockHeader(const CBlockHeader& block, [-C-]{+Block+}ValidationState& state, const CChainParams& params, const CBlockIndex* pindexPrev, int64_t nAdjustedTime) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@@ -3417 +3412 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_INVALID_HEADER, false, "bad-diffbits", "incorrect proof of work");
@@ -3426 +3421 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), "bad-fork-prior-to-checkpoint");
@@ -3431 +3426 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_INVALID_HEADER, false, "time-too-old", "block's timestamp is too early");
@@ -3435 +3430 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_TIME_FUTURE, false, "time-too-new", "block timestamp too far in the future");
@@ -3442 +3437 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_INVALID_HEADER, false, strprintf("bad-version(0x%08x)", block.nVersion),
@@ -3454 +3449 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta
static bool ContextualCheckBlock(const CBlock& block, [-C-]{+Block+}ValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
@@ -3472 +3467 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, false, "bad-txns-nonfinal", "non-final transaction");
@@ -3482 +3477 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, false, "bad-cb-height", "block height mismatch in coinbase");
@@ -3504 +3499 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
                return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED, false, "bad-witness-nonce-size", strprintf("%s : invalid witness reserved value size", __func__));
@@ -3508 +3503 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
                return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED, false, "bad-witness-merkle-match", strprintf("%s : witness merkle commitment mismatch", __func__));
@@ -3518 +3513 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
                return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED, false, "unexpected-witness", strprintf("%s : unexpected witness data found", __func__));
@@ -3530 +3525 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
        return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CONSENSUS, false, "bad-blk-weight", strprintf("%s : weight limit failed", __func__));
@@ -3536 +3531 @@ static bool ContextualCheckBlock(const CBlock& block, CValidationState& state, c
bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, [-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex)
@@ -3550 +3545 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
                return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::{+BLOCK_+}CACHED_INVALID, error("%s: block %s is marked invalid", __func__, hash.ToString()), "duplicate");
@@ -3561 +3556 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), "prev-blk-not-found");
@@ -3564 +3559 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
            return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
@@ -3601 +3596 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
                    return state.Invalid({+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), "bad-prevblk");
@@ -3616 +3611 @@ bool BlockManager::AcceptBlockHeader(const CBlockHeader& block, CValidationState
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, [-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex, CBlockHeader *first_invalid)
@@ -3663 +3658 @@ static FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, const CChai
bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, [-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock)
@@ -3713,2 +3708 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
        [-assert(IsBlockReason(state.GetReason()));-]
[-        -]if (state.IsInvalid() && state.GetRe[-a-]s[-on-]{+ult+}() != {+Block+}Validation[-Invalid-]Re[-a-]s[-on-]{+ult+}::BLOCK_MUTATED) {
@@ -3753 +3747 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
        [-C-]{+Block+}ValidationState state;
@@ -3774 +3768 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
    [-C-]{+Block+}ValidationState state; // Only used to report errors, not invalidity - ignore it
@@ -3781 +3775 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
bool TestBlockValidity([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot)
@@ -3892 +3886 @@ void PruneBlockFilesManual(int nManualPruneHeight)
    [-C-]{+Block+}ValidationState state;
@@ -4188 +4182 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
    [-C-]{+Block+}ValidationState state;
@@ -4432 +4426 @@ bool CChainState::RewindBlockIndex(const CChainParams& params)
    [-C-]{+Block+}ValidationState state;
@@ -4500 +4494 @@ bool RewindBlockIndex(const CChainParams& params) {
        [-C-]{+Block+}ValidationState state;
@@ -4652 +4646 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
                      [-C-]{+Block+}ValidationState state;
@@ -4666 +4660 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
                    [-C-]{+Block+}ValidationState state;
@@ -4689 +4683 @@ bool LoadExternalBlockFile(const CChainParams& chainparams, FILE* fileIn, FlatFi
                            [-C-]{+Block+}ValidationState dummy;
@@ -4966 +4960 @@ bool LoadMempool(CTxMemPool& pool)
            [-C-]{+Tx+}ValidationState state;
diff --git a/src/validation.h b/src/validation.h
index d17a320a47..f346e5caac 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -34,0 +35 @@ class CChainState;
{+class BlockValidationState;+}
@@ -44 +45 @@ class CTxMemPool;
class [-C-]{+Tx+}ValidationState;
@@ -226 +227 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<cons
bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, [-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr, CBlockHeader* first_invalid = nullptr) LOCKS_EXCLUDED(cs_main);
@@ -251 +252 @@ bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::P
bool ActivateBestChain([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock = std::shared_ptr<const CBlock>());
@@ -275 +276 @@ void PruneBlockFilesManual(int nManualPruneHeight);
bool AcceptToMemoryPool(CTxMemPool& pool, [-C-]{+Tx+}ValidationState &state, const CTransactionRef &tx,
@@ -371 +372 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
bool CheckBlock(const CBlock& block, [-C-]{+Block+}ValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
@@ -374 +375 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
bool TestBlockValidity([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, const CBlock& block, CBlockIndex* pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -491 +492 @@ public:
        [-C-]{+Block+}ValidationState& state,
@@ -655 +656 @@ public:
        [-C-]{+Block+}ValidationState &state,
@@ -681 +682 @@ public:
        [-C-]{+Block+}ValidationState& state,
@@ -685 +686 @@ public:
    bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, [-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -689 +690 @@ public:
    bool ConnectBlock(const CBlock& block, [-C-]{+Block+}ValidationState& state, CBlockIndex* pindex,
@@ -693 +694 @@ public:
    bool DisconnectTip([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions* disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
@@ -696,2 +697,2 @@ public:
    bool PreciousBlock([-C-]{+Block+}ValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
    bool InvalidateBlock([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
@@ -723,2 +724,2 @@ private:
    bool ActivateBestChainStep([-C-]{+Block+}ValidationState& 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([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, ::mempool.cs);
@@ -726 +727 @@ private:
    void InvalidBlockFound(CBlockIndex *pindex, const [-C-]{+Block+}ValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -741 +742 @@ private:
bool PreciousBlock([-C-]{+Block+}ValidationState& state, const CChainParams& params, CBlockIndex *pindex) LOCKS_EXCLUDED(cs_main);
@@ -744 +745 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
bool InvalidateBlock([-C-]{+Block+}ValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index cf4a529a6d..a46b4003f1 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -35 +35 @@ struct MainSignalsInstance {
    boost::signals2::signal<void (const CBlock&, const [-C-]{+Block+}ValidationState&)> BlockChecked;
@@ -171 +171 @@ void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
void CMainSignals::BlockChecked(const CBlock& block, const [-C-]{+Block+}ValidationState& state) {
diff --git a/src/validationinterface.h b/src/validationinterface.h
index 3ce617b827..dc8425869b 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -15,0 +16 @@ extern CCriticalSection cs_main;
{+class BlockValidationState;+}
@@ -21 +21,0 @@ class CValidationInterface;
[-class CValidationState;-]
@@ -137 +137 @@ protected:
     * If the provided [-C-]{+Block+}ValidationState IsValid, the provided block
@@ -141 +141 @@ protected:
    virtual void BlockChecked(const CBlock&, const [-C-]{+Block+}ValidationState&) {}
@@ -183 +183 @@ public:
    void BlockChecked(const CBlock&, const [-C-]{+Block+}ValidationState&);
jon@purity:~/projects/bitcoin/bitcoin ((HEAD detached at a27a2957ed))$ 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment