mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-17 13:22:03 +01:00
Compare commits
15 Commits
98f1ad45ba
...
0839b3419e
Author | SHA1 | Date | |
---|---|---|---|
|
0839b3419e | ||
|
5f4422d68d | ||
|
3301d2cbe8 | ||
|
9bfb0d75ba | ||
|
7ac281c19c | ||
|
4c5790105e | ||
|
201ebd8689 | ||
|
b7e7ca146b | ||
|
6a14878be3 | ||
|
90ab82e8ff | ||
|
43be0ce1c1 | ||
|
fc2374644a | ||
|
20cf7fe381 | ||
|
ef989f36ea | ||
|
ce776c77f7 |
@ -98,6 +98,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||
case TxoutType::MULTISIG:
|
||||
case TxoutType::NULL_DATA:
|
||||
case TxoutType::NONSTANDARD:
|
||||
case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY:
|
||||
addressRet = CNoDestination(scriptPubKey);
|
||||
return false;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
|
@ -214,6 +214,11 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
|
||||
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
|
||||
return false;
|
||||
}
|
||||
} else if (whichType == TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY) {
|
||||
// after activation, only allow bare with no scriptsig.
|
||||
// pre-activation disallowing enforced via discouraged logic in the
|
||||
// interpreter.
|
||||
if (tx.vin[i].scriptSig.size() != 0) return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,7 +124,11 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI
|
||||
SCRIPT_VERIFY_CONST_SCRIPTCODE |
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
|
||||
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE |
|
||||
SCRIPT_VERIFY_DISCOURAGE_CHECKTEMPLATEVERIFY |
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY |
|
||||
SCRIPT_VERIFY_CHECKTEMPLATEVERIFY};
|
||||
|
||||
|
||||
/** For convenience, standard but not mandatory verify flags. */
|
||||
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};
|
||||
|
@ -544,6 +544,8 @@ static RPCHelpMan decodescript()
|
||||
case TxoutType::WITNESS_UNKNOWN:
|
||||
case TxoutType::WITNESS_V1_TAPROOT:
|
||||
case TxoutType::ANCHOR:
|
||||
// don't wrap CTV because P2SH CTV is a hash cycle
|
||||
case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY:
|
||||
// Should not be wrapped
|
||||
return false;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
@ -587,6 +589,8 @@ static RPCHelpMan decodescript()
|
||||
case TxoutType::WITNESS_V0_SCRIPTHASH:
|
||||
case TxoutType::WITNESS_V1_TAPROOT:
|
||||
case TxoutType::ANCHOR:
|
||||
// don't wrap CTV because P2SH CTV is a hash cycle
|
||||
case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY:
|
||||
// Should not be wrapped
|
||||
return false;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
|
@ -591,7 +591,42 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_NOP1: case OP_NOP4: case OP_NOP5:
|
||||
case OP_CHECKTEMPLATEVERIFY:
|
||||
{
|
||||
if (flags & SCRIPT_VERIFY_DISCOURAGE_CHECKTEMPLATEVERIFY) {
|
||||
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
|
||||
}
|
||||
|
||||
// if flags not enabled; treat as a NOP4
|
||||
if (!(flags & SCRIPT_VERIFY_CHECKTEMPLATEVERIFY)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (stack.size() < 1) {
|
||||
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
||||
}
|
||||
|
||||
// If the argument was not 32 bytes, treat as OP_NOP4:
|
||||
switch (stack.back().size()) {
|
||||
case 32:
|
||||
{
|
||||
const Span<const unsigned char> hash{stack.back()};
|
||||
if (!checker.CheckDefaultCheckTemplateVerifyHash(hash)) {
|
||||
return set_error(serror, SCRIPT_ERR_TEMPLATE_MISMATCH);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// future upgrade can add semantics for this opcode with different length args
|
||||
// so discourage use when applicable
|
||||
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY) {
|
||||
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_NOP1: case OP_NOP5:
|
||||
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
|
||||
{
|
||||
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
||||
@ -1377,6 +1412,18 @@ uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
|
||||
HashWriter ss{};
|
||||
for (const auto& txout : outputs_spent) {
|
||||
ss << txout.nValue;
|
||||
|
||||
}
|
||||
return ss.GetSHA256();
|
||||
}
|
||||
|
||||
/** Compute the (single) SHA256 of the concatenation of all scriptSigs in a tx. */
|
||||
template <class T>
|
||||
uint256 GetScriptSigsSHA256(const T& txTo)
|
||||
{
|
||||
HashWriter ss{};
|
||||
for (const auto& in : txTo.vin) {
|
||||
ss << in.scriptSig;
|
||||
}
|
||||
return ss.GetSHA256();
|
||||
}
|
||||
@ -1391,9 +1438,64 @@ uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
|
||||
return ss.GetSHA256();
|
||||
}
|
||||
|
||||
/* Not Exported, just convenience */
|
||||
template<typename TxType>
|
||||
uint256 GetDefaultCheckTemplateVerifyHashWithScript(
|
||||
const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash,
|
||||
const uint256& scriptSig_hash, const uint32_t input_index) {
|
||||
auto h = HashWriter{}
|
||||
<< tx.version
|
||||
<< tx.nLockTime
|
||||
<< scriptSig_hash
|
||||
<< uint32_t(tx.vin.size())
|
||||
<< sequences_hash
|
||||
<< uint32_t(tx.vout.size())
|
||||
<< outputs_hash
|
||||
<< input_index;
|
||||
return h.GetSHA256();
|
||||
}
|
||||
|
||||
template<typename TxType>
|
||||
uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(
|
||||
const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash, const uint32_t input_index) {
|
||||
auto h = HashWriter{}
|
||||
<< tx.version
|
||||
<< tx.nLockTime
|
||||
<< uint32_t(tx.vin.size())
|
||||
<< sequences_hash
|
||||
<< uint32_t(tx.vout.size())
|
||||
<< outputs_hash
|
||||
<< input_index;
|
||||
return h.GetSHA256();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template<typename TxType>
|
||||
uint256 GetDefaultCheckTemplateVerifyHash(const TxType& tx, uint32_t input_index) {
|
||||
return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequencesSHA256(tx), input_index);
|
||||
}
|
||||
|
||||
template<typename TxType>
|
||||
static bool NoScriptSigs(const TxType& tx)
|
||||
{
|
||||
return std::all_of(tx.vin.begin(), tx.vin.end(), [](const CTxIn& c) { return c.scriptSig.empty(); });
|
||||
}
|
||||
|
||||
template<typename TxType>
|
||||
uint256 GetDefaultCheckTemplateVerifyHash(
|
||||
const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash, const uint32_t input_index) {
|
||||
return NoScriptSigs(tx) ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) :
|
||||
GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index);
|
||||
}
|
||||
|
||||
template
|
||||
uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
|
||||
const uint32_t input_index);
|
||||
template
|
||||
uint256 GetDefaultCheckTemplateVerifyHash(const CMutableTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
|
||||
const uint32_t input_index);
|
||||
|
||||
template <class T>
|
||||
void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent_outputs, bool force)
|
||||
{
|
||||
@ -1427,12 +1529,19 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
|
||||
if (uses_bip341_taproot && uses_bip143_segwit) break; // No need to scan further if we already need all.
|
||||
}
|
||||
|
||||
if (uses_bip143_segwit || uses_bip341_taproot) {
|
||||
// Computations shared between both sighash schemes.
|
||||
m_prevouts_single_hash = GetPrevoutsSHA256(txTo);
|
||||
m_sequences_single_hash = GetSequencesSHA256(txTo);
|
||||
m_outputs_single_hash = GetOutputsSHA256(txTo);
|
||||
}
|
||||
// Each of these computations is always required for CHECKTEMPLATEVERIFY, and sometimes
|
||||
// required for any segwit/taproot.
|
||||
m_prevouts_single_hash = GetPrevoutsSHA256(txTo);
|
||||
m_sequences_single_hash = GetSequencesSHA256(txTo);
|
||||
m_outputs_single_hash = GetOutputsSHA256(txTo);
|
||||
|
||||
// Only required for CHECKTEMPLATEVERIFY.
|
||||
//
|
||||
// The empty hash is used to signal whether or not we should skip scriptSigs
|
||||
// when re-computing for different indexes.
|
||||
m_scriptSigs_single_hash = NoScriptSigs(txTo) ? uint256{} : GetScriptSigsSHA256(txTo);
|
||||
m_bip119_ctv_ready = true;
|
||||
|
||||
if (uses_bip143_segwit) {
|
||||
hashPrevouts = SHA256Uint256(m_prevouts_single_hash);
|
||||
hashSequence = SHA256Uint256(m_sequences_single_hash);
|
||||
@ -1781,6 +1890,22 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool GenericTransactionSignatureChecker<T>::CheckDefaultCheckTemplateVerifyHash(const Span<const unsigned char>& hash) const
|
||||
{
|
||||
// Should already be checked before calling...
|
||||
assert(hash.size() == 32);
|
||||
if (txdata && txdata->m_bip119_ctv_ready) {
|
||||
assert(txTo != nullptr);
|
||||
uint256 hash_tmpl = txdata->m_scriptSigs_single_hash.IsNull() ?
|
||||
GetDefaultCheckTemplateVerifyHashEmptyScript(*txTo, txdata->m_outputs_single_hash, txdata->m_sequences_single_hash, nIn) :
|
||||
GetDefaultCheckTemplateVerifyHashWithScript(*txTo, txdata->m_outputs_single_hash, txdata->m_sequences_single_hash,
|
||||
txdata->m_scriptSigs_single_hash, nIn);
|
||||
return std::equal(hash_tmpl.begin(), hash_tmpl.end(), hash.data());
|
||||
} else {
|
||||
return HandleMissingData(m_mdb);
|
||||
}
|
||||
}
|
||||
// explicit instantiation
|
||||
template class GenericTransactionSignatureChecker<CTransaction>;
|
||||
template class GenericTransactionSignatureChecker<CMutableTransaction>;
|
||||
|
@ -143,6 +143,15 @@ enum : uint32_t {
|
||||
// Making unknown public key versions (in BIP 342 scripts) non-standard
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
|
||||
|
||||
// CHECKTEMPLATEVERIFY validation (BIP-119)
|
||||
SCRIPT_VERIFY_CHECKTEMPLATEVERIFY = (1U << 21),
|
||||
|
||||
// discourage upgradable OP_CHECKTEMPLATEVERIFY hashes
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY = (1U << 22),
|
||||
|
||||
// discourage OP_CHECKTEMPLATEVERIFY
|
||||
SCRIPT_VERIFY_DISCOURAGE_CHECKTEMPLATEVERIFY = (1U << 23),
|
||||
|
||||
// Constants to point to the highest flag in use. Add new flags above this line.
|
||||
//
|
||||
SCRIPT_VERIFY_END_MARKER
|
||||
@ -152,6 +161,9 @@ bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned i
|
||||
|
||||
struct PrecomputedTransactionData
|
||||
{
|
||||
// Order of fields is packed below (uint256 is 32 bytes, vector is 24 bytes
|
||||
// (3 ptrs), ready flags (1 byte each).
|
||||
|
||||
// BIP341 precomputed data.
|
||||
// These are single-SHA256, see https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#cite_note-16.
|
||||
uint256 m_prevouts_single_hash;
|
||||
@ -159,15 +171,25 @@ struct PrecomputedTransactionData
|
||||
uint256 m_outputs_single_hash;
|
||||
uint256 m_spent_amounts_single_hash;
|
||||
uint256 m_spent_scripts_single_hash;
|
||||
//! Whether the 5 fields above are initialized.
|
||||
bool m_bip341_taproot_ready = false;
|
||||
|
||||
// BIP119 precomputed data (single SHA256).
|
||||
uint256 m_scriptSigs_single_hash;
|
||||
|
||||
// BIP143 precomputed data (double-SHA256).
|
||||
uint256 hashPrevouts, hashSequence, hashOutputs;
|
||||
//! Whether the 3 fields above are initialized.
|
||||
|
||||
// BIP341 cached outputs.
|
||||
std::vector<CTxOut> m_spent_outputs;
|
||||
|
||||
//! Whether the bip341 fields above are initialized.
|
||||
bool m_bip341_taproot_ready = false;
|
||||
|
||||
//! Whether the bip119 fields above are initialized.
|
||||
bool m_bip119_ctv_ready = false;
|
||||
|
||||
//! Whether the bip143 fields above are initialized.
|
||||
bool m_bip143_segwit_ready = false;
|
||||
|
||||
std::vector<CTxOut> m_spent_outputs;
|
||||
//! Whether m_spent_outputs is initialized.
|
||||
bool m_spent_outputs_ready = false;
|
||||
|
||||
@ -187,6 +209,11 @@ struct PrecomputedTransactionData
|
||||
explicit PrecomputedTransactionData(const T& tx);
|
||||
};
|
||||
|
||||
/* Standard Template Hash Declarations */
|
||||
template<typename TxType>
|
||||
uint256 GetDefaultCheckTemplateVerifyHash(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash,
|
||||
const uint32_t input_index);
|
||||
|
||||
enum class SigVersion
|
||||
{
|
||||
BASE = 0, //!< Bare scripts and BIP16 P2SH-wrapped redeemscripts
|
||||
@ -265,6 +292,11 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool CheckDefaultCheckTemplateVerifyHash(const Span<const unsigned char>& hash) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual ~BaseSignatureChecker() = default;
|
||||
};
|
||||
|
||||
@ -301,6 +333,7 @@ public:
|
||||
bool CheckSchnorrSignature(Span<const unsigned char> sig, Span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override;
|
||||
bool CheckLockTime(const CScriptNum& nLockTime) const override;
|
||||
bool CheckSequence(const CScriptNum& nSequence) const override;
|
||||
bool CheckDefaultCheckTemplateVerifyHash(const Span<const unsigned char>& hash) const override;
|
||||
};
|
||||
|
||||
using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
|
||||
|
@ -138,7 +138,7 @@ std::string GetOpName(opcodetype opcode)
|
||||
case OP_NOP1 : return "OP_NOP1";
|
||||
case OP_CHECKLOCKTIMEVERIFY : return "OP_CHECKLOCKTIMEVERIFY";
|
||||
case OP_CHECKSEQUENCEVERIFY : return "OP_CHECKSEQUENCEVERIFY";
|
||||
case OP_NOP4 : return "OP_NOP4";
|
||||
case OP_CHECKTEMPLATEVERIFY : return "OP_CHECKTEMPLATEVERIFY";
|
||||
case OP_NOP5 : return "OP_NOP5";
|
||||
case OP_NOP6 : return "OP_NOP6";
|
||||
case OP_NOP7 : return "OP_NOP7";
|
||||
@ -221,6 +221,14 @@ bool CScript::IsPayToAnchor(int version, const std::vector<unsigned char>& progr
|
||||
program[1] == 0x73;
|
||||
}
|
||||
|
||||
bool CScript::IsPayToBareDefaultCheckTemplateVerifyHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-bare-default-check-template-verify-hash CScripts:
|
||||
return (this->size() == 34 &&
|
||||
(*this)[0] == 0x20 &&
|
||||
(*this)[33] == OP_CHECKTEMPLATEVERIFY);
|
||||
}
|
||||
|
||||
bool CScript::IsPayToScriptHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-script-hash CScripts:
|
||||
|
@ -198,7 +198,8 @@ enum opcodetype
|
||||
OP_NOP2 = OP_CHECKLOCKTIMEVERIFY,
|
||||
OP_CHECKSEQUENCEVERIFY = 0xb2,
|
||||
OP_NOP3 = OP_CHECKSEQUENCEVERIFY,
|
||||
OP_NOP4 = 0xb3,
|
||||
OP_CHECKTEMPLATEVERIFY = 0xb3,
|
||||
OP_NOP4 = OP_CHECKTEMPLATEVERIFY,
|
||||
OP_NOP5 = 0xb4,
|
||||
OP_NOP6 = 0xb5,
|
||||
OP_NOP7 = 0xb6,
|
||||
@ -552,6 +553,8 @@ public:
|
||||
*/
|
||||
static bool IsPayToAnchor(int version, const std::vector<unsigned char>& program);
|
||||
|
||||
bool IsPayToBareDefaultCheckTemplateVerifyHash() const;
|
||||
|
||||
bool IsPayToScriptHash() const;
|
||||
bool IsPayToWitnessScriptHash() const;
|
||||
bool IsWitnessProgram(int& version, std::vector<unsigned char>& program) const;
|
||||
|
@ -25,6 +25,8 @@ std::string ScriptErrorString(const ScriptError serror)
|
||||
return "Script failed an OP_CHECKSIGVERIFY operation";
|
||||
case SCRIPT_ERR_NUMEQUALVERIFY:
|
||||
return "Script failed an OP_NUMEQUALVERIFY operation";
|
||||
case SCRIPT_ERR_TEMPLATE_MISMATCH:
|
||||
return "Script failed an OP_CHECKTEMPLATEVERIFY operation";
|
||||
case SCRIPT_ERR_SCRIPT_SIZE:
|
||||
return "Script is too big";
|
||||
case SCRIPT_ERR_PUSH_SIZE:
|
||||
|
@ -29,6 +29,7 @@ typedef enum ScriptError_t
|
||||
SCRIPT_ERR_CHECKMULTISIGVERIFY,
|
||||
SCRIPT_ERR_CHECKSIGVERIFY,
|
||||
SCRIPT_ERR_NUMEQUALVERIFY,
|
||||
SCRIPT_ERR_TEMPLATE_MISMATCH,
|
||||
|
||||
/* Logical/Format/Canonical errors */
|
||||
SCRIPT_ERR_BAD_OPCODE,
|
||||
|
@ -412,6 +412,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator
|
||||
case TxoutType::NONSTANDARD:
|
||||
case TxoutType::NULL_DATA:
|
||||
case TxoutType::WITNESS_UNKNOWN:
|
||||
case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY:
|
||||
return false;
|
||||
case TxoutType::PUBKEY:
|
||||
if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false;
|
||||
|
@ -29,6 +29,7 @@ std::string GetTxnOutputType(TxoutType t)
|
||||
case TxoutType::WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash";
|
||||
case TxoutType::WITNESS_V1_TAPROOT: return "witness_v1_taproot";
|
||||
case TxoutType::WITNESS_UNKNOWN: return "witness_unknown";
|
||||
case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY: return "bare_default_ctv_hash";
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
assert(false);
|
||||
}
|
||||
@ -151,6 +152,10 @@ TxoutType Solver(const CScript& scriptPubKey, std::vector<std::vector<unsigned c
|
||||
return TxoutType::SCRIPTHASH;
|
||||
}
|
||||
|
||||
if (scriptPubKey.IsPayToBareDefaultCheckTemplateVerifyHash()) {
|
||||
return TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY;
|
||||
}
|
||||
|
||||
int witnessversion;
|
||||
std::vector<unsigned char> witnessprogram;
|
||||
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
|
||||
|
@ -31,6 +31,7 @@ enum class TxoutType {
|
||||
WITNESS_V0_SCRIPTHASH,
|
||||
WITNESS_V0_KEYHASH,
|
||||
WITNESS_V1_TAPROOT,
|
||||
TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY,
|
||||
WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above
|
||||
};
|
||||
|
||||
|
@ -34,6 +34,7 @@ add_executable(test_bitcoin
|
||||
compilerbug_tests.cpp
|
||||
compress_tests.cpp
|
||||
crypto_tests.cpp
|
||||
ctvhash_tests.cpp
|
||||
cuckoocache_tests.cpp
|
||||
dbwrapper_tests.cpp
|
||||
denialofservice_tests.cpp
|
||||
@ -130,6 +131,7 @@ target_json_data_sources(test_bitcoin
|
||||
data/base58_encode_decode.json
|
||||
data/bip341_wallet_vectors.json
|
||||
data/blockfilters.json
|
||||
data/ctvhash.json
|
||||
data/key_io_invalid.json
|
||||
data/key_io_valid.json
|
||||
data/script_tests.json
|
||||
|
198
src/test/ctvhash_tests.cpp
Normal file
198
src/test/ctvhash_tests.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2013-2021 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 <core_io.h>
|
||||
#include <consensus/tx_check.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <hash.h>
|
||||
#include <script/interpreter.h>
|
||||
#include <serialize.h>
|
||||
#include <streams.h>
|
||||
#include <test/data/ctvhash.json.h>
|
||||
#include <test/util/json.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <common/system.h>
|
||||
#include <random.h>
|
||||
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE(ctvhash_tests, BasicTestingSetup)
|
||||
|
||||
// Goal: check that CTV Hash Functions generate correct hash
|
||||
BOOST_AUTO_TEST_CASE(ctvhash_from_data)
|
||||
{
|
||||
UniValue tests = read_json(std::string(json_tests::ctvhash));
|
||||
|
||||
for (unsigned int idx = 0; idx < tests.size(); idx++) {
|
||||
const UniValue& test = tests[idx];
|
||||
std::string strTest = test.write();
|
||||
// comment
|
||||
if (test.isStr())
|
||||
continue;
|
||||
else if (test.isObject()) {
|
||||
std::vector<uint256> hash;
|
||||
std::vector<uint32_t> spend_index;
|
||||
|
||||
try {
|
||||
auto& hash_arr = test["result"].get_array();
|
||||
for (size_t i = 0; i < hash_arr.size(); ++i) {
|
||||
hash.emplace_back();
|
||||
hash.back().SetHexDeprecated(hash_arr[i].get_str());
|
||||
// reverse because python's sha256().digest().hex() is
|
||||
// backwards
|
||||
std::reverse(hash.back().begin(), hash.back().end());
|
||||
}
|
||||
} catch (...) {
|
||||
BOOST_ERROR("Bad test: Results could not be deserialized" << strTest);
|
||||
break;
|
||||
}
|
||||
try {
|
||||
auto& spend_index_arr = test["spend_index"].get_array();
|
||||
for (size_t i = 0; i < spend_index_arr.size(); ++i) {
|
||||
spend_index.emplace_back(spend_index_arr[i].getInt<uint32_t>());
|
||||
}
|
||||
} catch (...) {
|
||||
BOOST_ERROR("Bad test: spend_index could not be deserialized" << strTest);
|
||||
break;
|
||||
}
|
||||
if (spend_index.size() != hash.size()) {
|
||||
BOOST_ERROR("Bad test: Spend Indexes not same length as Result Hashes: " << strTest);
|
||||
break;
|
||||
}
|
||||
CMutableTransaction tx;
|
||||
try {
|
||||
// deserialize test data
|
||||
BOOST_CHECK(DecodeHexTx(tx, test["hex_tx"].get_str()));
|
||||
} catch (...) {
|
||||
BOOST_ERROR("Bad test, couldn't deserialize hex_tx: " << strTest);
|
||||
continue;
|
||||
}
|
||||
const PrecomputedTransactionData data{tx};
|
||||
for (size_t i = 0; i < hash.size(); ++i) {
|
||||
uint256 sh = GetDefaultCheckTemplateVerifyHash(tx, data.m_outputs_single_hash, data.m_sequences_single_hash, spend_index[i]);
|
||||
if (sh != hash[i]) {
|
||||
BOOST_ERROR("Expected: " << sh << " Got: " << hash[i] << " For:\n"
|
||||
<< strTest);
|
||||
}
|
||||
}
|
||||
// Change all of the outpoints and there should be no difference.
|
||||
FastRandomContext fr;
|
||||
|
||||
for (auto i = 0; i < 200; ++i) {
|
||||
CMutableTransaction txc = tx;
|
||||
bool hash_will_change = false;
|
||||
// do n mutations, 50% of being 1, 50% chance of being 2-11
|
||||
const uint64_t n_mutations = fr.randbool()? (fr.randrange(10)+2) : 1;
|
||||
for (uint64_t j = 0; j < n_mutations; ++j) {
|
||||
// on the first 50 passes, modify in ways that will not change hash
|
||||
const int mutate_field = i < 50 ? fr.randrange(2) : fr.randrange(10);
|
||||
switch (mutate_field) {
|
||||
case 0: {
|
||||
if (tx.vin.size() > 0) {
|
||||
// no need to rejection sample on 256 bits
|
||||
const auto which = fr.randrange(tx.vin.size());
|
||||
tx.vin[which].prevout = {Txid::FromUint256(fr.rand256()), fr.rand32()};
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
if (tx.vin.size() > 0) {
|
||||
const auto which = fr.randrange(tx.vin.size());
|
||||
tx.vin[which].scriptWitness.stack.push_back(fr.randbytes(500));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// Mutate a scriptSig
|
||||
txc.vin[0].scriptSig.push_back('x');
|
||||
hash_will_change = true;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// Mutate a sequence
|
||||
do {
|
||||
txc.vin.back().nSequence = fr.rand32();
|
||||
} while (txc.vin.back().nSequence == tx.vin.back().nSequence);
|
||||
hash_will_change = true;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
// Mutate version
|
||||
do {
|
||||
txc.version = fr.rand<int32_t>();
|
||||
} while (txc.version == tx.version);
|
||||
hash_will_change = true;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
if (tx.vin.size() > 0) {
|
||||
// Mutate output amount
|
||||
const auto which = fr.randrange(tx.vout.size());
|
||||
txc.vout[which].nValue += 1;
|
||||
hash_will_change = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 6: {
|
||||
if (tx.vin.size() > 0) {
|
||||
// Mutate output script
|
||||
const auto which = fr.randrange(tx.vout.size());
|
||||
txc.vout[which].scriptPubKey.push_back('x');
|
||||
hash_will_change = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 7: {
|
||||
// Mutate nLockTime
|
||||
do {
|
||||
txc.nLockTime = fr.rand32();
|
||||
} while (txc.nLockTime == tx.nLockTime);
|
||||
hash_will_change = true;
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
// don't add and remove for a mutation otherwise it may end up valid
|
||||
break;
|
||||
}
|
||||
case 9: {
|
||||
// don't add and remove for a mutation otherwise it may end up valid
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
const PrecomputedTransactionData data_txc{txc};
|
||||
// iterate twice, one time with the correct spend indexes, one time with incorrect.
|
||||
for (auto use_random_index = 0; use_random_index < 2; ++use_random_index) {
|
||||
hash_will_change |= use_random_index != 0;
|
||||
for (size_t i = 0; i < hash.size(); ++i) {
|
||||
uint32_t index{spend_index[i]};
|
||||
while (use_random_index && index == spend_index[i]) {
|
||||
index = fr.rand32();
|
||||
}
|
||||
uint256 sh = GetDefaultCheckTemplateVerifyHash(txc, data_txc.m_outputs_single_hash, data_txc.m_sequences_single_hash, index);
|
||||
const bool hash_equals = sh == hash[i];
|
||||
if (hash_will_change && hash_equals) {
|
||||
BOOST_ERROR("Expected: NOT " << hash[i] << " Got: " << sh << " For:\n"
|
||||
<< strTest);
|
||||
} else if (!hash_will_change && !hash_equals) {
|
||||
BOOST_ERROR("Expected: " << hash[i] << " Got: " << sh << " For:\n"
|
||||
<< strTest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
BOOST_ERROR("Bad test: " << strTest);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
2204
src/test/data/ctvhash.json
Normal file
2204
src/test/data/ctvhash.json
Normal file
File diff suppressed because one or more lines are too long
@ -244,8 +244,8 @@
|
||||
["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC", "OK"],
|
||||
|
||||
|
||||
["1","NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC", "OK"],
|
||||
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC", "OK"],
|
||||
["1","NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY CHECKTEMPLATEVERIFY NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC", "OK"],
|
||||
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY CHECKTEMPLATEVERIFY NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC", "OK"],
|
||||
|
||||
["1", "NOP", "P2SH,STRICTENC,DISCOURAGE_UPGRADABLE_NOPS", "OK", "Discourage NOPx flag allows OP_NOP"],
|
||||
|
||||
@ -456,7 +456,7 @@
|
||||
["NOP", "NOP1 1", "P2SH,STRICTENC", "OK"],
|
||||
["NOP", "CHECKLOCKTIMEVERIFY 1", "P2SH,STRICTENC", "OK"],
|
||||
["NOP", "CHECKSEQUENCEVERIFY 1", "P2SH,STRICTENC", "OK"],
|
||||
["NOP", "NOP4 1", "P2SH,STRICTENC", "OK"],
|
||||
["NOP", "CHECKTEMPLATEVERIFY 1", "P2SH,STRICTENC", "OK"],
|
||||
["NOP", "NOP5 1", "P2SH,STRICTENC", "OK"],
|
||||
["NOP", "NOP6 1", "P2SH,STRICTENC", "OK"],
|
||||
["NOP", "NOP7 1", "P2SH,STRICTENC", "OK"],
|
||||
@ -870,12 +870,11 @@
|
||||
["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
|
||||
["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "DISABLED_OPCODE", "disabled"],
|
||||
|
||||
["1", "NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
|
||||
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
|
||||
["1", "NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY CHECKTEMPLATEVERIFY NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
|
||||
["'NOP_1_to_10' NOP1 CHECKLOCKTIMEVERIFY CHECKSEQUENCEVERIFY CHECKTEMPLATEVERIFY NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC", "EVAL_FALSE"],
|
||||
|
||||
["Ensure 100% coverage of discouraged NOPS"],
|
||||
["1", "NOP1", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
|
||||
["1", "NOP4", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
|
||||
["1", "NOP5", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
|
||||
["1", "NOP6", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
|
||||
["1", "NOP7", "P2SH,DISCOURAGE_UPGRADABLE_NOPS", "DISCOURAGE_UPGRADABLE_NOPS"],
|
||||
|
@ -393,5 +393,100 @@
|
||||
["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]],
|
||||
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "CONST_SCRIPTCODE"],
|
||||
|
||||
["CheckTemplateVerify (CTV) Tests"],
|
||||
["Modified Segwit OP_CTV Spend Failed if Amount Mutated"],
|
||||
[[["10bf165531fbdfac386f018d92d72dce3ad73af1f183f6fac2c7a2a1050aa51b",
|
||||
0,
|
||||
"0x00 0x20 0x9e650578b4f13cde08d16211f3635239e22ba3e108ba7f5fa4bd6c12f8c8219a",
|
||||
155000]],
|
||||
"020000000001011ba50a05a1a2c7c2faf683f1f13ad73ace2dd7928d016f38acdffb315516bf100000000000000000000ae90300000000000017a9142b697af70a75926b158a2ea0aab8054eb18490ac87d00700000000000017a9143177919dae74db1c4cd3e6e69861091c6aee9eb287b80b00000000000017a91417d751e7c17c8264e90e4831fed9c47804b2bbc887a00f00000000000017a914a46167b1fbca936b56dda9710a0c16a53fd32fe687881300000000000017a914b4a5ddbdda32760d1c61dd131007fd7e67d650e187701700000000000017a91480909aab0729614b1162d86563cbfb0c71d5bc9e87581b00000000000017a914997c99e26f67463a1f9770003f90603360408bed87401f00000000000017a9149fef27cd2e724889aa522ac6b5eb35de7582727487282300000000000017a914c7c616d8323c7046de863e2301ec0c7884626e9687102700000000000017a914b590ca292351b64cbf725bad01c3ba6da808ab0b870122200a2891d90df11c7714549c76b80b29c86d544110d958a6dabcfcd5cda1612427b300000000",
|
||||
"CHECKTEMPLATEVERIFY,WITNESS,P2SH"],
|
||||
|
||||
["Modified Segwit OP_CTV Spend Failed if # inputs Mutated"],
|
||||
[[["7438c73c9a554540dce173b485e888683e9ae5beae3ae94142e77ae2cc024e3c",
|
||||
0,
|
||||
"0x00 0x20 0xc19287614d027e87b85ace418cb0fc2d89241392370f0f7cf2ebb06b861c85f0",
|
||||
155000],
|
||||
["24040d2cd61f2ecb67e9fe5634c1d90e59b6b16028ff03003cf20f398ce27e44",
|
||||
0,
|
||||
"1",
|
||||
155000]],
|
||||
"020000000001023c4e02cce27ae74241e93aaebee59a3e6888e885b473e1dc4045559a3cc73874000000000000000000447ee28c390ff23c0003ff2860b1b6590ed9c13456fee967cb2e1fd62c0d04240000000000000000000ae90300000000000017a91406651b0a47731127630ccc27d07fb9afc041846987d00700000000000017a914c758d7ce652d5ed562253ed00e9afc34ea1f76bf87b80b00000000000017a914fe8740b477b23838679c7eaa6e452e66c58a72bc87a00f00000000000017a914cc07d98fc32e2ff65f62076f2824d63bd5a1628787881300000000000017a914acfb84e8356788c7a8312194d1833e5d5677d58e87701700000000000017a91409aad9fbb6609e4486fa5b04afbbde40659388f787581b00000000000017a914ffd3dc8f12ebb700dd45a6a58914347533b6728587401f00000000000017a914781456255e72a09dfab2211dc151165c62ab7af987282300000000000017a914ee01dfa11feb2bc68b22d6909052647c8c001ec787102700000000000017a9145dd4e76cb2cef90e09f181c55fdc42717f3d948787012220cf100c0bb5dc85c104d87c31e7b57a4a7791cc2091dc87ddaac40c91edda7f6bb30000000000",
|
||||
"CHECKTEMPLATEVERIFY,WITNESS,P2SH"],
|
||||
["Wrong Size CTV Argument is Discouraged"],
|
||||
[[["13e313be0d1eab290bcf2b58f4ad76c3f4fd46b2ac4273c607cdc7f5a4170794",
|
||||
0,
|
||||
"0x00 0x20 0xaeba7cb39e708a34dd186698a80cc34e70bb92921a01f853ac691bb572b52d62",
|
||||
155000]],
|
||||
"02000000000101940717a4f5c7cd07c67342acb246fdf4c376adf4582bcf0b29ab1e0dbe13e3130000000000000000000ae90300000000000017a914f0ccedba146f6390e5961b2a0a39cfba046c312987d00700000000000017a91458d4792223eebb552801d6690b5985513fbddaca87b80b00000000000017a914774b6fe872b65890c610ec6edda928703fe8503e87a00f00000000000017a9148ad37662e56b5f2e472e4bdc205f0dcde8708fd787881300000000000017a9149e8680d850f172186f4e16cee442f0d0121fd46e87701700000000000017a9141394792d48889f70878ce2ee3b151de33d4b774987581b00000000000017a9142444dbb85cf5dfa3e94d2a970a4d4bb795495df687401f00000000000017a914b0437ba6b526e697e695d4f8a53482d26547b64f87282300000000000017a91408ceb5466bc28db2122f954ca59d4a4a08fc133b87102700000000000017a91486f51c990634abc769d6d9d01608ff99f93b050387010251b300000000",
|
||||
"CHECKTEMPLATEVERIFY,WITNESS,P2SH,DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["Empty Stack is Rejected for CTV"],
|
||||
[[["e658e5b94eba5931faf2379a61a75a05b153648690527d35f7143bed462a6ebc",
|
||||
0,
|
||||
"0x00 0x20 0x6c9cc4747e7d287ac1abf8c65152a78d369213583e306b7d3163e12c561abaa2",
|
||||
155000]],
|
||||
"02000000000101bc6e2a46ed3b14f7357d5290866453b1055aa7619a37f2fa3159ba4eb9e558e60000000000000000000ae90300000000000017a914b038d0ca030a6d6bc4a06bda13ae1413ce96f37e87d00700000000000017a914fa5716162fb8f5f3cafdce1c1f5533e182c83f4d87b80b00000000000017a91417d10dea89621354333f4dfcbdafe18ec6a794da87a00f00000000000017a9142abb09f63aaecdfbe0e92fedc0afedf19194360187881300000000000017a914aab8b0219014272348de62cbc195e20151b7735787701700000000000017a914a507b83449359c82a195fc9bab99fa1b7c8289eb87581b00000000000017a91401ea6e7336fb9d5e5f36994eecade840ba938d0687401f00000000000017a914e5a474adbd25d66bb70c9b0b6a27f3eebf70b3f587282300000000000017a914d4ae33b227632cf0434f054782558baf9aa6e42d87102700000000000017a9147e4cca8f6c63cb7a56dd3c6edd2acbd031813de9870106b3746375685100000000",
|
||||
"CHECKTEMPLATEVERIFY,WITNESS,P2SH"],
|
||||
|
||||
["Wrong Size Stack Argument is Discouraged for CTV"],
|
||||
[[["e658e5b94eba5931faf2379a61a75a05b153648690527d35f7143bed462a6ebc",
|
||||
0,
|
||||
"0x00 0x20 0x6c9cc4747e7d287ac1abf8c65152a78d369213583e306b7d3163e12c561abaa2",
|
||||
155000]],
|
||||
"02000000000101bc6e2a46ed3b14f7357d5290866453b1055aa7619a37f2fa3159ba4eb9e558e60000000000000000000ae90300000000000017a914b038d0ca030a6d6bc4a06bda13ae1413ce96f37e87d00700000000000017a914fa5716162fb8f5f3cafdce1c1f5533e182c83f4d87b80b00000000000017a91417d10dea89621354333f4dfcbdafe18ec6a794da87a00f00000000000017a9142abb09f63aaecdfbe0e92fedc0afedf19194360187881300000000000017a914aab8b0219014272348de62cbc195e20151b7735787701700000000000017a914a507b83449359c82a195fc9bab99fa1b7c8289eb87581b00000000000017a91401ea6e7336fb9d5e5f36994eecade840ba938d0687401f00000000000017a914e5a474adbd25d66bb70c9b0b6a27f3eebf70b3f587282300000000000017a914d4ae33b227632cf0434f054782558baf9aa6e42d87102700000000000017a9147e4cca8f6c63cb7a56dd3c6edd2acbd031813de98702015106b3746375685100000000",
|
||||
"CHECKTEMPLATEVERIFY,WITNESS,P2SH,DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["Wrong TX Hash passed via the stack fails CTV"],
|
||||
[[["1303ae3fc607b6eb3a4da63d3d7f4722b595db87890943618e11c3905662cae4",
|
||||
0,
|
||||
"0x00 0x20 0x6c9cc4747e7d287ac1abf8c65152a78d369213583e306b7d3163e12c561abaa2",
|
||||
155000]],
|
||||
"02000000000101e4ca625690c3118e6143098987db95b522477f3d3da64d3aebb607c63fae03130000000000000000000ae90300000000000017a9145850541d205b7b1feb1bc10112f9d739fa9a7dc287d00700000000000017a914d76b85e77e20777d5ec9d7d9998ae0c062d4669087b80b00000000000017a914c79f4a39b0580e4ec90e1b4989fc6124e4135cc187a00f00000000000017a91469635f1f4c06d66591282a02303b1435ee888d9487881300000000000017a91410d3b9b2aaffae25b6098169e2dc69928849215387701700000000000017a91456e4a3e5a3a49b9a66240288e79a8a5e8e31d05587581b00000000000017a9143936403d1a70b32c1e0e6920f9cd99cbc8a8345787401f00000000000017a9146ec4fa5a4e329f9d92ea29b65fa48c6ec1470ffa87282300000000000017a914f66743d56210c98bce8a44742b2ecfa9b7f48fdb87102700000000000017a914555c65f1c355993b46003311931eb08cf457209b870220a2638b51a692e6a8b39e87c431edde4fc1ada3dedaf9665875ac8353af44c50706b3746375685100000000",
|
||||
"CHECKTEMPLATEVERIFY,WITNESS,P2SH"],
|
||||
|
||||
["Embedded CTV Impossible with Bare P2SH due to hash cycle"],
|
||||
[[["6a869fd9a0395f35e412ad3eb7fffa61a59263b1ad16aeb5fcc30e032bc3a8bf",
|
||||
0,
|
||||
"OP_HASH160 0x14 0x40aec8967698985eb369afd3ad3dc571110e6a10 OP_EQUAL",
|
||||
155000]],
|
||||
"0200000001bfa8c32b030ec3fcb5ae16adb16392a561faffb73ead12e4355f39a0d99f866a000000002322203b8d241649e612058fd2f1b4decbe9141284f0e4dd297d95b0da01a5d8791e4bb3000000000ae90300000000000017a914b04d55bbfedf606a08795fb0c2655bb3212f2bde87d00700000000000017a914d079c2cfad655234e68159422727eefa78811b4787b80b00000000000017a9145ea3edd87eb790af8051da692f4d59e5be6ffd4b87a00f00000000000017a914e17e2c4f4fcae1ef0d5ef96c740565426009ca2187881300000000000017a9144769d9f3b6fdf14f1223d9e7f11be7873bcbcde387701700000000000017a914064529bab7b89253159c9043ef128f37f78add7a87581b00000000000017a9147bae64476db031d744b442ddee9af3e60ef1e4ea87401f00000000000017a914dd2d96d0ba673c0b9d5950223c334f19f2b6f4a487282300000000000017a9148abaaa7b977855f96afacea4c79e3caf5e7482c487102700000000000017a9140dab14b1ee04aea522639ee27d29a5f6a57758c18700000000",
|
||||
"CHECKTEMPLATEVERIFY,P2SH"],
|
||||
|
||||
["CTV at pos 2 with >1 Input Fails if too few inputs"],
|
||||
[[["eeda9ea077b04abec103ffbba6bcf41cd67cdfdabe5ccc6ed766b9cd4ed4808a",
|
||||
0,
|
||||
"0x20 0x3e123dbe62352fa40471c195aebd3cdec43cca8728520c8a2d5737009fa05b0b OP_CHECKTEMPLATEVERIFY",
|
||||
155000]],
|
||||
"02000000018a80d44ecdb966d76ecc5cbedadf7cd61cf4bca6bbff03c1be4ab077a09edaee0000000000000000000ae80300000000000017a9144dd991d2f69eed133bb9d16e298703c830e1fb2387d00700000000000017a9147a50ac55b0af704dfffc797c507db803488ad44787b80b00000000000017a914caab97b53be0b75526e011bc49b0101365f611b887a00f00000000000017a91448c947e1b16103782a7dcba1dd5896936fbc7d2587881300000000000017a914ff075d852727e7e32ff5e11b13d254cb553fb73287701700000000000017a914761069764474d5ef5d0e068e88e4ebe2edd2336087581b00000000000017a914cd76c979ed6421f5d39380b5eb3d0dc7f56e864b87401f00000000000017a91417e7563571166469e14275be7ef00d91927eee0387282300000000000017a9140f9ddd36a76392fec584f05b34d33282fbd4921287102700000000000017a91417603536acce13cf7496387f8169a7f832f08f4c8700000000",
|
||||
"CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["CTV at pos 2 with >1 Input Fails if inputs in wrong order"],
|
||||
[[["eeda9ea077b04abec103ffbba6bcf41cd67cdfdabe5ccc6ed766b9cd4ed4808a",
|
||||
0,
|
||||
"0x20 0x3e123dbe62352fa40471c195aebd3cdec43cca8728520c8a2d5737009fa05b0b OP_CHECKTEMPLATEVERIFY",
|
||||
155000],
|
||||
["b6d623f1e5eaaaa83a21739f60ac173818ce6b9e13ca18ddda74e9dbe6124c0b", 0, "1", 155000]],
|
||||
"02000000028a80d44ecdb966d76ecc5cbedadf7cd61cf4bca6bbff03c1be4ab077a09edaee0000000000000000000b4c12e6dbe974dadd18ca139e6bce183817ac609f73213aa8aaeae5f123d6b60000000000000000000ae80300000000000017a9144dd991d2f69eed133bb9d16e298703c830e1fb2387d00700000000000017a9147a50ac55b0af704dfffc797c507db803488ad44787b80b00000000000017a914caab97b53be0b75526e011bc49b0101365f611b887a00f00000000000017a91448c947e1b16103782a7dcba1dd5896936fbc7d2587881300000000000017a914ff075d852727e7e32ff5e11b13d254cb553fb73287701700000000000017a914761069764474d5ef5d0e068e88e4ebe2edd2336087581b00000000000017a914cd76c979ed6421f5d39380b5eb3d0dc7f56e864b87401f00000000000017a91417e7563571166469e14275be7ef00d91927eee0387282300000000000017a9140f9ddd36a76392fec584f05b34d33282fbd4921287102700000000000017a91417603536acce13cf7496387f8169a7f832f08f4c8700000000",
|
||||
"CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["CTV at pos 2 with >1 Input Fails if scriptSig of other input modified"],
|
||||
[[["eeda9ea077b04abec103ffbba6bcf41cd67cdfdabe5ccc6ed766b9cd4ed4808a",
|
||||
0,
|
||||
"0x20 0x3e123dbe62352fa40471c195aebd3cdec43cca8728520c8a2d5737009fa05b0b OP_CHECKTEMPLATEVERIFY",
|
||||
155000],
|
||||
["b6d623f1e5eaaaa83a21739f60ac173818ce6b9e13ca18ddda74e9dbe6124c0b", 0, "1", 155000]],
|
||||
"02000000020b4c12e6dbe974dadd18ca139e6bce183817ac609f73213aa8aaeae5f123d6b6000000000151000000008a80d44ecdb966d76ecc5cbedadf7cd61cf4bca6bbff03c1be4ab077a09edaee0000000000000000000ae80300000000000017a9144dd991d2f69eed133bb9d16e298703c830e1fb2387d00700000000000017a9147a50ac55b0af704dfffc797c507db803488ad44787b80b00000000000017a914caab97b53be0b75526e011bc49b0101365f611b887a00f00000000000017a91448c947e1b16103782a7dcba1dd5896936fbc7d2587881300000000000017a914ff075d852727e7e32ff5e11b13d254cb553fb73287701700000000000017a914761069764474d5ef5d0e068e88e4ebe2edd2336087581b00000000000017a914cd76c979ed6421f5d39380b5eb3d0dc7f56e864b87401f00000000000017a91417e7563571166469e14275be7ef00d91927eee0387282300000000000017a9140f9ddd36a76392fec584f05b34d33282fbd4921287102700000000000017a91417603536acce13cf7496387f8169a7f832f08f4c8700000000",
|
||||
"CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["CTV at pos 1 with specific scriptsigs fails with incorrect scriptSig"],
|
||||
[[["a2522fa96033c5736f3142ff616426cd03a3d0f077f609e22c5a33a96e04e597",
|
||||
0,
|
||||
"0x20 0x4870387ef3dc7b392294140a323ec7b38dc138710f0931ce27f386a57128ea63 OP_CHECKTEMPLATEVERIFY",
|
||||
155000],
|
||||
["b6d623f1e5eaaaa83a21739f60ac173818ce6b9e13ca18ddda74e9dbe6124c0b", 0, "1", 155000]],
|
||||
"020000000297e5046ea9335a2ce209f677f0d0a303cd266461ff42316f73c53360a92f52a2000000000151000000000b4c12e6dbe974dadd18ca139e6bce183817ac609f73213aa8aaeae5f123d6b6000000000151000000000ae80300000000000017a9143f163a8747557345ce2e6fe00c1894f2f281795e87d00700000000000017a9144cf13dfda93a7413b7e646611735656e5457657087b80b00000000000017a914868998b49df649c37a88d48c9d4a5b37290e507287a00f00000000000017a914034f9914a77571a6396482e9881745c92c3037c687881300000000000017a914a8238003e1732e2baf4334a8546d72be99af9bae87701700000000000017a91491dbac5d67d5941115a03fc7eaec09f31a5b4dfc87581b00000000000017a914e0c0f19fec3b2993b9c116c798b5429d4515596687401f00000000000017a914d6b40d98d94530f1a1eb57614680813c81a95ccd87282300000000000017a914fb0bfb072bb79611a4323981828108a3cf54b0a687102700000000000017a9149e2d11f06ba667e981b802af10be8dabd08eafff8700000000",
|
||||
"CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||
]
|
||||
|
@ -520,5 +520,157 @@
|
||||
[[["1111111111111111111111111111111111111111111111111111111111111111", 0, "0x00 0x14 0x751e76e8199196d454941c45d1b3a323f1433bd6", 5000000]],
|
||||
"0100000000010111111111111111111111111111111111111111111111111111111111111111110000000000ffffffff0130244c0000000000fd02014cdc1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111175210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac02483045022100c1a4a6581996a7fdfea77d58d537955a5655c1d619b6f3ab6874f28bb2e19708022056402db6fede03caae045a3be616a1a2d0919a475ed4be828dc9ff21f24063aa01210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179800000000", "NONE"],
|
||||
|
||||
["Check that CTV is Processed with a Taproot Spend"],
|
||||
[[["f90521604b56c392ffa17a01bcae5914b8cf7728cc6cec00d90838818cc5465f", 0, "1 0x20 0x24f5fe807bcee7774dc515f0b7ee8d6ae39eefd1b590264c52ff867e22c49419", 155000]],
|
||||
"020000000001015f46c58c813808d900ec6ccc2877cfb81459aebc017aa1ff92c3564b602105f90000000000000000000ae80300000000000017a914ce0036ae7d49f06967dd92cc1ffff4a878c457f987d00700000000000017a91406e00c3b362e65e03507a2858d7b6499b668669887b80b00000000000017a9142ee42c65592c59b69bfefbd03781140c67e5232487a00f00000000000017a9146b3df16a1e6651d582ca6598900cb4f2d6c9dfb887881300000000000017a914877d55932d4f38b476d4db27e4efbe159ff0a07187701700000000000017a91441e9dc892e861d252d513d594ba833cd6bc8917087581b00000000000017a914b93075800c693dcc78b0553bf9d1cf879d76a02487401f00000000000017a914e9f0ea3a2cae0ad01114e2ec3502ef08bbc50af487282300000000000017a9149a645b5293bdf8be72cb9d1460bce7d64445cfad87102700000000000017a91451e5d6b2ee24ae128234c92245df3624620ea7d3870222209eb65498bfcd4eb90e61c2c5e323a9c16c8bfd8d53ba649915bcdb572099c12fb321c0b7e0105780185688d998a8f8438aa07637a5799755688ec80175cb26c0406e0200000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["Check that CTV upgradability works (taproot)"],
|
||||
[[["f90521604b56c392ffa17a01bcae5914b8cf7728cc6cec00d90838818cc5465f", 0, "1 0x20 0x24f5fe807bcee7774dc515f0b7ee8d6ae39eefd1b590264c52ff867e22c49419", 155000]],
|
||||
"020000000001015f46c58c813808d900ec6ccc2877cfb81459aebc017aa1ff92c3564b602105f90000000000000000000ae80300000000000017a914ce0036ae7d49f06967dd92cc1ffff4a878c457f987d00700000000000017a91406e00c3b362e65e03507a2858d7b6499b668669887b80b00000000000017a9142ee42c65592c59b69bfefbd03781140c67e5232487a00f00000000000017a9146b3df16a1e6651d582ca6598900cb4f2d6c9dfb887881300000000000017a914877d55932d4f38b476d4db27e4efbe159ff0a07187701700000000000017a91441e9dc892e861d252d513d594ba833cd6bc8917087581b00000000000017a914b93075800c693dcc78b0553bf9d1cf879d76a02487401f00000000000017a914e9f0ea3a2cae0ad01114e2ec3502ef08bbc50af487282300000000000017a9149a645b5293bdf8be72cb9d1460bce7d64445cfad87102700000000000017a91451e5d6b2ee24ae128234c92245df3624620ea7d3870222209eb65498bfcd4eb90e61c2c5e323a9c16c8bfd8d53ba649915bcdb572099c12fb321c0b7e0105780185688d998a8f8438aa07637a5799755688ec80175cb26c0406e0200000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["Segwit v0 CTV Spend"],
|
||||
[[["c16621d89637274011a8fb02ac487d283367f33d36de8c1ec8e323e55cb149cb",
|
||||
0,
|
||||
"0x00 0x20 0xf47ad51491d952cb1fad0d3f208dde482561d2170ebbbbc08e2e0292eeb4ec3d",
|
||||
155000]],
|
||||
"02000000000101cb49b15ce523e3c81e8cde363df36733287d48ac02fba81140273796d82166c10000000000000000000ae80300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d1870122207427029cbb0a48361ba1b83e4fff21918618477be3d217d83b2ff846815305f6b300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["Check that CTV upgradability works (Segwit v0)"],
|
||||
[[["c16621d89637274011a8fb02ac487d283367f33d36de8c1ec8e323e55cb149cb",
|
||||
0,
|
||||
"0x00 0x20 0xf47ad51491d952cb1fad0d3f208dde482561d2170ebbbbc08e2e0292eeb4ec3d",
|
||||
155000]],
|
||||
"02000000000101cb49b15ce523e3c81e8cde363df36733287d48ac02fba81140273796d82166c10000000000000000000ae80300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d1870122207427029cbb0a48361ba1b83e4fff21918618477be3d217d83b2ff846815305f6b300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["CTV reserves different sized args for future upgrades"],
|
||||
[[["e8e9805801b7fb44814531de0dd498b955651b9c25a85a043d73f18970622647",
|
||||
0,
|
||||
"0x00 0x20 0x65f15821061635e6807f06701bf0a12d8e89dcff88df5968bd0822c9dbb52f1c",
|
||||
155000]],
|
||||
"020000000001014726627089f1733d045aa8259c1b6555b998d40dde31458144fbb7015880e9e80000000000000000000ae90300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d18702015101b300000000",
|
||||
"DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY,DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["CheckTemplateVerify Argument from Witness Stack"],
|
||||
[[["e8e9805801b7fb44814531de0dd498b955651b9c25a85a043d73f18970622647",
|
||||
0,
|
||||
"0x00 0x20 0x65f15821061635e6807f06701bf0a12d8e89dcff88df5968bd0822c9dbb52f1c",
|
||||
155000]],
|
||||
"020000000001014726627089f1733d045aa8259c1b6555b998d40dde31458144fbb7015880e9e80000000000000000000ae90300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d18702204d5783a61241bdef19c3480e094cc933c91d2bde995c8c50407099184b501f4301b300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["CheckTemplateVerify Argument from Witness Stack"],
|
||||
[[["e8e9805801b7fb44814531de0dd498b955651b9c25a85a043d73f18970622647",
|
||||
0,
|
||||
"0x00 0x20 0x65f15821061635e6807f06701bf0a12d8e89dcff88df5968bd0822c9dbb52f1c",
|
||||
155000]],
|
||||
"020000000001014726627089f1733d045aa8259c1b6555b998d40dde31458144fbb7015880e9e80000000000000000000ae90300000000000017a91496e75de842d245fe846f1866f535d3d549af1eee87d00700000000000017a91443078220afb62f1dd0f13b58103c2cdea3ec31eb87b80b00000000000017a914c2aabf119c1825b1de66bc34e0792e37c198b5a987a00f00000000000017a9146e9e99a0b342e90e9360e26aa1a2b12ac7d1701e87881300000000000017a9149fc2952de5c6268759a4addd6f1336585de5a6b687701700000000000017a914f0bb53b2734e0f4027b25084630f4c7cb793f0d087581b00000000000017a914151a578ea0bbe3a24bf8335c4ee162643be28b4787401f00000000000017a9148f7ffde60fa425fa919ab9de3c7731fa4268151787282300000000000017a91454c45d77bccc359d07a2b17b4abfc78e8c3237b787102700000000000017a914e43197dbd28424b86c7c8823180e2b15192a96d18702204d5783a61241bdef19c3480e094cc933c91d2bde995c8c50407099184b501f4301b300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["BEGIN CTV congestion control tree level with 4 levels:"],
|
||||
["CTV congestion control tree level 0"],
|
||||
[[["d0246d069143263bca9a2b176fcf64bd8e4975c7670ed33659b4b8f88d3e7446",
|
||||
0,
|
||||
"0x20 0x10618b50aa1120e9e940bbea8b6d081019e38fbb9b956b0ab4f61631d05727ca OP_CHECKTEMPLATEVERIFY",
|
||||
16600]],
|
||||
"020000000146743e8df8b8b45936d30e67c775498ebd64cf6f172b9aca3b264391066d24d000000000000000000002781e0000000000002220bceb923d731eddf09705690d6ee697d1b3d57279ad96910cfb66a8d43a638800b3781e00000000000022201210e50077518896fd1661bffc2c1e88ad6e204ec4e8755407b42a97347c1e1bb300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["CTV congestion control tree level 1"],
|
||||
[[["b69f866d47ebb75eeecfbc3b9b641f926f11035b64ff27a5a5e88b9c065bddf5",
|
||||
0,
|
||||
"0x20 0xbceb923d731eddf09705690d6ee697d1b3d57279ad96910cfb66a8d43a638800 OP_CHECKTEMPLATEVERIFY",
|
||||
7800]],
|
||||
"0200000001f5dd5b069c8be8a5a527ff645b03116f921f649b3bbccfee5eb7eb476d869fb600000000000000000002480d00000000000022204c683607ca7950380df10647b223f656cd73d1f7ad67b30caf60d78337f913b2b3480d0000000000002220805bddd8b95a3cf3729b62703de37a1533b11634de76aa4a18605b640f1f3208b300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["CTV congestion control tree level 2"],
|
||||
[[["7d331a33880504fa94478c9687f3f41322ec76f81edad8e72491cbb81eea4754",
|
||||
0,
|
||||
"0x20 0x4c683607ca7950380df10647b223f656cd73d1f7ad67b30caf60d78337f913b2 OP_CHECKTEMPLATEVERIFY",
|
||||
3400]],
|
||||
"02000000015447ea1eb8cb9124e7d8da1ef876ec2213f4f387968c4794fa040588331a337d00000000000000000002b004000000000000222084ac6e0fdbe91b09d1bf68158643ad68e0b3e64373738fb35711de0835011079b3b0040000000000002220241af26179a8e861cca473244723978127c16531f71fbcc33563c4f099651f8fb300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["CTV congestion control tree level 3"],
|
||||
[[["e630b2357e02d1611a0615ce3964c408823ce3269974bd94e57ddea96900da70",
|
||||
0,
|
||||
"0x20 0x84ac6e0fdbe91b09d1bf68158643ad68e0b3e64373738fb35711de0835011079 OP_CHECKTEMPLATEVERIFY",
|
||||
1200]],
|
||||
"020000000170da0069a9de7de594bd749926e33c8208c46439ce15061a61d1027e35b230e60000000000000000000264000000000000001600141ca3bdf6bd2b1fc27420316a0d13f81fcdb85cb0640000000000000016001489d611c79700d6b4ae73d853ed49b86621d5802100000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["END"],
|
||||
|
||||
["BEGIN CTV congestion control tree level with 4 levels:"],
|
||||
["CTV congestion control tree level 0"],
|
||||
[[["d0246d069143263bca9a2b176fcf64bd8e4975c7670ed33659b4b8f88d3e7446",
|
||||
0,
|
||||
"0x20 0x10618b50aa1120e9e940bbea8b6d081019e38fbb9b956b0ab4f61631d05727ca OP_CHECKTEMPLATEVERIFY",
|
||||
16600]],
|
||||
"020000000146743e8df8b8b45936d30e67c775498ebd64cf6f172b9aca3b264391066d24d000000000000000000002781e0000000000002220bceb923d731eddf09705690d6ee697d1b3d57279ad96910cfb66a8d43a638800b3781e00000000000022201210e50077518896fd1661bffc2c1e88ad6e204ec4e8755407b42a97347c1e1bb300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["CTV congestion control tree level 1"],
|
||||
[[["b69f866d47ebb75eeecfbc3b9b641f926f11035b64ff27a5a5e88b9c065bddf5",
|
||||
0,
|
||||
"0x20 0xbceb923d731eddf09705690d6ee697d1b3d57279ad96910cfb66a8d43a638800 OP_CHECKTEMPLATEVERIFY",
|
||||
7800]],
|
||||
"0200000001f5dd5b069c8be8a5a527ff645b03116f921f649b3bbccfee5eb7eb476d869fb600000000000000000002480d00000000000022204c683607ca7950380df10647b223f656cd73d1f7ad67b30caf60d78337f913b2b3480d0000000000002220805bddd8b95a3cf3729b62703de37a1533b11634de76aa4a18605b640f1f3208b300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["CTV congestion control tree level 2"],
|
||||
[[["7d331a33880504fa94478c9687f3f41322ec76f81edad8e72491cbb81eea4754",
|
||||
0,
|
||||
"0x20 0x4c683607ca7950380df10647b223f656cd73d1f7ad67b30caf60d78337f913b2 OP_CHECKTEMPLATEVERIFY",
|
||||
3400]],
|
||||
"02000000015447ea1eb8cb9124e7d8da1ef876ec2213f4f387968c4794fa040588331a337d00000000000000000002b004000000000000222084ac6e0fdbe91b09d1bf68158643ad68e0b3e64373738fb35711de0835011079b3b0040000000000002220241af26179a8e861cca473244723978127c16531f71fbcc33563c4f099651f8fb300000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["CTV congestion control tree level 3"],
|
||||
[[["e630b2357e02d1611a0615ce3964c408823ce3269974bd94e57ddea96900da70",
|
||||
0,
|
||||
"0x20 0x84ac6e0fdbe91b09d1bf68158643ad68e0b3e64373738fb35711de0835011079 OP_CHECKTEMPLATEVERIFY",
|
||||
1200]],
|
||||
"020000000170da0069a9de7de594bd749926e33c8208c46439ce15061a61d1027e35b230e60000000000000000000264000000000000001600141ca3bdf6bd2b1fc27420316a0d13f81fcdb85cb0640000000000000016001489d611c79700d6b4ae73d853ed49b86621d5802100000000",
|
||||
"DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["END"],
|
||||
|
||||
["Test CTV with a specific scriptsig"],
|
||||
[[["32858fe9a6348d4ee5fcfce78f6dbca0b54dff169ff4cc41439adca4e5d30746",
|
||||
0,
|
||||
"1",
|
||||
155000],
|
||||
["357722dce671e5aa52abd617002baa8d5d970cef43feca3bf2d4c8b1e5d53d11",
|
||||
0,
|
||||
"0x20 0x08a5903863a0562c0b5608521a8a77ca02e669eb01f3981eede6bf6f2f38c2c2 OP_CHECKTEMPLATEVERIFY",
|
||||
155000]],
|
||||
"0200000002113dd5e5b1c8d4f23bcafe43ef0c975d8daa2b0017d6ab52aae571e6dc227735000000000151000000004607d3e5a4dc9a4341ccf49f16ff4db5a0bc6d8fe7fcfce54e8d34a6e98f8532000000000100000000000ae80300000000000017a9146422bb825e07ab99ab915223ac67f195a4fb761987d00700000000000017a914cc9fa001f8c9ff9dfdecf0ec1356d37c808aec2d87b80b00000000000017a914092f42f35fd05eaf816a090ad8f1adec8394132d87a00f00000000000017a9147cfd2a76093289ebabf860d3071b92756dbde1b787881300000000000017a914c3d81e1a59c256bff75c535878e1701943a9e48987701700000000000017a914029ddf1319c05ff38cd974ba99fdcf1cb4b88b9687581b00000000000017a9148c95279a9fd452ad7b1cb7a35fd08e7ff55946af87401f00000000000017a9149216fef0f965b2f1890a420aa725cb86ba47a9c087282300000000000017a9141424c24d8cd907a36310db639ec7d194c62d620087102700000000000017a9145b278b155e6dd103b4bf5ba78e4a95c16926c9bd8700000000",
|
||||
"CLEANSTACK,DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
[[["32858fe9a6348d4ee5fcfce78f6dbca0b54dff169ff4cc41439adca4e5d30746",
|
||||
0,
|
||||
"1",
|
||||
155000],
|
||||
["357722dce671e5aa52abd617002baa8d5d970cef43feca3bf2d4c8b1e5d53d11",
|
||||
0,
|
||||
"0x20 0x08a5903863a0562c0b5608521a8a77ca02e669eb01f3981eede6bf6f2f38c2c2 OP_CHECKTEMPLATEVERIFY",
|
||||
155000]],
|
||||
"0200000002113dd5e5b1c8d4f23bcafe43ef0c975d8daa2b0017d6ab52aae571e6dc227735000000000151000000004607d3e5a4dc9a4341ccf49f16ff4db5a0bc6d8fe7fcfce54e8d34a6e98f8532000000000100000000000ae80300000000000017a9146422bb825e07ab99ab915223ac67f195a4fb761987d00700000000000017a914cc9fa001f8c9ff9dfdecf0ec1356d37c808aec2d87b80b00000000000017a914092f42f35fd05eaf816a090ad8f1adec8394132d87a00f00000000000017a9147cfd2a76093289ebabf860d3071b92756dbde1b787881300000000000017a914c3d81e1a59c256bff75c535878e1701943a9e48987701700000000000017a914029ddf1319c05ff38cd974ba99fdcf1cb4b88b9687581b00000000000017a9148c95279a9fd452ad7b1cb7a35fd08e7ff55946af87401f00000000000017a9149216fef0f965b2f1890a420aa725cb86ba47a9c087282300000000000017a9141424c24d8cd907a36310db639ec7d194c62d620087102700000000000017a9145b278b155e6dd103b4bf5ba78e4a95c16926c9bd8700000000",
|
||||
"CLEANSTACK,DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
["Test CTV with a specific scriptsig at different index"],
|
||||
[[["e2f2baee9c59389b34e39742ce05debf64aaa7a00fbdab88614f4d3c133186d5",
|
||||
0,
|
||||
"1",
|
||||
155000],
|
||||
["c88e4b769a9211d2bca7516dbeacf250585dc825e41e34a65607a444b97fb782",
|
||||
0,
|
||||
"0x20 0xcc06acb181a8e9893c53c92fcfcb56fc004a360964af02cfd15b9f3321385f86 OP_CHECKTEMPLATEVERIFY",
|
||||
155000]],
|
||||
"0200000002d58631133c4d4f6188abbd0fa0a7aa64bfde05ce4297e3349b38599ceebaf2e20000000001510000000082b77fb944a40756a6341ee425c85d5850f2acbe6d51a7bcd211929a764b8ec8000000000100000000000ae80300000000000017a914d63e77972529f4db5b32efaa4e06f66ae0b5dc0987d00700000000000017a91488b6705f8c9568c52b55ed712c257f84f64a49f587b80b00000000000017a9142be57e9a179f8d9ff8f33a788d4b54512ea9e36087a00f00000000000017a91429261b4f65796f618908de9f51669014e2e2e04f87881300000000000017a914e3a1e1d24cbba3ca9369248082988bad3ceafcfb87701700000000000017a91403801b0a9591f3b5a00a5ea60fb34dc12b4a691187581b00000000000017a91465248bc2c732db2d88db0b0d677c1514b101025b87401f00000000000017a91420021e3dc4e80c7192c1a3cd04026d22d0f8d38287282300000000000017a914df27596dbff2028791bd7692846e65d16d8fed0d87102700000000000017a9142ed128e911cab04d3277d3635f79d5e3d7e6f4c48700000000",
|
||||
"CLEANSTACK,DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
[[["e2f2baee9c59389b34e39742ce05debf64aaa7a00fbdab88614f4d3c133186d5",
|
||||
0,
|
||||
"1",
|
||||
155000],
|
||||
["c88e4b769a9211d2bca7516dbeacf250585dc825e41e34a65607a444b97fb782",
|
||||
0,
|
||||
"0x20 0xcc06acb181a8e9893c53c92fcfcb56fc004a360964af02cfd15b9f3321385f86 OP_CHECKTEMPLATEVERIFY",
|
||||
155000]],
|
||||
"0200000002d58631133c4d4f6188abbd0fa0a7aa64bfde05ce4297e3349b38599ceebaf2e20000000001510000000082b77fb944a40756a6341ee425c85d5850f2acbe6d51a7bcd211929a764b8ec8000000000100000000000ae80300000000000017a914d63e77972529f4db5b32efaa4e06f66ae0b5dc0987d00700000000000017a91488b6705f8c9568c52b55ed712c257f84f64a49f587b80b00000000000017a9142be57e9a179f8d9ff8f33a788d4b54512ea9e36087a00f00000000000017a91429261b4f65796f618908de9f51669014e2e2e04f87881300000000000017a914e3a1e1d24cbba3ca9369248082988bad3ceafcfb87701700000000000017a91403801b0a9591f3b5a00a5ea60fb34dc12b4a691187581b00000000000017a91465248bc2c732db2d88db0b0d677c1514b101025b87401f00000000000017a91420021e3dc4e80c7192c1a3cd04026d22d0f8d38287282300000000000017a914df27596dbff2028791bd7692846e65d16d8fed0d87102700000000000017a9142ed128e911cab04d3277d3635f79d5e3d7e6f4c48700000000",
|
||||
"CLEANSTACK,DISCOURAGE_CHECKTEMPLATEVERIFY"],
|
||||
|
||||
["Make diffs cleaner by leaving a comment here without comma at the end"]
|
||||
]
|
||||
|
@ -76,6 +76,7 @@ FUZZ_TARGET(script, .init = initialize_script)
|
||||
assert(which_type == TxoutType::PUBKEY ||
|
||||
which_type == TxoutType::NONSTANDARD ||
|
||||
which_type == TxoutType::NULL_DATA ||
|
||||
which_type == TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY ||
|
||||
which_type == TxoutType::MULTISIG);
|
||||
}
|
||||
if (which_type == TxoutType::NONSTANDARD ||
|
||||
|
@ -70,6 +70,9 @@ static std::map<std::string, unsigned int> mapFlagNames = {
|
||||
{std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE},
|
||||
{std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS},
|
||||
{std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION},
|
||||
{std::string("DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECKTEMPLATEVERIFY},
|
||||
{std::string("DISCOURAGE_CHECKTEMPLATEVERIFY"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_CHECKTEMPLATEVERIFY},
|
||||
{std::string("CHECKTEMPLATEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKTEMPLATEVERIFY},
|
||||
};
|
||||
|
||||
unsigned int ParseScriptFlags(std::string strFlags)
|
||||
|
@ -912,6 +912,8 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
|
||||
case TxoutType::WITNESS_V1_TAPROOT:
|
||||
case TxoutType::ANCHOR:
|
||||
return "unrecognized script";
|
||||
case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY:
|
||||
return "bare default CheckTemplateVerify hash";
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
NONFATAL_UNREACHABLE();
|
||||
}
|
||||
|
@ -208,6 +208,11 @@ IsMineResult IsMineInner(const LegacyDataSPKM& keystore, const CScript& scriptPu
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TxoutType::TX_BARE_DEFAULT_CHECKTEMPLATEVERIFY:
|
||||
{
|
||||
ret = IsMineResult::NO;
|
||||
break;
|
||||
}
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
|
||||
if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
|
||||
|
445
test/functional/feature_checktemplateverify.py
Executable file
445
test/functional/feature_checktemplateverify.py
Executable file
@ -0,0 +1,445 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2015-2021 The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""Test (CheckTemplateVerify)
|
||||
"""
|
||||
|
||||
from test_framework.blocktools import (
|
||||
create_coinbase,
|
||||
create_block,
|
||||
add_witness_commitment,
|
||||
)
|
||||
from test_framework.messages import (
|
||||
CTransaction,
|
||||
CTxOut,
|
||||
CTxIn,
|
||||
CTxInWitness,
|
||||
COutPoint,
|
||||
COIN,
|
||||
sha256,
|
||||
)
|
||||
from test_framework.p2p import P2PInterface
|
||||
from test_framework.script import (
|
||||
CScript,
|
||||
OP_TRUE,
|
||||
OP_DEPTH,
|
||||
OP_ENDIF,
|
||||
OP_IF,
|
||||
OP_CHECKTEMPLATEVERIFY,
|
||||
OP_FALSE,
|
||||
OP_DROP,
|
||||
taproot_construct,
|
||||
)
|
||||
from test_framework.script_util import script_to_p2sh_script
|
||||
from test_framework.key import ECKey, compute_xonly_pubkey
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal, assert_raises_rpc_error
|
||||
from test_framework.wallet import MiniWallet, MiniWalletMode
|
||||
from decimal import Decimal
|
||||
import random
|
||||
from io import BytesIO
|
||||
from test_framework.address import script_to_p2sh
|
||||
|
||||
CHECKTEMPLATEVERIFY_ERROR = "non-mandatory-script-verify-flag (Script failed an OP_CHECKTEMPLATEVERIFY operation)"
|
||||
DISCOURAGED_ERROR = (
|
||||
"non-mandatory-script-verify-flag (NOPx reserved for soft-fork upgrades)"
|
||||
)
|
||||
STACK_TOO_SHORT_ERROR = (
|
||||
"non-mandatory-script-verify-flag (Operation not valid with the current stack size)"
|
||||
)
|
||||
|
||||
|
||||
def random_bytes(n):
|
||||
return bytes(random.getrandbits(8) for i in range(n))
|
||||
|
||||
|
||||
def template_hash_for_outputs(outputs, nIn=0, nVin=1, vin_override=None):
|
||||
c = CTransaction()
|
||||
c.version = 2
|
||||
c.vin = vin_override
|
||||
if vin_override is None:
|
||||
c.vin = [CTxIn()] * nVin
|
||||
c.vout = outputs
|
||||
return c.get_standard_template_hash(nIn)
|
||||
|
||||
|
||||
def random_p2sh():
|
||||
return script_to_p2sh_script(random_bytes(20))
|
||||
|
||||
|
||||
def random_real_outputs_and_script(n, nIn=0, nVin=1, vin_override=None):
|
||||
outputs = [CTxOut((x + 1) * 1000, random_p2sh()) for x in range(n)]
|
||||
script = CScript(
|
||||
[
|
||||
template_hash_for_outputs(outputs, nIn, nVin, vin_override),
|
||||
OP_CHECKTEMPLATEVERIFY,
|
||||
]
|
||||
)
|
||||
return outputs, script
|
||||
|
||||
|
||||
def random_secure_tree(depth):
|
||||
leaf_nodes = [
|
||||
CTxOut(nValue=100, scriptPubKey=CScript(bytes([0, 0x14]) + random_bytes(20)))
|
||||
for x in range(2 ** depth)
|
||||
]
|
||||
outputs_tree = [[CTxOut()] * (2 ** i) for i in range(depth)] + [leaf_nodes]
|
||||
for d in range(1, depth + 2):
|
||||
idxs = zip(
|
||||
range(0, len(outputs_tree[-d]), 2), range(1, len(outputs_tree[-d]), 2)
|
||||
)
|
||||
for (idx, (a, b)) in enumerate(
|
||||
[(outputs_tree[-d][i], outputs_tree[-d][j]) for (i, j) in idxs]
|
||||
):
|
||||
s = CScript(
|
||||
bytes([0x20])
|
||||
+ template_hash_for_outputs([a, b])
|
||||
+ bytes([OP_CHECKTEMPLATEVERIFY])
|
||||
)
|
||||
a = sum(o.nValue for o in [a, b])
|
||||
t = CTxOut(a + 1000, s)
|
||||
outputs_tree[-d - 1][idx] = t
|
||||
return outputs_tree
|
||||
|
||||
|
||||
def create_transaction_to_script(node, wallet, txid, script, *, amount_sats):
|
||||
"""Return signed transaction spending the first output of the
|
||||
input txid. Note that the node must be able to sign for the
|
||||
output that is being spent, and the node must not be running
|
||||
multiple wallets.
|
||||
"""
|
||||
random_address = script_to_p2sh(CScript())
|
||||
output = wallet.get_utxo(txid=txid)
|
||||
rawtx = node.createrawtransaction(
|
||||
inputs=[{"txid": output["txid"], "vout": output["vout"]}],
|
||||
outputs={random_address: Decimal(amount_sats) / COIN},
|
||||
)
|
||||
tx = CTransaction()
|
||||
tx.deserialize(BytesIO(bytes.fromhex(rawtx)))
|
||||
# Replace with our script
|
||||
tx.vout[0].scriptPubKey = script
|
||||
# Sign
|
||||
wallet.sign_tx(tx)
|
||||
return tx
|
||||
|
||||
|
||||
class CheckTemplateVerifyTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
self.extra_args = [
|
||||
["-par=1"]
|
||||
] # Use only one script thread to get the exact reject reason for testing
|
||||
self.setup_clean_chain = True
|
||||
self.rpc_timeout = 120
|
||||
|
||||
def get_block(self, txs):
|
||||
self.tip = self.nodes[0].getbestblockhash()
|
||||
self.height = self.nodes[0].getblockcount()
|
||||
self.log.debug(self.height)
|
||||
block = create_block(int(self.tip, 16), create_coinbase(self.height + 1))
|
||||
block.vtx.extend(txs)
|
||||
add_witness_commitment(block)
|
||||
block.hashMerkleRoot = block.calc_merkle_root()
|
||||
block.solve()
|
||||
return block.serialize(True).hex(), block.hash
|
||||
|
||||
def add_block(self, txs):
|
||||
block, h = self.get_block(txs)
|
||||
reason = self.nodes[0].submitblock(block)
|
||||
if reason:
|
||||
self.log.debug("Reject Reason: [%s]", reason)
|
||||
assert_equal(self.nodes[0].getbestblockhash(), h)
|
||||
return h
|
||||
|
||||
def fail_block(self, txs, cause=CHECKTEMPLATEVERIFY_ERROR):
|
||||
block, h = self.get_block(txs)
|
||||
assert_equal(self.nodes[0].submitblock(block), cause)
|
||||
assert_equal(self.nodes[0].getbestblockhash(), self.tip)
|
||||
|
||||
def run_test(self):
|
||||
|
||||
# The goal is to test a number of circumstances and combinations of parameters. Roughly:
|
||||
#
|
||||
# - Taproot OP_CTV
|
||||
# - SegWit OP_CTV
|
||||
# - SegWit OP_CTV wrong size on stack
|
||||
# - fails policy
|
||||
# - passes consensus
|
||||
# - SegWit OP_CTV no argument in stack from program
|
||||
# - fails policy and consensus with empty stack
|
||||
# - passes consensus and policy when argument is the correct hash
|
||||
# - passes consensus when argument is non 32 bytes
|
||||
# - fails policy when argument is non 32 bytes
|
||||
# - P2SH OP_CTV (impossible to spend w/o hash cycle!)
|
||||
# - Bare OP_CTV
|
||||
# - OP_CTV at vin index 0
|
||||
# - OP_CTV at vin index > 0
|
||||
# - OP_CTV with scriptSigs set
|
||||
# - OP_CTV without scriptSigs set
|
||||
# - OP_CTV with multiple inputs
|
||||
# - accepting correct parameters
|
||||
# - rejecting incorrect parameters
|
||||
# - OP_CTV in a tree
|
||||
#
|
||||
# A few tests may seem redundant, but it is because they are testing the cached computation of the hash
|
||||
# at vin index 0
|
||||
wallet = MiniWallet(self.nodes[0], mode=MiniWalletMode.RAW_P2PK)
|
||||
self.nodes[0].add_p2p_connection(P2PInterface())
|
||||
|
||||
BLOCKS = 115
|
||||
self.log.info("Mining %d blocks for mature coinbases", BLOCKS)
|
||||
# Drop the last 100 as they're unspendable!
|
||||
coinbase_txids = [
|
||||
self.nodes[0].getblock(b)["tx"][0]
|
||||
for b in self.generate(wallet, BLOCKS)[:-100]
|
||||
]
|
||||
get_coinbase = lambda: coinbase_txids.pop()
|
||||
|
||||
self.log.info("Creating setup transactions")
|
||||
|
||||
self.log.info("Creating script for 10 random outputs")
|
||||
outputs, script = random_real_outputs_and_script(10)
|
||||
# Add some fee satoshis
|
||||
amount_sats = sum(out.nValue for out in outputs) + 200 * 500
|
||||
|
||||
self.log.info("Creating funding txn for 10 random outputs as a Taproot script")
|
||||
private_key = ECKey()
|
||||
# use simple deterministic private key (k=1)
|
||||
private_key.set((1).to_bytes(32, "big"), False)
|
||||
assert private_key.is_valid
|
||||
public_key, _ = compute_xonly_pubkey(private_key.get_bytes())
|
||||
taproot = taproot_construct(public_key, [("only-path", script, 0xC0)])
|
||||
taproot_ctv_funding_tx = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
taproot.scriptPubKey,
|
||||
amount_sats=amount_sats,
|
||||
)
|
||||
|
||||
self.log.info("Creating funding txn for 10 random outputs as a segwit script")
|
||||
segwit_ctv_funding_tx = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
CScript([0, sha256(script)]),
|
||||
amount_sats=amount_sats,
|
||||
)
|
||||
|
||||
self.log.info("Creating a CTV with a non 32 byte stack segwit script")
|
||||
segwit_ctv_funding_tx_wrongsize_stack = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
CScript([0, sha256(CScript([OP_TRUE, OP_CHECKTEMPLATEVERIFY]))]),
|
||||
amount_sats=amount_sats,
|
||||
)
|
||||
|
||||
self.log.info("Creating a CTV with an empty stack segwit script")
|
||||
# allows either calling with empty witness stack or with a 32 byte hash (cleanstack rule)
|
||||
empty_stack_script = CScript(
|
||||
[OP_CHECKTEMPLATEVERIFY, OP_DEPTH, OP_IF, OP_DROP, OP_ENDIF, OP_TRUE]
|
||||
)
|
||||
segwit_ctv_funding_tx_empty_stack = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
CScript([0, sha256(empty_stack_script)]),
|
||||
amount_sats=amount_sats,
|
||||
)
|
||||
|
||||
self.log.info(
|
||||
"Creating funding txn for 10 random outputs as a p2sh script (impossible to spend)"
|
||||
)
|
||||
p2sh_ctv_funding_tx = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
script_to_p2sh_script(script),
|
||||
amount_sats=amount_sats,
|
||||
)
|
||||
|
||||
# Small tree size 4 for test speed.
|
||||
# Can be set to a large value like 16 (i.e., 65K txns).
|
||||
TREE_SIZE = 4
|
||||
self.log.info(f"Creating script for tree size depth {TREE_SIZE}")
|
||||
congestion_tree_txo = random_secure_tree(TREE_SIZE)
|
||||
|
||||
self.log.info(f"Creating funding txn for tree size depth {TREE_SIZE}")
|
||||
bare_ctv_tree_funding_tx = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
congestion_tree_txo[0][0].scriptPubKey,
|
||||
amount_sats=congestion_tree_txo[0][0].nValue,
|
||||
)
|
||||
|
||||
self.log.info("Creating script for spend at position 2")
|
||||
outputs_position_2, script_position_2 = random_real_outputs_and_script(10, 1, 2)
|
||||
# Add some fee satoshis
|
||||
amount_position_2 = sum(out.nValue for out in outputs_position_2) + 200 * 500
|
||||
|
||||
self.log.info("Creating funding txn for spend at position 2")
|
||||
bare_ctv_position_2_funding_tx = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
script_position_2,
|
||||
amount_sats=amount_position_2,
|
||||
)
|
||||
|
||||
self.log.info(
|
||||
"Creating script for spend at position 1 with 2 non-null scriptsigs"
|
||||
)
|
||||
(
|
||||
outputs_specific_scriptSigs,
|
||||
script_specific_scriptSigs,
|
||||
) = random_real_outputs_and_script(
|
||||
10,
|
||||
0,
|
||||
2,
|
||||
[CTxIn(scriptSig=CScript([OP_TRUE])), CTxIn(scriptSig=CScript([OP_FALSE]))],
|
||||
)
|
||||
# Add some fee satoshis
|
||||
amount_specific_scriptSigs = (
|
||||
sum(out.nValue for out in outputs_specific_scriptSigs) + 200 * 500
|
||||
)
|
||||
|
||||
self.log.info(
|
||||
"Creating funding txn for spend at position 1 with 2 non-null scriptsigs"
|
||||
)
|
||||
bare_ctv_specific_scriptSigs_funding_tx = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
script_specific_scriptSigs,
|
||||
amount_sats=amount_specific_scriptSigs,
|
||||
)
|
||||
|
||||
self.log.info(
|
||||
"Creating script for spend at position 2 with 2 non-null scriptsigs"
|
||||
)
|
||||
(
|
||||
outputs_specific_scriptSigs_position_2,
|
||||
script_specific_scriptSigs_position_2,
|
||||
) = random_real_outputs_and_script(
|
||||
10,
|
||||
1,
|
||||
2,
|
||||
[CTxIn(scriptSig=CScript([OP_TRUE])), CTxIn(scriptSig=CScript([OP_FALSE]))],
|
||||
)
|
||||
# Add some fee satoshis
|
||||
amount_specific_scriptSigs_position_2 = (
|
||||
sum(out.nValue for out in outputs_specific_scriptSigs_position_2)
|
||||
+ 200 * 500
|
||||
)
|
||||
|
||||
self.log.info(
|
||||
"Creating funding txn for spend at position 2 with 2 non-null scriptsigs"
|
||||
)
|
||||
bare_ctv_specific_scriptSigs_position_2_funding_tx = (
|
||||
create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
script_specific_scriptSigs_position_2,
|
||||
amount_sats=amount_specific_scriptSigs_position_2,
|
||||
)
|
||||
)
|
||||
|
||||
self.log.info("Creating funding txns for some anyone can spend outputs")
|
||||
anyone_can_spend_funding_tx = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
CScript([OP_TRUE]),
|
||||
amount_sats=amount_sats,
|
||||
)
|
||||
bare_anyone_can_spend_funding_tx = create_transaction_to_script(
|
||||
self.nodes[0],
|
||||
wallet,
|
||||
get_coinbase(),
|
||||
CScript([OP_TRUE]),
|
||||
amount_sats=amount_sats,
|
||||
)
|
||||
|
||||
funding_txs = [
|
||||
taproot_ctv_funding_tx,
|
||||
segwit_ctv_funding_tx,
|
||||
segwit_ctv_funding_tx_wrongsize_stack,
|
||||
segwit_ctv_funding_tx_empty_stack,
|
||||
p2sh_ctv_funding_tx,
|
||||
anyone_can_spend_funding_tx,
|
||||
bare_ctv_tree_funding_tx,
|
||||
bare_ctv_position_2_funding_tx,
|
||||
bare_anyone_can_spend_funding_tx,
|
||||
bare_ctv_specific_scriptSigs_funding_tx,
|
||||
bare_ctv_specific_scriptSigs_position_2_funding_tx,
|
||||
]
|
||||
|
||||
self.log.info("Obtaining TXIDs")
|
||||
(
|
||||
taproot_ctv_outpoint,
|
||||
segwit_ctv_outpoint,
|
||||
segwit_ctv_wrongsize_stack_outpoint,
|
||||
segwit_ctv_empty_stack_outpoint,
|
||||
p2sh_ctv_outpoint,
|
||||
anyone_can_spend_outpoint,
|
||||
bare_ctv_tree_outpoint,
|
||||
bare_ctv_position_2_outpoint,
|
||||
bare_anyone_can_spend_outpoint,
|
||||
bare_ctv_specific_scriptSigs_outpoint,
|
||||
bare_ctv_specific_scriptSigs_position_2_outpoint,
|
||||
) = [COutPoint(int(tx.rehash(), 16), 0) for tx in funding_txs]
|
||||
|
||||
self.log.info("Funding all outputs")
|
||||
self.add_block(funding_txs)
|
||||
|
||||
self.log.info("Testing Taproot OP_CHECKTEMPLATEVERIFY spend")
|
||||
# Test sendrawtransaction
|
||||
taproot_check_template_verify_tx = CTransaction()
|
||||
taproot_check_template_verify_tx.version = 2
|
||||
taproot_check_template_verify_tx.vin = [CTxIn(taproot_ctv_outpoint)]
|
||||
taproot_check_template_verify_tx.vout = outputs
|
||||
taproot_check_template_verify_tx.wit.vtxinwit += [CTxInWitness()]
|
||||
taproot_check_template_verify_tx.wit.vtxinwit[0].scriptWitness.stack = [
|
||||
script,
|
||||
bytes([0xC0 + taproot.negflag]) + taproot.internal_pubkey,
|
||||
]
|
||||
assert_raises_rpc_error(
|
||||
-26,
|
||||
DISCOURAGED_ERROR,
|
||||
self.nodes[0].sendrawtransaction,
|
||||
taproot_check_template_verify_tx.serialize().hex(),
|
||||
)
|
||||
self.log.info(
|
||||
"Taproot OP_CHECKTEMPLATEVERIFY spend discouraged by sendrawtransaction"
|
||||
)
|
||||
|
||||
self.log.info("Testing Segwit OP_CHECKTEMPLATEVERIFY spend")
|
||||
# Test sendrawtransaction
|
||||
check_template_verify_tx = CTransaction()
|
||||
check_template_verify_tx.version = 2
|
||||
check_template_verify_tx.vin = [CTxIn(segwit_ctv_outpoint)]
|
||||
check_template_verify_tx.vout = outputs
|
||||
|
||||
check_template_verify_tx.wit.vtxinwit += [CTxInWitness()]
|
||||
check_template_verify_tx.wit.vtxinwit[0].scriptWitness.stack = [script]
|
||||
assert_raises_rpc_error(
|
||||
-26,
|
||||
DISCOURAGED_ERROR,
|
||||
self.nodes[0].sendrawtransaction,
|
||||
check_template_verify_tx.serialize().hex(),
|
||||
)
|
||||
self.log.info(
|
||||
"Segwit OP_CHECKTEMPLATEVERIFY spend discouraged by sendrawtransaction"
|
||||
)
|
||||
|
||||
# TODO: In Jeremy's original patches, there were many additional tests. We
|
||||
# should add these back once a proper deployment is specified for
|
||||
# CHECKTEMPLATEVERIFY, and can be mocked with `-testactivationheight=`.
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
CheckTemplateVerifyTest(__file__).main()
|
@ -88,7 +88,7 @@ class InitTest(BitcoinTestFramework):
|
||||
|
||||
args = ['-txindex=1', '-blockfilterindex=1', '-coinstatsindex=1']
|
||||
for terminate_line in lines_to_terminate_after:
|
||||
self.log.info(f"Starting node and will exit after line {terminate_line}")
|
||||
self.log.info(f"Starting node and will terminate after line {terminate_line}")
|
||||
with node.busy_wait_for_debug_log([terminate_line]):
|
||||
if platform.system() == 'Windows':
|
||||
# CREATE_NEW_PROCESS_GROUP is required in order to be able
|
||||
@ -108,12 +108,22 @@ class InitTest(BitcoinTestFramework):
|
||||
'blocks/index/*.ldb': 'Error opening block database.',
|
||||
'chainstate/*.ldb': 'Error opening coins database.',
|
||||
'blocks/blk*.dat': 'Error loading block database.',
|
||||
'indexes/txindex/MANIFEST*': 'LevelDB error: Corruption: CURRENT points to a non-existent file',
|
||||
# Removing these files does not result in a startup error:
|
||||
# 'indexes/blockfilter/basic/*.dat', 'indexes/blockfilter/basic/db/*.*', 'indexes/coinstats/db/*.*',
|
||||
# 'indexes/txindex/*.log', 'indexes/txindex/CURRENT', 'indexes/txindex/LOCK'
|
||||
}
|
||||
|
||||
files_to_perturb = {
|
||||
'blocks/index/*.ldb': 'Error loading block database.',
|
||||
'chainstate/*.ldb': 'Error opening coins database.',
|
||||
'blocks/blk*.dat': 'Corrupted block database detected.',
|
||||
'indexes/blockfilter/basic/db/*.*': 'LevelDB error: Corruption',
|
||||
'indexes/coinstats/db/*.*': 'LevelDB error: Corruption',
|
||||
'indexes/txindex/*.log': 'LevelDB error: Corruption',
|
||||
'indexes/txindex/CURRENT': 'LevelDB error: Corruption',
|
||||
# Perturbing these files does not result in a startup error:
|
||||
# 'indexes/blockfilter/basic/*.dat', 'indexes/txindex/MANIFEST*', 'indexes/txindex/LOCK'
|
||||
}
|
||||
|
||||
for file_patt, err_fragment in files_to_delete.items():
|
||||
@ -135,9 +145,10 @@ class InitTest(BitcoinTestFramework):
|
||||
self.stop_node(0)
|
||||
|
||||
self.log.info("Test startup errors after perturbing certain essential files")
|
||||
dirs = ["blocks", "chainstate", "indexes"]
|
||||
for file_patt, err_fragment in files_to_perturb.items():
|
||||
shutil.copytree(node.chain_path / "blocks", node.chain_path / "blocks_bak")
|
||||
shutil.copytree(node.chain_path / "chainstate", node.chain_path / "chainstate_bak")
|
||||
for dir in dirs:
|
||||
shutil.copytree(node.chain_path / dir, node.chain_path / f"{dir}_bak")
|
||||
target_files = list(node.chain_path.glob(file_patt))
|
||||
|
||||
for target_file in target_files:
|
||||
@ -151,10 +162,9 @@ class InitTest(BitcoinTestFramework):
|
||||
|
||||
start_expecting_error(err_fragment)
|
||||
|
||||
shutil.rmtree(node.chain_path / "blocks")
|
||||
shutil.rmtree(node.chain_path / "chainstate")
|
||||
shutil.move(node.chain_path / "blocks_bak", node.chain_path / "blocks")
|
||||
shutil.move(node.chain_path / "chainstate_bak", node.chain_path / "chainstate")
|
||||
for dir in dirs:
|
||||
shutil.rmtree(node.chain_path / dir)
|
||||
shutil.move(node.chain_path / f"{dir}_bak", node.chain_path / dir)
|
||||
|
||||
def init_pid_test(self):
|
||||
BITCOIN_PID_FILENAME_CUSTOM = "my_fancy_bitcoin_pid_file.foobar"
|
||||
|
@ -45,6 +45,7 @@ from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_greater_than,
|
||||
assert_raises_rpc_error,
|
||||
sync_txindex,
|
||||
)
|
||||
from test_framework.wallet import MiniWallet
|
||||
from test_framework.wallet_util import generate_keypair
|
||||
@ -270,6 +271,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
|
||||
|
||||
self.log.info('A coinbase transaction')
|
||||
# Pick the input of the first tx we created, so it has to be a coinbase tx
|
||||
sync_txindex(self, node)
|
||||
raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
|
||||
tx = tx_from_hex(raw_tx_coinbase_spent)
|
||||
self.check_mempool_result(
|
||||
|
@ -34,6 +34,7 @@ from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_greater_than,
|
||||
assert_raises_rpc_error,
|
||||
sync_txindex,
|
||||
)
|
||||
from test_framework.wallet import (
|
||||
getnewdestination,
|
||||
@ -70,7 +71,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
self.num_nodes = 3
|
||||
self.extra_args = [
|
||||
["-txindex"],
|
||||
["-txindex"],
|
||||
[],
|
||||
["-fastprune", "-prune=1"],
|
||||
]
|
||||
# whitelist peers to speed up tx relay / mempool sync
|
||||
@ -109,6 +110,7 @@ class RawTransactionsTest(BitcoinTestFramework):
|
||||
self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex")
|
||||
|
||||
if n == 0:
|
||||
sync_txindex(self, self.nodes[n])
|
||||
# With -txindex.
|
||||
# 1. valid parameters - only supply txid
|
||||
assert_equal(self.nodes[n].getrawtransaction(txId), tx['hex'])
|
||||
|
@ -12,6 +12,7 @@ from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_raises_rpc_error,
|
||||
sync_txindex,
|
||||
)
|
||||
from test_framework.wallet import MiniWallet
|
||||
|
||||
@ -77,6 +78,7 @@ class MerkleBlockTest(BitcoinTestFramework):
|
||||
assert_equal(sorted(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid1, txid2]))), sorted(txlist))
|
||||
assert_equal(sorted(self.nodes[0].verifytxoutproof(self.nodes[0].gettxoutproof([txid2, txid1]))), sorted(txlist))
|
||||
# We can always get a proof if we have a -txindex
|
||||
sync_txindex(self, self.nodes[1])
|
||||
assert_equal(self.nodes[0].verifytxoutproof(self.nodes[1].gettxoutproof([txid_spent])), [txid_spent])
|
||||
# We can't get a proof if we specify transactions from different blocks
|
||||
assert_raises_rpc_error(-5, "Not all transactions found in specified or retrieved block", self.nodes[0].gettxoutproof, [txid1, txid3])
|
||||
|
@ -25,6 +25,7 @@ from io import BytesIO
|
||||
import math
|
||||
import random
|
||||
import socket
|
||||
import struct
|
||||
import time
|
||||
import unittest
|
||||
|
||||
@ -633,6 +634,19 @@ class CTransaction:
|
||||
r += self.nLockTime.to_bytes(4, "little")
|
||||
return r
|
||||
|
||||
def get_standard_template_hash(self, nIn):
|
||||
r = b""
|
||||
r += self.version.to_bytes(4, "little")
|
||||
r += self.nLockTime.to_bytes(4, "little")
|
||||
if any(inp.scriptSig for inp in self.vin):
|
||||
r += sha256(b"".join(ser_string(inp.scriptSig) for inp in self.vin))
|
||||
r += struct.pack("<I", len(self.vin))
|
||||
r += sha256(b"".join(struct.pack("<I", inp.nSequence) for inp in self.vin))
|
||||
r += struct.pack("<I", len(self.vout))
|
||||
r += sha256(b"".join(out.serialize() for out in self.vout))
|
||||
r += struct.pack("<I", nIn)
|
||||
return sha256(r)
|
||||
|
||||
# Only serialize with witness when explicitly called for
|
||||
def serialize_with_witness(self):
|
||||
flags = 0
|
||||
|
@ -240,7 +240,7 @@ OP_CHECKMULTISIGVERIFY = CScriptOp(0xaf)
|
||||
OP_NOP1 = CScriptOp(0xb0)
|
||||
OP_CHECKLOCKTIMEVERIFY = CScriptOp(0xb1)
|
||||
OP_CHECKSEQUENCEVERIFY = CScriptOp(0xb2)
|
||||
OP_NOP4 = CScriptOp(0xb3)
|
||||
OP_CHECKTEMPLATEVERIFY = CScriptOp(0xb3)
|
||||
OP_NOP5 = CScriptOp(0xb4)
|
||||
OP_NOP6 = CScriptOp(0xb5)
|
||||
OP_NOP7 = CScriptOp(0xb6)
|
||||
@ -358,7 +358,7 @@ OPCODE_NAMES.update({
|
||||
OP_NOP1: 'OP_NOP1',
|
||||
OP_CHECKLOCKTIMEVERIFY: 'OP_CHECKLOCKTIMEVERIFY',
|
||||
OP_CHECKSEQUENCEVERIFY: 'OP_CHECKSEQUENCEVERIFY',
|
||||
OP_NOP4: 'OP_NOP4',
|
||||
OP_CHECKTEMPLATEVERIFY : 'OP_CHECKTEMPLATEVERIFY',
|
||||
OP_NOP5: 'OP_NOP5',
|
||||
OP_NOP6: 'OP_NOP6',
|
||||
OP_NOP7: 'OP_NOP7',
|
||||
|
@ -592,3 +592,10 @@ def find_vout_for_address(node, txid, addr):
|
||||
if addr == tx["vout"][i]["scriptPubKey"]["address"]:
|
||||
return i
|
||||
raise RuntimeError("Vout not found for address: txid=%s, addr=%s" % (txid, addr))
|
||||
|
||||
|
||||
def sync_txindex(test_framework, node):
|
||||
test_framework.log.debug("Waiting for node txindex to sync")
|
||||
sync_start = int(time.time())
|
||||
test_framework.wait_until(lambda: node.getindexinfo("txindex")["txindex"]["synced"])
|
||||
test_framework.log.debug(f"Synced in {time.time() - sync_start} seconds")
|
||||
|
@ -311,6 +311,7 @@ BASE_SCRIPTS = [
|
||||
'wallet_balance.py --descriptors',
|
||||
'p2p_initial_headers_sync.py',
|
||||
'feature_nulldummy.py',
|
||||
'feature_checktemplateverify.py',
|
||||
'mempool_accept.py',
|
||||
'mempool_expiry.py',
|
||||
'wallet_import_with_label.py --legacy-wallet',
|
||||
|
@ -117,7 +117,6 @@ class AddressInputTypeGrouping(BitcoinTestFramework):
|
||||
self.extra_args = [
|
||||
[
|
||||
"-addresstype=bech32",
|
||||
"-txindex",
|
||||
],
|
||||
[
|
||||
"-addresstype=p2sh-segwit",
|
||||
|
Loading…
x
Reference in New Issue
Block a user