mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 03:47:29 -03:00
Merge #16658: validation: Rename CheckInputs to CheckInputScripts
3bd8db80d8
[validation] fix comments in CheckInputScripts() (John Newbery)6f6465cefc
scripted-diff: [validation] Rename CheckInputs to CheckInputScripts (John Newbery) Pull request description: CheckInputs() used to check no double spends, scripts & sigs and amounts. Since832e074
, the double spend and amount checks have been moved to CheckTxInputs(), and CheckInputs() now just validates input scripts. Rename the function to CheckInputScripts(). Also fix incorrect comments. ACKs for top commit: MarcoFalke: re-ACK3bd8db80d8
, did the rebase myself, checked the scripted diff 👡 promag: ACK3bd8db80d8
:trollface: Tree-SHA512: 7b3f8597d210492798fb784ee8ea47ea6377519111190161c7cc34a967509013f4337304f52e9bedc97b7710de7b0ff8880e08cd7f867754567f82e7b02c794c
This commit is contained in:
commit
3f8dbcd655
5 changed files with 41 additions and 39 deletions
|
@ -47,7 +47,7 @@ extern unsigned nMaxDatacarrierBytes;
|
|||
* but in the future other flags may be added, such as a soft-fork to enforce
|
||||
* strict DER encoding.
|
||||
*
|
||||
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
|
||||
* Failing one of these tests may trigger a DoS ban - see CheckInputScripts() for
|
||||
* details.
|
||||
*/
|
||||
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
|
||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks);
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
|
||||
|
||||
|
@ -95,8 +95,8 @@ BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
|
|||
BOOST_CHECK_EQUAL(m_node.mempool->size(), 0U);
|
||||
}
|
||||
|
||||
// Run CheckInputs (using CoinsTip()) on the given transaction, for all script
|
||||
// flags. Test that CheckInputs passes for all flags that don't overlap with
|
||||
// Run CheckInputScripts (using CoinsTip()) on the given transaction, for all script
|
||||
// flags. Test that CheckInputScripts passes for all flags that don't overlap with
|
||||
// the failing_flags argument, but otherwise fails.
|
||||
// CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY (and future NOP codes that may
|
||||
// get reassigned) have an interaction with DISCOURAGE_UPGRADABLE_NOPS: if
|
||||
|
@ -123,8 +123,8 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
|
|||
// WITNESS requires P2SH
|
||||
test_flags |= SCRIPT_VERIFY_P2SH;
|
||||
}
|
||||
bool ret = CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, nullptr);
|
||||
// CheckInputs should succeed iff test_flags doesn't intersect with
|
||||
bool ret = CheckInputScripts(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, nullptr);
|
||||
// CheckInputScripts should succeed iff test_flags doesn't intersect with
|
||||
// failing_flags
|
||||
bool expected_return_value = !(test_flags & failing_flags);
|
||||
BOOST_CHECK_EQUAL(ret, expected_return_value);
|
||||
|
@ -133,13 +133,13 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
|
|||
if (ret && add_to_cache) {
|
||||
// Check that we get a cache hit if the tx was valid
|
||||
std::vector<CScriptCheck> scriptchecks;
|
||||
BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, &scriptchecks));
|
||||
BOOST_CHECK(CheckInputScripts(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, &scriptchecks));
|
||||
BOOST_CHECK(scriptchecks.empty());
|
||||
} else {
|
||||
// Check that we get script executions to check, if the transaction
|
||||
// was invalid, or we didn't add to cache.
|
||||
std::vector<CScriptCheck> scriptchecks;
|
||||
BOOST_CHECK(CheckInputs(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, &scriptchecks));
|
||||
BOOST_CHECK(CheckInputScripts(tx, state, &::ChainstateActive().CoinsTip(), test_flags, true, add_to_cache, txdata, &scriptchecks));
|
||||
BOOST_CHECK_EQUAL(scriptchecks.size(), tx.vin.size());
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ static void ValidateCheckInputsForAllFlags(const CTransaction &tx, uint32_t fail
|
|||
|
||||
BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
||||
{
|
||||
// Test that passing CheckInputs with one set of script flags doesn't imply
|
||||
// Test that passing CheckInputScripts with one set of script flags doesn't imply
|
||||
// that we would pass again with a different set of flags.
|
||||
{
|
||||
LOCK(cs_main);
|
||||
|
@ -202,16 +202,16 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||
TxValidationState state;
|
||||
PrecomputedTransactionData ptd_spend_tx(spend_tx);
|
||||
|
||||
BOOST_CHECK(!CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
|
||||
BOOST_CHECK(!CheckInputScripts(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, nullptr));
|
||||
|
||||
// If we call again asking for scriptchecks (as happens in
|
||||
// ConnectBlock), we should add a script check object for this -- we're
|
||||
// not caching invalidity (if that changes, delete this test case).
|
||||
std::vector<CScriptCheck> scriptchecks;
|
||||
BOOST_CHECK(CheckInputs(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
|
||||
BOOST_CHECK(CheckInputScripts(CTransaction(spend_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_DERSIG, true, true, ptd_spend_tx, &scriptchecks));
|
||||
BOOST_CHECK_EQUAL(scriptchecks.size(), 1U);
|
||||
|
||||
// Test that CheckInputs returns true iff DERSIG-enforcing flags are
|
||||
// Test that CheckInputScripts returns true iff DERSIG-enforcing flags are
|
||||
// not present. Don't add these checks to the cache, so that we can
|
||||
// test later that block validation works fine in the absence of cached
|
||||
// successes.
|
||||
|
@ -270,7 +270,7 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||
invalid_with_cltv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
||||
TxValidationState state;
|
||||
PrecomputedTransactionData txdata(invalid_with_cltv_tx);
|
||||
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_cltv_tx), state, ::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
|
||||
BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_cltv_tx), state, ::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY, true, true, txdata, nullptr));
|
||||
}
|
||||
|
||||
// TEST CHECKSEQUENCEVERIFY
|
||||
|
@ -298,12 +298,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||
invalid_with_csv_tx.vin[0].scriptSig = CScript() << vchSig << 100;
|
||||
TxValidationState state;
|
||||
PrecomputedTransactionData txdata(invalid_with_csv_tx);
|
||||
BOOST_CHECK(CheckInputs(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
|
||||
BOOST_CHECK(CheckInputScripts(CTransaction(invalid_with_csv_tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_CHECKSEQUENCEVERIFY, true, true, txdata, nullptr));
|
||||
}
|
||||
|
||||
// TODO: add tests for remaining script flags
|
||||
|
||||
// Test that passing CheckInputs with a valid witness doesn't imply success
|
||||
// Test that passing CheckInputScripts with a valid witness doesn't imply success
|
||||
// for the same tx with a different witness.
|
||||
{
|
||||
CMutableTransaction valid_with_witness_tx;
|
||||
|
@ -360,12 +360,12 @@ BOOST_FIXTURE_TEST_CASE(checkinputs_test, TestChain100Setup)
|
|||
TxValidationState state;
|
||||
PrecomputedTransactionData txdata(tx);
|
||||
// This transaction is now invalid under segwit, because of the second input.
|
||||
BOOST_CHECK(!CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
|
||||
BOOST_CHECK(!CheckInputScripts(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, nullptr));
|
||||
|
||||
std::vector<CScriptCheck> scriptchecks;
|
||||
// Make sure this transaction was not cached (ie because the first
|
||||
// input was valid)
|
||||
BOOST_CHECK(CheckInputs(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
|
||||
BOOST_CHECK(CheckInputScripts(CTransaction(tx), state, &::ChainstateActive().CoinsTip(), SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS, true, true, txdata, &scriptchecks));
|
||||
// Should get 2 script checks back -- caching is on a whole-transaction basis.
|
||||
BOOST_CHECK_EQUAL(scriptchecks.size(), 2U);
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ std::unique_ptr<CBlockTreeDB> pblocktree;
|
|||
// See definition for documentation
|
||||
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
|
||||
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
|
||||
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
|
||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
|
||||
static FILE* OpenUndoFile(const FlatFilePos &pos, bool fReadOnly = false);
|
||||
static FlatFileSeq BlockFileSeq();
|
||||
static FlatFileSeq UndoFileSeq();
|
||||
|
@ -396,19 +396,19 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS
|
|||
|
||||
// pool.cs should be locked already, but go ahead and re-take the lock here
|
||||
// to enforce that mempool doesn't change between when we check the view
|
||||
// and when we actually call through to CheckInputs
|
||||
// and when we actually call through to CheckInputScripts
|
||||
LOCK(pool.cs);
|
||||
|
||||
assert(!tx.IsCoinBase());
|
||||
for (const CTxIn& txin : tx.vin) {
|
||||
const Coin& coin = view.AccessCoin(txin.prevout);
|
||||
|
||||
// At this point we haven't actually checked if the coins are all
|
||||
// available (or shouldn't assume we have, since CheckInputs does).
|
||||
// So we just return failure if the inputs are not available here,
|
||||
// and then only have to check equivalence for available inputs.
|
||||
// AcceptToMemoryPoolWorker has already checked that the coins are
|
||||
// available, so this shouldn't fail. If the inputs are not available
|
||||
// here then return false.
|
||||
if (coin.IsSpent()) return false;
|
||||
|
||||
// Check equivalence for available inputs.
|
||||
const CTransactionRef& txFrom = pool.get(txin.prevout.hash);
|
||||
if (txFrom) {
|
||||
assert(txFrom->GetHash() == txin.prevout.hash);
|
||||
|
@ -421,8 +421,8 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS
|
|||
}
|
||||
}
|
||||
|
||||
// Call CheckInputs() to cache signature and script validity against current tip consensus rules.
|
||||
return CheckInputs(tx, state, view, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata);
|
||||
// Call CheckInputScripts() to cache signature and script validity against current tip consensus rules.
|
||||
return CheckInputScripts(tx, state, view, flags, /* cacheSigStore = */ true, /* cacheFullSciptStore = */ true, txdata);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -906,20 +906,20 @@ bool MemPoolAccept::PolicyScriptChecks(ATMPArgs& args, Workspace& ws, Precompute
|
|||
|
||||
constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
|
||||
|
||||
// Check against previous transactions
|
||||
// Check input scripts and signatures.
|
||||
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
|
||||
if (!CheckInputs(tx, state, m_view, scriptVerifyFlags, true, false, txdata)) {
|
||||
if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, txdata)) {
|
||||
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
|
||||
// need to turn both off, and compare against just turning off CLEANSTACK
|
||||
// to see if the failure is specifically due to witness validation.
|
||||
TxValidationState state_dummy; // Want reported failures to be from first CheckInputs
|
||||
if (!tx.HasWitness() && CheckInputs(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
|
||||
!CheckInputs(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
|
||||
TxValidationState state_dummy; // Want reported failures to be from first CheckInputScripts
|
||||
if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, txdata) &&
|
||||
!CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, txdata)) {
|
||||
// Only the witness is missing, so the transaction itself may be fine.
|
||||
state.Invalid(TxValidationResult::TX_WITNESS_MUTATED,
|
||||
state.GetRejectReason(), state.GetDebugMessage());
|
||||
}
|
||||
return false; // state filled in by CheckInputs
|
||||
return false; // state filled in by CheckInputScripts
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -950,7 +950,7 @@ bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs& args, Workspace& ws, Precomp
|
|||
// transactions into the mempool can be exploited as a DoS attack.
|
||||
unsigned int currentBlockScriptVerifyFlags = GetBlockScriptFlags(::ChainActive().Tip(), chainparams.GetConsensus());
|
||||
if (!CheckInputsFromMempoolAndCache(tx, state, m_view, m_pool, currentBlockScriptVerifyFlags, txdata)) {
|
||||
return error("%s: BUG! PLEASE REPORT THIS! CheckInputs failed against latest-block but not STANDARD flags %s, %s",
|
||||
return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed against latest-block but not STANDARD flags %s, %s",
|
||||
__func__, hash.ToString(), FormatStateMessage(state));
|
||||
}
|
||||
|
||||
|
@ -1466,8 +1466,10 @@ void InitScriptExecutionCache() {
|
|||
}
|
||||
|
||||
/**
|
||||
* Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts)
|
||||
* This does not modify the UTXO set.
|
||||
* Check whether all of this transaction's input scripts succeed.
|
||||
*
|
||||
* This involves ECDSA signature checks so can be computationally intensive. This function should
|
||||
* only be called after the cheap sanity checks in CheckTxInputs passed.
|
||||
*
|
||||
* If pvChecks is not nullptr, script checks are pushed onto it instead of being performed inline. Any
|
||||
* script checks which are not necessary (eg due to script execution cache hits) are, obviously,
|
||||
|
@ -1482,7 +1484,7 @@ void InitScriptExecutionCache() {
|
|||
*
|
||||
* Non-static (and re-declared) in src/test/txvalidationcache_tests.cpp
|
||||
*/
|
||||
bool CheckInputs(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const CCoinsViewCache &inputs, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
||||
{
|
||||
if (tx.IsCoinBase()) return true;
|
||||
|
||||
|
@ -2129,11 +2131,11 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
|
|||
std::vector<CScriptCheck> vChecks;
|
||||
bool fCacheResults = fJustCheck; /* Don't cache results if we're actually connecting blocks (still consult the cache, though) */
|
||||
TxValidationState tx_state;
|
||||
if (fScriptChecks && !CheckInputs(tx, tx_state, view, flags, fCacheResults, fCacheResults, txdata[i], g_parallel_script_checks ? &vChecks : nullptr)) {
|
||||
if (fScriptChecks && !CheckInputScripts(tx, tx_state, view, flags, fCacheResults, fCacheResults, txdata[i], g_parallel_script_checks ? &vChecks : nullptr)) {
|
||||
// Any transaction validation failure in ConnectBlock is a block consensus failure
|
||||
state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
|
||||
tx_state.GetRejectReason(), tx_state.GetDebugMessage());
|
||||
return error("ConnectBlock(): CheckInputs on %s failed with %s",
|
||||
return error("ConnectBlock(): CheckInputScripts on %s failed with %s",
|
||||
tx.GetHash().ToString(), FormatStateMessage(state));
|
||||
}
|
||||
control.Add(vChecks);
|
||||
|
|
|
@ -135,7 +135,7 @@ class BIP65Test(BitcoinTestFramework):
|
|||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.solve()
|
||||
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputs on {} failed with non-mandatory-script-verify-flag (Negative locktime)'.format(block.vtx[-1].hash)]):
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputScripts on {} failed with non-mandatory-script-verify-flag (Negative locktime)'.format(block.vtx[-1].hash)]):
|
||||
self.nodes[0].p2p.send_and_ping(msg_block(block))
|
||||
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
|
||||
self.nodes[0].p2p.sync_with_ping()
|
||||
|
|
|
@ -120,7 +120,7 @@ class BIP66Test(BitcoinTestFramework):
|
|||
block.rehash()
|
||||
block.solve()
|
||||
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputs on {} failed with non-mandatory-script-verify-flag (Non-canonical DER signature)'.format(block.vtx[-1].hash)]):
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=['CheckInputScripts on {} failed with non-mandatory-script-verify-flag (Non-canonical DER signature)'.format(block.vtx[-1].hash)]):
|
||||
self.nodes[0].p2p.send_and_ping(msg_block(block))
|
||||
assert_equal(int(self.nodes[0].getbestblockhash(), 16), tip)
|
||||
self.nodes[0].p2p.sync_with_ping()
|
||||
|
|
Loading…
Reference in a new issue