Skip to content

Commit 7b267c0

Browse files
committed
[validation] Add detailed txin/txout information for script error messages
Don't just report which script error occurred, but which in which input of which transaction, and which UTXO was being spent.
1 parent 146a3d5 commit 7b267c0

File tree

2 files changed

+9
-8
lines changed

2 files changed

+9
-8
lines changed

src/validation.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,14 +2103,15 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
21032103
AddCoins(inputs, tx, nHeight);
21042104
}
21052105

2106-
std::optional<ScriptError> CScriptCheck::operator()() {
2106+
std::optional<std::pair<ScriptError, std::string>> CScriptCheck::operator()() {
21072107
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
21082108
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
21092109
ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR};
21102110
if (VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata), &error)) {
21112111
return std::nullopt;
21122112
} else {
2113-
return error;
2113+
auto debug_str = strprintf("input %i of %s (wtxid %s), spending %s:%i", nIn, ptxTo->GetHash().ToString(), ptxTo->GetWitnessHash().ToString(), ptxTo->vin[nIn].prevout.hash.ToString(), ptxTo->vin[nIn].prevout.n);
2114+
return std::make_pair(error, std::move(debug_str));
21142115
}
21152116
}
21162117

@@ -2214,7 +2215,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
22142215
flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheSigStore, &txdata);
22152216
auto mandatory_result = check2();
22162217
if (!mandatory_result.has_value()) {
2217-
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(*result)));
2218+
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, strprintf("non-mandatory-script-verify-flag (%s)", ScriptErrorString(result->first)), result->second);
22182219
} else {
22192220
// If the second check failed, it failed due to a mandatory script verification
22202221
// flag, but the first check might have failed on a non-mandatory script
@@ -2228,7 +2229,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
22282229

22292230
// MANDATORY flag failures correspond to
22302231
// TxValidationResult::TX_CONSENSUS.
2231-
return state.Invalid(TxValidationResult::TX_CONSENSUS, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(*result)));
2232+
return state.Invalid(TxValidationResult::TX_CONSENSUS, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(result->first)), result->second);
22322233
}
22332234
}
22342235

@@ -2688,7 +2689,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
26882689
// Any transaction validation failure in ConnectBlock is a block consensus failure
26892690
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
26902691
tx_state.GetRejectReason(), tx_state.GetDebugMessage());
2691-
LogInfo("Script validation error in block: %s\n", tx_state.GetRejectReason());
2692+
LogInfo("Script validation error in block: %s\n", state.ToString());
26922693
return false;
26932694
}
26942695
control.Add(std::move(vChecks));
@@ -2716,8 +2717,8 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
27162717

27172718
auto parallel_result = control.Complete();
27182719
if (parallel_result.has_value()) {
2719-
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(*parallel_result)));
2720-
LogInfo("Script validation error in block: %s", state.GetRejectReason());
2720+
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(parallel_result->first)), parallel_result->second);
2721+
LogInfo("Script validation error in block: %s", state.ToString());
27212722
return false;
27222723
}
27232724
const auto time_4{SteadyClock::now()};

src/validation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ class CScriptCheck
347347
CScriptCheck(CScriptCheck&&) = default;
348348
CScriptCheck& operator=(CScriptCheck&&) = default;
349349

350-
std::optional<ScriptError> operator()();
350+
std::optional<std::pair<ScriptError, std::string>> operator()();
351351
};
352352

353353
// CScriptCheck is used a lot in std::vector, make sure that's efficient

0 commit comments

Comments
 (0)