diff --git a/src/consensus/params.h b/src/consensus/params.h index 7f56729455a8..6514e3ebee3d 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -36,6 +36,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_ enum DeploymentPos : uint16_t { DEPLOYMENT_TESTDUMMY, + DEPLOYMENT_TEMPLATEHASH, // NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp // Removing an entry may require bumping MinBIP9WarningHeight. MAX_VERSION_BITS_DEPLOYMENTS diff --git a/src/deploymentinfo.cpp b/src/deploymentinfo.cpp index 551982b23ae7..f4ff3d1122f0 100644 --- a/src/deploymentinfo.cpp +++ b/src/deploymentinfo.cpp @@ -13,6 +13,10 @@ const std::array Versi .name = "testdummy", .gbt_optional_rule = true, }, + VBDeploymentInfo{ + .name = "templatehash", + .gbt_optional_rule = true, + } }; std::string DeploymentName(Consensus::BuriedDeployment dep) diff --git a/src/kernel/chainparams.cpp b/src/kernel/chainparams.cpp index cc77a373481b..06650ef1c6bd 100644 --- a/src/kernel/chainparams.cpp +++ b/src/kernel/chainparams.cpp @@ -136,6 +136,12 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].threshold = 1815; // 90% consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].period = 2016; + // Deployment of OP_TEMPLATEHASH + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].min_activation_height = 0; + ApplyDeploymentOptions(opts.dep_opts); consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000001128750f82f4c366153a3a030"}; @@ -261,6 +267,12 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].threshold = 1512; // 75% consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].period = 2016; + // Deployment of OP_TEMPLATEHASH + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].min_activation_height = 0; + ApplyDeploymentOptions(opts.dep_opts); consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000017dde1c649f3708d14b6"}; @@ -363,6 +375,12 @@ class CTestNet4Params : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].threshold = 1512; // 75% consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].period = 2016; + // Deployment of OP_TEMPLATEHASH + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].min_activation_height = 0; + ApplyDeploymentOptions(opts.dep_opts); consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000009a0fe15d0177d086304"}; @@ -508,6 +526,12 @@ class SigNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].threshold = 1815; // 90% consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].period = 2016; + // Deployment of OP_TEMPLATEHASH + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].min_activation_height = 0; + ApplyDeploymentOptions(options.dep_opts); // message start is defined as the first 4 bytes of the sha256d of the block script @@ -592,6 +616,14 @@ class CRegTestParams : public CChainParams consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].threshold = 108; // 75% consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].period = 144; // Faster than normal for regtest (144 instead of 2016) + // Deployment of OP_TEMPLATEHASH + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].bit = 3; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].min_activation_height = 0; // No activation delay + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].threshold = 108; // 75% + consensus.vDeployments[Consensus::DEPLOYMENT_TEMPLATEHASH].period = 144; + consensus.nMinimumChainWork = uint256{}; consensus.defaultAssumeValid = uint256{}; diff --git a/src/policy/policy.h b/src/policy/policy.h index 13bcf4cef750..05d01da4995a 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -107,7 +107,8 @@ static constexpr script_verify_flags MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY | SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_VERIFY_WITNESS | - SCRIPT_VERIFY_TAPROOT}; + SCRIPT_VERIFY_TAPROOT | + SCRIPT_VERIFY_TEMPLATEHASH}; /** * Standard script verification flags that standard transactions will comply @@ -128,7 +129,8 @@ static constexpr script_verify_flags STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRI 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_TEMPLATEHASH}; /** For convenience, standard but not mandatory verify flags. */ static constexpr script_verify_flags STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS}; diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 264f861bc7a4..7f6775bb8ab0 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -233,12 +233,12 @@ bool XOnlyPubKey::IsFullyValid() const return secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data()); } -bool XOnlyPubKey::VerifySchnorr(const uint256& msg, std::span sigbytes) const +bool XOnlyPubKey::VerifySchnorr(std::span msg, std::span sigbytes) const { assert(sigbytes.size() == 64); secp256k1_xonly_pubkey pubkey; if (!secp256k1_xonly_pubkey_parse(secp256k1_context_static, &pubkey, m_keydata.data())) return false; - return secp256k1_schnorrsig_verify(secp256k1_context_static, sigbytes.data(), msg.begin(), 32, &pubkey); + return secp256k1_schnorrsig_verify(secp256k1_context_static, sigbytes.data(), msg.data(), msg.size(), &pubkey); } static const HashWriter HASHER_TAPTWEAK{TaggedHash("TapTweak")}; diff --git a/src/pubkey.h b/src/pubkey.h index 0391609ebcc3..da2cae854970 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -255,9 +255,10 @@ class XOnlyPubKey /** Verify a Schnorr signature against this public key. * - * sigbytes must be exactly 64 bytes. + * msg may be of any length: per BIP340 the message is not required to be a + * 32-byte hash. sigbytes must be exactly 64 bytes. */ - bool VerifySchnorr(const uint256& msg, std::span sigbytes) const; + bool VerifySchnorr(std::span msg, std::span sigbytes) const; /** Compute the Taproot tweak as specified in BIP341, with *this as internal * key: diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 14412c90fcc9..4cd658d0171a 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1516,6 +1516,7 @@ UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager& SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CSV); SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT); SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY); + SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TEMPLATEHASH); return softforks; } } // anon namespace diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 98b16eca6bcd..1d99e2f6a2c4 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -414,6 +414,57 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con assert(false); } +/** Helper for OP_CHECKSIGFROMSTACK (BIP-348). + * + * Returns false when script execution must immediately fail. On success, success_out indicates + * whether the signature check itself succeeded (false only for an empty signature). + */ +static bool EvalChecksigFromStack(const valtype& sig, const valtype& msg, const valtype& pubkey_in, ScriptExecutionData& execdata, script_verify_flags flags, SigVersion sigversion, ScriptError* serror, bool& success_out) +{ + assert(sigversion == SigVersion::TAPSCRIPT); + + /* + * The following validation sequence is consensus critical. Please note how -- + * upgradable public key versions precede other rules; + * the script execution fails when using empty signature with invalid public key; + * the script execution fails when using non-empty invalid signature. + */ + success_out = !sig.empty(); + if (success_out) { + // Implement the sigops/witnesssize ratio test. + // Passing with an upgradable public key version is also counted. + assert(execdata.m_validation_weight_left_init); + execdata.m_validation_weight_left -= VALIDATION_WEIGHT_PER_SIGOP_PASSED; + if (execdata.m_validation_weight_left < 0) { + return set_error(serror, SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT); + } + } + if (pubkey_in.size() == 0) { + return set_error(serror, SCRIPT_ERR_TAPSCRIPT_EMPTY_PUBKEY); + } else if (pubkey_in.size() == 32) { + if (success_out) { + if (sig.size() != 64) { + return set_error(serror, SCRIPT_ERR_SCHNORR_SIG_SIZE); + } + XOnlyPubKey pubkey{pubkey_in}; + if (!pubkey.VerifySchnorr(msg, sig)) { + return set_error(serror, SCRIPT_ERR_SCHNORR_SIG); + } + } + } else { + /* + * New public key version softforks should be defined before this `else` block. + * Generally, the new code should not do anything but failing the script execution. To avoid + * consensus bugs, it should not modify any existing values (including `success_out`). + */ + if ((flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE) != 0) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE); + } + } + + return true; +} + bool EvalScript(std::vector >& stack, const CScript& script, script_verify_flags flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) { static const CScriptNum bnZero(0); @@ -1224,6 +1275,64 @@ bool EvalScript(std::vector >& stack, const CScript& } break; + case OP_TEMPLATEHASH: + { + // OP_TEMPLATEHASH is only available in Tapscript. Note this is the exact same error + // returned in the default case, which would be the one hit by OP_SUCCESS206 before + // the introduction of OP_TEMPLATEHASH. + if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) { + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + + const uint256 template_hash{checker.GetTemplateHash(execdata)}; + stack.emplace_back(template_hash.begin(), template_hash.end()); + } + break; + + case OP_CHECKSIGFROMSTACK: + { + // DISCOURAGE/activation for OP_CHECKSIGFROMSTACK is handled in OP_SUCCESS handling. + // OP_CHECKSIGFROMSTACK is only available in Tapscript. + if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) { + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + + // If fewer than 3 elements are on the stack, the script MUST fail and terminate immediately. + if (stack.size() < 3) { + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + } + + // The public key (top element), message (second to top element), and + // signature (third from top element) are read from the stack. + const valtype& pubkey = stacktop(-1); + const valtype& msg = stacktop(-2); + const valtype& sig = stacktop(-3); + + bool push_success{true}; + if (!EvalChecksigFromStack(sig, msg, pubkey, execdata, flags, sigversion, serror, push_success)) { + return false; // serror set by EvalChecksigFromStack + } + + popstack(stack); + popstack(stack); + popstack(stack); + + stack.push_back(push_success ? vchTrue : vchFalse); + } + break; + + case OP_INTERNALKEY: + { + // OP_INTERNALKEY is only available in Tapscript. + if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) { + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + } + // The internal key is always set when executing Tapscript (see VerifyWitnessProgram). + assert(execdata.m_internal_key); + stack.emplace_back(execdata.m_internal_key->begin(), execdata.m_internal_key->end()); + } + break; + default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } @@ -1476,6 +1585,7 @@ template PrecomputedTransactionData::PrecomputedTransactionData(const CMutableTr const HashWriter HASHER_TAPSIGHASH{TaggedHash("TapSighash")}; const HashWriter HASHER_TAPLEAF{TaggedHash("TapLeaf")}; const HashWriter HASHER_TAPBRANCH{TaggedHash("TapBranch")}; +const HashWriter HASHER_TEMPLATEHASH{TaggedHash("TemplateHash")}; static bool HandleMissingData(MissingDataBehavior mdb) { @@ -1835,6 +1945,27 @@ bool GenericTransactionSignatureChecker::CheckSequence(const CScriptNum& nSeq return true; } +template +uint256 GenericTransactionSignatureChecker::GetTemplateHash(ScriptExecutionData& execdata) const +{ + assert(txdata && txdata->m_bip341_taproot_ready); + assert(execdata.m_annex_init); + + HashWriter ss{HASHER_TEMPLATEHASH}; + ss << txTo->version; + ss << txTo->nLockTime; + ss << txdata->m_sequences_single_hash; + ss << txdata->m_outputs_single_hash; + const uint8_t annex_present = (execdata.m_annex_present ? 1 : 0); + ss << annex_present; + ss << nIn; + if (execdata.m_annex_present) { + ss << execdata.m_annex_hash; + } + + return ss.GetSHA256(); +} + // explicit instantiation template class GenericTransactionSignatureChecker; template class GenericTransactionSignatureChecker; @@ -1854,6 +1985,16 @@ static bool ExecuteWitnessScript(const std::span& stack_span, con } // New opcodes will be listed here. May use a different sigversion to modify existing opcodes. if (IsOpSuccess(opcode)) { + // Do not return early success on the BIP-448 opcodes (OP_TEMPLATEHASH, + // OP_CHECKSIGFROMSTACK, OP_INTERNALKEY) once they are active. They are non-standard until then. + if (opcode == OP_TEMPLATEHASH || opcode == OP_CHECKSIGFROMSTACK || opcode == OP_INTERNALKEY) { + if (flags & SCRIPT_VERIFY_DISCOURAGE_TEMPLATEHASH) { + return set_error(serror, SCRIPT_ERR_DISCOURAGE_TEMPLATEHASH); + } + if (flags & SCRIPT_VERIFY_TEMPLATEHASH) { + continue; + } + } if (flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS) { return set_error(serror, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS); } @@ -1990,6 +2131,8 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, exec_script = CScript(script.begin(), script.end()); execdata.m_validation_weight_left = ::GetSerializeSize(witness.stack) + VALIDATION_WEIGHT_OFFSET; execdata.m_validation_weight_left_init = true; + // Expose the verified 32-byte internal key (control[1:33]) for OP_INTERNALKEY. + execdata.m_internal_key = uint256{std::span{control}.subspan(1, 32)}; return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::TAPSCRIPT, checker, execdata, serror); } if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) { @@ -2200,6 +2343,8 @@ const std::map& ScriptFlagNamesToEnum() FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE), FLAG_NAME(DISCOURAGE_OP_SUCCESS), FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION), + FLAG_NAME(TEMPLATEHASH), + FLAG_NAME(DISCOURAGE_TEMPLATEHASH), }; #undef FLAG_NAME return g_names_to_enum; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index ff63a73f0fc7..95f015e78df4 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -146,6 +146,12 @@ enum class script_verify_flag_name : uint8_t { // Making unknown public key versions (in BIP 342 scripts) non-standard SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE, + // OP_TEMPLATEHASH validation (BIP 446) + SCRIPT_VERIFY_TEMPLATEHASH, + + // Make OP_TEMPLATEHASH spend non-standard before activation. + SCRIPT_VERIFY_DISCOURAGE_TEMPLATEHASH, + // Constants to point to the highest flag in use. Add new flags above this line. // SCRIPT_VERIFY_END_MARKER @@ -232,6 +238,9 @@ struct ScriptExecutionData //! The hash of the corresponding output std::optional m_output_hash; + + //! The 32-byte x-only Taproot internal key, set for Tapscript spends (for OP_INTERNALKEY). + std::optional m_internal_key; }; /** Signature hash sizes */ @@ -295,6 +304,11 @@ class BaseSignatureChecker return false; } + virtual uint256 GetTemplateHash(ScriptExecutionData& execdata) const + { + return {}; + } + virtual ~BaseSignatureChecker() = default; }; @@ -332,6 +346,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker bool CheckSchnorrSignature(std::span sig, std::span pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; + uint256 GetTemplateHash(ScriptExecutionData& execdata) const override; }; using TransactionSignatureChecker = GenericTransactionSignatureChecker; @@ -363,6 +378,11 @@ class DeferringSignatureChecker : public BaseSignatureChecker { return m_checker.CheckSequence(nSequence); } + + uint256 GetTemplateHash(ScriptExecutionData& execdata) const override + { + return m_checker.GetTemplateHash(execdata); + } }; /** Compute the BIP341 tapleaf hash from leaf version & script. */ diff --git a/src/script/script.cpp b/src/script/script.cpp index 4097d13d2c4a..56358292c1df 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -150,6 +150,15 @@ std::string GetOpName(opcodetype opcode) // Opcode added by BIP 342 (Tapscript) case OP_CHECKSIGADD : return "OP_CHECKSIGADD"; + // Opcode added by BIP446 (Tapscript) + case OP_TEMPLATEHASH : return "OP_TEMPLATEHASH"; + + // Opcode added by BIP348 (Tapscript) + case OP_CHECKSIGFROMSTACK : return "OP_CHECKSIGFROMSTACK"; + + // Opcode added by BIP349 (Tapscript) + case OP_INTERNALKEY : return "OP_INTERNALKEY"; + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; } // no default case, so the compiler can warn about missing cases diff --git a/src/script/script.h b/src/script/script.h index e0112cc386e7..af1463637c72 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -210,6 +210,15 @@ enum opcodetype // Opcode added by BIP 342 (Tapscript) OP_CHECKSIGADD = 0xba, + // Opcode added by BIP xx (Tapscript-only, formerly OP_SUCCESS206) + OP_TEMPLATEHASH = 0xce, + + // Opcode added by BIP348 (Tapscript-only, formerly OP_SUCCESS204) + OP_CHECKSIGFROMSTACK = 0xcc, + + // Opcode added by BIP349 (Tapscript-only, formerly OP_SUCCESS203) + OP_INTERNALKEY = 0xcb, + OP_INVALIDOPCODE = 0xff, }; diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index 7fa127420e65..afcabad76a0d 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -79,6 +79,8 @@ std::string ScriptErrorString(const ScriptError serror) return "OP_SUCCESSx reserved for soft-fork upgrades"; case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE: return "Public key version reserved for soft-fork upgrades"; + case SCRIPT_ERR_DISCOURAGE_TEMPLATEHASH: + return "BIP-448 opcode not active"; case SCRIPT_ERR_PUBKEYTYPE: return "Public key is neither compressed or uncompressed"; case SCRIPT_ERR_CLEANSTACK: diff --git a/src/script/script_error.h b/src/script/script_error.h index 60ab3e51bfe6..c1ca6e015683 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -60,6 +60,7 @@ typedef enum ScriptError_t SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION, SCRIPT_ERR_DISCOURAGE_OP_SUCCESS, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE, + SCRIPT_ERR_DISCOURAGE_TEMPLATEHASH, /* segregated witness */ SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH, diff --git a/src/test/fuzz/CMakeLists.txt b/src/test/fuzz/CMakeLists.txt index a159ef7e11cd..4e2f89af5e4d 100644 --- a/src/test/fuzz/CMakeLists.txt +++ b/src/test/fuzz/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable(fuzz buffered_file.cpp chain.cpp checkqueue.cpp + checksigfromstack.cpp cluster_linearize.cpp cmpctblock.cpp coins_view.cpp @@ -122,6 +123,7 @@ add_executable(fuzz string.cpp strprintf.cpp system.cpp + templatehash.cpp threadpool.cpp timeoffsets.cpp torcontrol.cpp diff --git a/src/test/fuzz/checksigfromstack.cpp b/src/test/fuzz/checksigfromstack.cpp new file mode 100644 index 000000000000..7a469a7470ab --- /dev/null +++ b/src/test/fuzz/checksigfromstack.cpp @@ -0,0 +1,107 @@ +// Copyright (c) 2009-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include +#include +#include +#include