Files
bitcoin/src/test/fuzz/transaction.cpp
Ava Chow bc1c540920 Merge bitcoin/bitcoin#29060: Policy: Report debug message why inputs are non standard
d8f4e7caf0 doc: add release notes (ismaelsadeeq)
248c175e3d test: ensure `ValidateInputsStandardness` optionally returns debug string (ismaelsadeeq)
d2716e9e5b policy: 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:
    ACK d8f4e7caf0
  achow101:
    ACK d8f4e7caf0
  sedited:
    Re-ACK d8f4e7caf0

Tree-SHA512: 19b1a73c68584522f863b9ee2c8d3a735348667f3628dc51e36be3ba59158509509fcc1ffc5683555112c09c8b14da3ad140bb879eac629b6f60b8313cfd8b91
2026-03-19 15:43:18 -07:00

105 lines
3.2 KiB
C++

// Copyright (c) 2019-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <chainparams.h>
#include <coins.h>
#include <consensus/tx_check.h>
#include <consensus/tx_verify.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <core_memusage.h>
#include <policy/policy.h>
#include <policy/settings.h>
#include <primitives/transaction.h>
#include <streams.h>
#include <test/fuzz/fuzz.h>
#include <test/util/random.h>
#include <univalue.h>
#include <util/chaintype.h>
#include <util/rbf.h>
#include <validation.h>
#include <cassert>
void initialize_transaction()
{
SelectParams(ChainType::REGTEST);
}
FUZZ_TARGET(transaction, .init = initialize_transaction)
{
SeedRandomStateForTest(SeedRand::ZEROS);
SpanReader ds{buffer};
bool valid_tx = true;
const CTransaction tx = [&] {
try {
return CTransaction(deserialize, TX_WITH_WITNESS, ds);
} catch (const std::ios_base::failure&) {
valid_tx = false;
return CTransaction{CMutableTransaction{}};
}
}();
bool valid_mutable_tx = true;
CMutableTransaction mutable_tx;
try {
SpanReader{buffer} >> TX_WITH_WITNESS(mutable_tx);
} catch (const std::ios_base::failure&) {
valid_mutable_tx = false;
}
assert(valid_tx == valid_mutable_tx);
if (!valid_tx) {
return;
}
{
TxValidationState state_with_dupe_check;
const bool res{CheckTransaction(tx, state_with_dupe_check)};
Assert(res == state_with_dupe_check.IsValid());
}
const CFeeRate dust_relay_fee{DUST_RELAY_TX_FEE};
std::string reason;
const bool is_standard_with_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ true, dust_relay_fee, reason);
const bool is_standard_without_permit_bare_multisig = IsStandardTx(tx, std::nullopt, /* permit_bare_multisig= */ false, dust_relay_fee, reason);
if (is_standard_without_permit_bare_multisig) {
assert(is_standard_with_permit_bare_multisig);
}
(void)tx.GetHash();
(void)tx.ComputeTotalSize();
try {
(void)tx.GetValueOut();
} catch (const std::runtime_error&) {
}
(void)tx.GetWitnessHash();
(void)tx.HasWitness();
(void)tx.IsCoinBase();
(void)tx.IsNull();
(void)tx.ToString();
(void)EncodeHexTx(tx);
(void)GetLegacySigOpCount(tx);
(void)GetTransactionWeight(tx);
(void)GetVirtualTransactionSize(tx);
(void)IsFinalTx(tx, /* nBlockHeight= */ 1024, /* nBlockTime= */ 1024);
(void)RecursiveDynamicUsage(tx);
(void)SignalsOptInRBF(tx);
CCoinsView coins_view;
const CCoinsViewCache coins_view_cache(&coins_view);
(void)ValidateInputsStandardness(tx, coins_view_cache);
(void)IsWitnessStandard(tx, coins_view_cache);
if (tx.ComputeTotalSize() < 250'000) { // Avoid high memory usage (with msan) due to json encoding
{
UniValue u{UniValue::VOBJ};
TxToUniv(tx, /*block_hash=*/uint256::ZERO, /*entry=*/u);
}
{
UniValue u{UniValue::VOBJ};
TxToUniv(tx, /*block_hash=*/uint256::ONE, /*entry=*/u);
}
}
}