Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_
enum DeploymentPos : uint16_t {
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_TAPROOT, // Deployment of Schnorr/Taproot (BIPs 340-342)
DEPLOYMENT_TEMPLATEHASH,
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
Expand Down
4 changes: 4 additions & 0 deletions src/deploymentinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ const std::array<VBDeploymentInfo,Consensus::MAX_VERSION_BITS_DEPLOYMENTS> Versi
.name = "taproot",
.gbt_optional_rule = true,
},
VBDeploymentInfo{
.name = "templatehash",
.gbt_optional_rule = true,
}
};

std::string DeploymentName(Consensus::BuriedDeployment dep)
Expand Down
32 changes: 32 additions & 0 deletions src/kernel/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ class CMainParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].threshold = 1815; // 90%
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].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;

consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000b1f3b93b65b16d035a82be84"};
consensus.defaultAssumeValid = uint256{"00000000000000000001b658dd1120e82e66d2790811f89ede9742ada3ed6d77"}; // 886157

Expand Down Expand Up @@ -232,6 +238,12 @@ class CTestNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].threshold = 1512; // 75%
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].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;

consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000015f5e0c9f13455b0eb17"};
consensus.defaultAssumeValid = uint256{"00000000000003fc7967410ba2d0a8a8d50daedc318d43e8baf1a9782c236a57"}; // 3974606

Expand Down Expand Up @@ -328,6 +340,12 @@ class CTestNet4Params : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].threshold = 1512; // 75%
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].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;

consensus.nMinimumChainWork = uint256{"0000000000000000000000000000000000000000000001d6dce8651b6094e4c1"};
consensus.defaultAssumeValid = uint256{"0000000000003ed4f08dbdf6f7d6b271a6bcffce25675cb40aa9fa43179a89f3"}; // 72600

Expand Down Expand Up @@ -462,6 +480,12 @@ class SigNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].threshold = 1815; // 90%
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].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;

// message start is defined as the first 4 bytes of the sha256d of the block script
HashWriter h{};
h << consensus.signet_challenge;
Expand Down Expand Up @@ -539,6 +563,14 @@ class CRegTestParams : public CChainParams
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].threshold = 108; // 75%
consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].period = 144;

// 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{};

Expand Down
4 changes: 3 additions & 1 deletion src/policy/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ 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_TEMPLATEHASH |
SCRIPT_VERIFY_TEMPLATEHASH};

/** 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};
Expand Down
1 change: 1 addition & 0 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1423,6 +1423,7 @@ UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager&
SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT);
SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY);
SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT);
SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TEMPLATEHASH);
return softforks;
}
} // anon namespace
Expand Down
46 changes: 46 additions & 0 deletions src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,20 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& 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_SUCCESS187 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.push_back({template_hash.begin(), template_hash.end()});
}
break;

default:
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
Expand Down Expand Up @@ -1461,6 +1475,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)
{
Expand Down Expand Up @@ -1781,6 +1796,27 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
return true;
}

template<class T>
uint256 GenericTransactionSignatureChecker<T>::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<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;
Expand All @@ -1800,6 +1836,16 @@ static bool ExecuteWitnessScript(const std::span<const valtype>& 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 OP_TEMPLATEHASH (OP_SUCCESS187) once it is active. It is
// non-standard until then.
if (opcode == OP_TEMPLATEHASH) {
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);
}
Expand Down
17 changes: 17 additions & 0 deletions src/script/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ enum : uint32_t {
// Making unknown public key versions (in BIP 342 scripts) non-standard
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),

// OP_TEMPLATEHASH validation (BIP xx)
SCRIPT_VERIFY_TEMPLATEHASH = (1U << 21),

// Make OP_TEMPLATEHASH spend non-standard before activation.
SCRIPT_VERIFY_DISCOURAGE_TEMPLATEHASH = (1U << 22),

// Constants to point to the highest flag in use. Add new flags above this line.
//
SCRIPT_VERIFY_END_MARKER
Expand Down Expand Up @@ -265,6 +271,11 @@ class BaseSignatureChecker
return false;
}

virtual uint256 GetTemplateHash(ScriptExecutionData& execdata) const
{
return {};
}

virtual ~BaseSignatureChecker() = default;
};

Expand Down Expand Up @@ -301,6 +312,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
bool CheckSchnorrSignature(std::span<const unsigned char> sig, std::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;
uint256 GetTemplateHash(ScriptExecutionData& execdata) const override;
};

using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
Expand Down Expand Up @@ -332,6 +344,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. */
Expand Down
3 changes: 3 additions & 0 deletions src/script/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ std::string GetOpName(opcodetype opcode)
// Opcode added by BIP 342 (Tapscript)
case OP_CHECKSIGADD : return "OP_CHECKSIGADD";

// Opcode added by BIP xx (Tapscript-only, formerly OP_SUCCESS187)
case OP_TEMPLATEHASH : return "OP_TEMPLATEHASH";

case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";

default:
Expand Down
3 changes: 3 additions & 0 deletions src/script/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ enum opcodetype
// Opcode added by BIP 342 (Tapscript)
OP_CHECKSIGADD = 0xba,

// Opcode added by BIP xx (Tapscript-only, formerly OP_SUCCESS187)
OP_TEMPLATEHASH = 0xbb,

OP_INVALIDOPCODE = 0xff,
};

Expand Down
2 changes: 2 additions & 0 deletions src/script/script_error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 "Templatehash is not active";
case SCRIPT_ERR_PUBKEYTYPE:
return "Public key is neither compressed or uncompressed";
case SCRIPT_ERR_CLEANSTACK:
Expand Down
1 change: 1 addition & 0 deletions src/script/script_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,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,
Expand Down
1 change: 1 addition & 0 deletions src/test/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ add_executable(fuzz
string.cpp
strprintf.cpp
system.cpp
templatehash.cpp
timeoffsets.cpp
torcontrol.cpp
transaction.cpp
Expand Down
4 changes: 3 additions & 1 deletion src/test/fuzz/script_assets_test_minimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,14 @@ const std::map<std::string, unsigned int> FLAG_NAMES = {
{std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY},
{std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS},
{std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT},
{std::string("TEMPLATE"), (unsigned int)SCRIPT_VERIFY_TEMPLATEHASH},
};

std::vector<unsigned int> AllFlags()
{
std::vector<unsigned int> ret;

for (unsigned int i = 0; i < 128; ++i) {
for (unsigned int i = 0; i < 256; ++i) {
unsigned int flag = 0;
if (i & 1) flag |= SCRIPT_VERIFY_P2SH;
if (i & 2) flag |= SCRIPT_VERIFY_DERSIG;
Expand All @@ -113,6 +114,7 @@ std::vector<unsigned int> AllFlags()
if (i & 16) flag |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
if (i & 32) flag |= SCRIPT_VERIFY_WITNESS;
if (i & 64) flag |= SCRIPT_VERIFY_TAPROOT;
if (i & 128) flag |= SCRIPT_VERIFY_TEMPLATEHASH;

// SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH
if (flag & SCRIPT_VERIFY_WITNESS && !(flag & SCRIPT_VERIFY_P2SH)) continue;
Expand Down
Loading
Loading