mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-19 14:45:08 +01:00
Only relay Taproot spends if next block has it active
This commit is contained in:
parent
42b66a6b81
commit
525cbd425e
@ -45,7 +45,7 @@ static void CCoinsCaching(benchmark::Bench& bench)
|
||||
// Benchmark.
|
||||
const CTransaction tx_1(t1);
|
||||
bench.run([&] {
|
||||
bool success = AreInputsStandard(tx_1, coins);
|
||||
bool success = AreInputsStandard(tx_1, coins, false);
|
||||
assert(success);
|
||||
});
|
||||
ECC_Stop();
|
||||
|
@ -155,7 +155,7 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
|
||||
*
|
||||
* Note that only the non-witness portion of the transaction is checked here.
|
||||
*/
|
||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active)
|
||||
{
|
||||
if (tx.IsCoinBase())
|
||||
return true; // Coinbases don't use vin normally
|
||||
@ -183,6 +183,9 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
|
||||
return false;
|
||||
}
|
||||
} else if (whichType == TxoutType::WITNESS_V1_TAPROOT) {
|
||||
// Don't allow Taproot spends unless Taproot is active.
|
||||
if (!taproot_active) return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,10 +95,11 @@ bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType);
|
||||
bool IsStandardTx(const CTransaction& tx, 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
|
||||
* @param[in] mapInputs Map of previous transactions that have outputs we're spending
|
||||
* @param[in] taproot_active Whether or taproot consensus rules are active (used to decide whether spends of them are permitted)
|
||||
* @return True if all inputs (scriptSigs) use only standard transaction forms
|
||||
*/
|
||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
|
||||
bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, bool taproot_active);
|
||||
/**
|
||||
* Check if the transaction is over standard P2WSH resources limit:
|
||||
* 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements
|
||||
|
@ -229,7 +229,8 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
(void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache);
|
||||
(void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, false);
|
||||
(void)AreInputsStandard(CTransaction{random_mutable_transaction}, coins_view_cache, true);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
|
@ -95,7 +95,8 @@ void test_one_input(const std::vector<uint8_t>& buffer)
|
||||
|
||||
CCoinsView coins_view;
|
||||
const CCoinsViewCache coins_view_cache(&coins_view);
|
||||
(void)AreInputsStandard(tx, coins_view_cache);
|
||||
(void)AreInputsStandard(tx, coins_view_cache, false);
|
||||
(void)AreInputsStandard(tx, coins_view_cache, true);
|
||||
(void)IsWitnessStandard(tx, coins_view_cache);
|
||||
|
||||
UniValue u(UniValue::VOBJ);
|
||||
|
@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||
txTo.vin[3].scriptSig << OP_11 << OP_11 << std::vector<unsigned char>(oneAndTwo.begin(), oneAndTwo.end());
|
||||
txTo.vin[4].scriptSig << std::vector<unsigned char>(fifteenSigops.begin(), fifteenSigops.end());
|
||||
|
||||
BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins));
|
||||
BOOST_CHECK(::AreInputsStandard(CTransaction(txTo), coins, false));
|
||||
// 22 P2SH sigops for all inputs (1 for vin[0], 6 for vin[3], 15 for vin[4]
|
||||
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txTo), coins), 22U);
|
||||
|
||||
@ -356,7 +356,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||
txToNonStd1.vin[0].prevout.hash = txFrom.GetHash();
|
||||
txToNonStd1.vin[0].scriptSig << std::vector<unsigned char>(sixteenSigops.begin(), sixteenSigops.end());
|
||||
|
||||
BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins));
|
||||
BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd1), coins, false));
|
||||
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd1), coins), 16U);
|
||||
|
||||
CMutableTransaction txToNonStd2;
|
||||
@ -368,7 +368,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard)
|
||||
txToNonStd2.vin[0].prevout.hash = txFrom.GetHash();
|
||||
txToNonStd2.vin[0].scriptSig << std::vector<unsigned char>(twentySigops.begin(), twentySigops.end());
|
||||
|
||||
BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins));
|
||||
BOOST_CHECK(!::AreInputsStandard(CTransaction(txToNonStd2), coins, false));
|
||||
BOOST_CHECK_EQUAL(GetP2SHSigOpCount(CTransaction(txToNonStd2), coins), 20U);
|
||||
}
|
||||
|
||||
|
@ -305,7 +305,7 @@ BOOST_AUTO_TEST_CASE(test_Get)
|
||||
t1.vout[0].nValue = 90*CENT;
|
||||
t1.vout[0].scriptPubKey << OP_1;
|
||||
|
||||
BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins));
|
||||
BOOST_CHECK(AreInputsStandard(CTransaction(t1), coins, false));
|
||||
}
|
||||
|
||||
static void CreateCreditAndSpend(const FillableSigningProvider& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true)
|
||||
|
@ -690,7 +690,9 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
||||
}
|
||||
|
||||
// Check for non-standard pay-to-script-hash in inputs
|
||||
if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
|
||||
const auto& params = args.m_chainparams.GetConsensus();
|
||||
auto taproot_state = VersionBitsState(::ChainActive().Tip(), params, Consensus::DEPLOYMENT_TAPROOT, versionbitscache);
|
||||
if (fRequireStandard && !AreInputsStandard(tx, m_view, taproot_state == ThresholdState::ACTIVE)) {
|
||||
return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
|
||||
}
|
||||
|
||||
|
@ -1129,13 +1129,13 @@ def spenders_taproot_inactive():
|
||||
]
|
||||
tap = taproot_construct(pub, scripts)
|
||||
|
||||
# Test that keypath spending is valid & standard if compliant, but valid and nonstandard otherwise.
|
||||
add_spender(spenders, "inactive/keypath_valid", key=sec, tap=tap)
|
||||
# Test that keypath spending is valid & non-standard, regardless of validity.
|
||||
add_spender(spenders, "inactive/keypath_valid", key=sec, tap=tap, standard=False)
|
||||
add_spender(spenders, "inactive/keypath_invalidsig", key=sec, tap=tap, standard=False, sighash=bitflipper(default_sighash))
|
||||
add_spender(spenders, "inactive/keypath_empty", key=sec, tap=tap, standard=False, witness=[])
|
||||
|
||||
# Same for scriptpath spending (but using future features like annex, leaf versions, or OP_SUCCESS is nonstandard).
|
||||
add_spender(spenders, "inactive/scriptpath_valid", key=sec, tap=tap, leaf="pk", inputs=[getter("sign")])
|
||||
# Same for scriptpath spending (and features like annex, leaf versions, or OP_SUCCESS don't change this)
|
||||
add_spender(spenders, "inactive/scriptpath_valid", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")])
|
||||
add_spender(spenders, "inactive/scriptpath_invalidsig", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")], sighash=bitflipper(default_sighash))
|
||||
add_spender(spenders, "inactive/scriptpath_invalidcb", key=sec, tap=tap, leaf="pk", standard=False, inputs=[getter("sign")], controlblock=bitflipper(default_controlblock))
|
||||
add_spender(spenders, "inactive/scriptpath_valid_unkleaf", key=sec, tap=tap, leaf="future_leaf", standard=False, inputs=[getter("sign")])
|
||||
|
Loading…
Reference in New Issue
Block a user