mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-30 07:43:48 +02:00
Merge bitcoin/bitcoin#29060: Policy: Report debug message why inputs are non standard
d8f4e7caf0doc: add release notes (ismaelsadeeq)248c175e3dtest: ensure `ValidateInputsStandardness` optionally returns debug string (ismaelsadeeq)d2716e9e5bpolicy: update `AreInputsStandard` to return error string (ismaelsadeeq) Pull request description: This PR is another attempt at #13525. Transactions that fail `PreChecks` Validation due to non-standard inputs now returns invalid validation state`TxValidationResult::TX_INPUTS_NOT_STANDARD` along with a debug error message. Previously, the debug error message for non-standard inputs do not specify why the inputs were considered non-standard. Instead, the same error string, `bad-txns-nonstandard-inputs`, used for all types of non-standard input scriptSigs. This PR updates the `AreInputsStandard` to include the reason why inputs are non-standard in the debug message. This improves the `Precheck` debug message to be more descriptive. Furthermore, I have addressed all remaining comments from #13525 in this PR. ACKs for top commit: instagibbs: ACKd8f4e7caf0achow101: ACKd8f4e7caf0sedited: Re-ACKd8f4e7caf0Tree-SHA512: 19b1a73c68584522f863b9ee2c8d3a735348667f3628dc51e36be3ba59158509509fcc1ffc5683555112c09c8b14da3ad140bb879eac629b6f60b8313cfd8b91
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
#include <script/solver.h>
|
||||
#include <serialize.h>
|
||||
#include <span.h>
|
||||
#include <tinyformat.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
@@ -210,14 +211,16 @@ static bool CheckSigopsBIP54(const CTransaction& tx, const CCoinsViewCache& inpu
|
||||
*
|
||||
* We also check the total number of non-witness sigops across the whole transaction, as per BIP54.
|
||||
*/
|
||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||
TxValidationState ValidateInputsStandardness(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||
{
|
||||
TxValidationState state;
|
||||
if (tx.IsCoinBase()) {
|
||||
return true; // Coinbases don't use vin normally
|
||||
return state; // Coinbases don't use vin normally
|
||||
}
|
||||
|
||||
if (!CheckSigopsBIP54(tx, mapInputs)) {
|
||||
return false;
|
||||
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", "non-witness sigops exceed bip54 limit");
|
||||
return state;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < tx.vin.size(); i++) {
|
||||
@@ -225,27 +228,38 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||
|
||||
std::vector<std::vector<unsigned char> > vSolutions;
|
||||
TxoutType whichType = Solver(prev.scriptPubKey, vSolutions);
|
||||
if (whichType == TxoutType::NONSTANDARD || whichType == TxoutType::WITNESS_UNKNOWN) {
|
||||
if (whichType == TxoutType::NONSTANDARD) {
|
||||
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("input %u script unknown", i));
|
||||
return state;
|
||||
} else if (whichType == TxoutType::WITNESS_UNKNOWN) {
|
||||
// WITNESS_UNKNOWN failures are typically also caught with a policy
|
||||
// flag in the script interpreter, but it can be helpful to catch
|
||||
// this type of NONSTANDARD transaction earlier in transaction
|
||||
// validation.
|
||||
return false;
|
||||
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("input %u witness program is undefined", i));
|
||||
return state;
|
||||
} else if (whichType == TxoutType::SCRIPTHASH) {
|
||||
std::vector<std::vector<unsigned char> > stack;
|
||||
ScriptError serror;
|
||||
// convert the scriptSig into a stack, so we can inspect the redeemScript
|
||||
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE))
|
||||
return false;
|
||||
if (stack.empty())
|
||||
return false;
|
||||
if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE, &serror)) {
|
||||
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("p2sh scriptsig malformed (input %u: %s)", i, ScriptErrorString(serror)));
|
||||
return state;
|
||||
}
|
||||
if (stack.empty()) {
|
||||
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("input %u P2SH redeemscript missing", i));
|
||||
return state;
|
||||
}
|
||||
CScript subscript(stack.back().begin(), stack.back().end());
|
||||
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
|
||||
return false;
|
||||
unsigned int sigop_count = subscript.GetSigOpCount(true);
|
||||
if (sigop_count > MAX_P2SH_SIGOPS) {
|
||||
state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs", strprintf("p2sh redeemscript sigops exceed limit (input %u: %u > %u)", i, sigop_count, MAX_P2SH_SIGOPS));
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return state;
|
||||
}
|
||||
|
||||
bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||
@@ -354,7 +368,7 @@ bool SpendsNonAnchorWitnessProg(const CTransaction& tx, const CCoinsViewCache& p
|
||||
}
|
||||
|
||||
// For P2SH extract the redeem script and check if it spends a non-Taproot witness program. Note
|
||||
// this is fine to call EvalScript (as done in AreInputsStandard/IsWitnessStandard) because this
|
||||
// this is fine to call EvalScript (as done in ValidateInputsStandardness/IsWitnessStandard) because this
|
||||
// function is only ever called after IsStandardTx, which checks the scriptsig is pushonly.
|
||||
if (prev_spk.IsPayToScriptHash()) {
|
||||
// If EvalScript fails or results in an empty stack, the transaction is invalid by consensus.
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <consensus/amount.h>
|
||||
#include <consensus/consensus.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <script/solver.h>
|
||||
@@ -157,11 +158,12 @@ static constexpr decltype(CTransaction::version) TX_MAX_STANDARD_VERSION{3};
|
||||
*/
|
||||
bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& max_datacarrier_bytes, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
|
||||
/**
|
||||
* Check for standard transaction types
|
||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||
* @return True if all inputs (scriptSigs) use only standard transaction forms
|
||||
*/
|
||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
|
||||
* Check for standard transaction types
|
||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||
* @returns valid TxValidationState if all inputs (scriptSigs) use only standard transaction forms else returns
|
||||
* invalid TxValidationState which states why the first invalid input is not standard
|
||||
*/
|
||||
TxValidationState ValidateInputsStandardness(const CTransaction& tx, const CCoinsViewCache& mapInputs);
|
||||
/**
|
||||
* Check if the transaction is over standard P2WSH resources limit:
|
||||
* 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements
|
||||
|
||||
Reference in New Issue
Block a user