Skip to content

Commit ff1cc73

Browse files
authored
Merge pull request #66 from ajtowns/202409-inq28-ctv
Implement BIP 119 validation (OP_CHECKTEMPLATEVERIFY)
2 parents 1deba63 + 530ee1b commit ff1cc73

32 files changed

+3640
-19
lines changed

src/Makefile.test.include

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ JSON_TEST_FILES = \
1919
test/data/bip341_wallet_vectors.json \
2020
test/data/base58_encode_decode.json \
2121
test/data/blockfilters.json \
22+
test/data/ctvhash.json \
2223
test/data/key_io_valid.json \
2324
test/data/key_io_invalid.json \
2425
test/data/script_tests.json \
@@ -91,6 +92,7 @@ BITCOIN_TESTS =\
9192
test/compilerbug_tests.cpp \
9293
test/compress_tests.cpp \
9394
test/crypto_tests.cpp \
95+
test/ctvhash_tests.cpp \
9496
test/cuckoocache_tests.cpp \
9597
test/dbwrapper_tests.cpp \
9698
test/denialofservice_tests.cpp \

src/addresstype.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
9898
case TxoutType::MULTISIG:
9999
case TxoutType::NULL_DATA:
100100
case TxoutType::NONSTANDARD:
101+
case TxoutType::TX_BARE_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH:
101102
addressRet = CNoDestination(scriptPubKey);
102103
return false;
103104
} // no default case, so the compiler can warn about missing cases

src/consensus/params.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_
3232

3333
enum DeploymentPos : uint16_t {
3434
DEPLOYMENT_TESTDUMMY,
35+
DEPLOYMENT_CHECKTEMPLATEVERIFY, // Deployment of CTV (BIP 119)
3536
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp
3637
MAX_VERSION_BITS_DEPLOYMENTS
3738
};

src/deploymentinfo.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B
1515
/*.name =*/ "testdummy",
1616
/*.gbt_force =*/ true,
1717
},
18+
{
19+
/*.name =*/ "checktemplateverify",
20+
/*.gbt_force =*/ true,
21+
},
1822
};
1923

2024
std::string DeploymentName(Consensus::BuriedDeployment dep)
@@ -76,6 +80,9 @@ const std::map<std::string, uint32_t> g_verify_flag_names{
7680
FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE),
7781
FLAG_NAME(DISCOURAGE_OP_SUCCESS),
7882
FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION),
83+
FLAG_NAME(DEFAULT_CHECK_TEMPLATE_VERIFY_HASH),
84+
FLAG_NAME(DISCOURAGE_UPGRADABLE_CHECK_TEMPLATE_VERIFY_HASH),
85+
FLAG_NAME(DISCOURAGE_CHECK_TEMPLATE_VERIFY_HASH),
7986
};
8087
#undef FLAG_NAME
8188

src/kernel/chainparams.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class CMainParams : public CChainParams {
142142
consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
143143
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
144144
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = SetupDeployment{.activate = 0x30000000, .abandon = 0, .never = true};
145+
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{.activate = 0x60007700, .abandon = 0x40007700, .never = true};
145146

146147
consensus.nMinimumChainWork = uint256{"000000000000000000000000000000000000000088e186b70e0862c193ec44d6"};
147148
consensus.defaultAssumeValid = uint256{"000000000000000000011c5890365bdbe5d25b97ce0057589acaef4f1a57263f"}; // 856760
@@ -258,6 +259,7 @@ class CTestNetParams : public CChainParams {
258259
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
259260
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
260261
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = SetupDeployment{.activate = 0x30000000, .abandon = 0, .never = true};
262+
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{.activate = 0x60007700, .abandon = 0x40007700, .never = true};
261263

262264
consensus.nMinimumChainWork = uint256{"000000000000000000000000000000000000000000000f209695166be8b61fa9"};
263265
consensus.defaultAssumeValid = uint256{"000000000000000465b1a66c9f386308e8c75acef9201f3f577811da09fc90ad"}; // 2873500
@@ -481,6 +483,12 @@ class SigNetParams : public CChainParams {
481483
consensus.MinBIP9WarningHeight = 0;
482484
consensus.powLimit = uint256{"00000377ae000000000000000000000000000000000000000000000000000000"};
483485
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = SetupDeployment{.activate = 0x30000000, .abandon = 0, .never = true};
486+
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{
487+
.start = 1654041600, // 2022-06-01
488+
.timeout = 1969660800, // 2032-06-01
489+
.activate = 0x60007700,
490+
.abandon = 0x40007700,
491+
};
484492

485493
RenounceDeployments(options.renounce, consensus.vDeployments);
486494

@@ -554,6 +562,7 @@ class CRegTestParams : public CChainParams
554562

555563
// 0x3000_0000 = bit 28 plus versionbits signalling; 0x5000_0000 = bit 38 plus VERSIONBITS_TOP_ABANDON
556564
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = SetupDeployment{.start = 0, .timeout = Consensus::HereticalDeployment::NO_TIMEOUT, .activate = 0x30000000, .abandon = 0x50000000};
565+
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{.activate = 0x60007700, .abandon = 0x40007700, .always = true};
557566

558567
consensus.nMinimumChainWork = uint256{};
559568
consensus.defaultAssumeValid = uint256{};

src/policy/policy.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
202202
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
203203
return false;
204204
}
205+
} else if (whichType == TxoutType::TX_BARE_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) {
206+
// after activation, only allow bare with no scriptsig.
207+
// pre-activation disallowing enforced via discouraged logic in the
208+
// interpreter.
209+
if (tx.vin[i].scriptSig.size() != 0) return false;
205210
}
206211
}
207212

src/policy/policy.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI
113113
SCRIPT_VERIFY_CONST_SCRIPTCODE |
114114
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
115115
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
116-
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE};
116+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE |
117+
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECK_TEMPLATE_VERIFY_HASH |
118+
SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH};
117119

118120
/** For convenience, standard but not mandatory verify flags. */
119121
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS};

src/rpc/blockchain.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,7 @@ UniValue DeploymentInfo(const CBlockIndex* blockindex, const ChainstateManager&
13931393
SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_SEGWIT);
13941394
SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TESTDUMMY);
13951395
SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_TAPROOT);
1396+
SoftForkDescPushBack(blockindex, softforks, chainman, Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY);
13961397
return softforks;
13971398
}
13981399
} // anon namespace

src/rpc/rawtransaction.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ static RPCHelpMan decodescript()
558558
case TxoutType::WITNESS_UNKNOWN:
559559
case TxoutType::WITNESS_V1_TAPROOT:
560560
case TxoutType::ANCHOR:
561+
// don't wrap CTV because P2SH CTV is a hash cycle
562+
case TxoutType::TX_BARE_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH:
561563
// Should not be wrapped
562564
return false;
563565
} // no default case, so the compiler can warn about missing cases
@@ -601,6 +603,8 @@ static RPCHelpMan decodescript()
601603
case TxoutType::WITNESS_V0_SCRIPTHASH:
602604
case TxoutType::WITNESS_V1_TAPROOT:
603605
case TxoutType::ANCHOR:
606+
// don't wrap CTV because P2SH CTV is a hash cycle
607+
case TxoutType::TX_BARE_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH:
604608
// Should not be wrapped
605609
return false;
606610
} // no default case, so the compiler can warn about missing cases

src/script/interpreter.cpp

+126-2
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,42 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
591591
break;
592592
}
593593

594-
case OP_NOP1: case OP_NOP4: case OP_NOP5:
594+
case OP_CHECKTEMPLATEVERIFY:
595+
{
596+
if (flags & SCRIPT_VERIFY_DISCOURAGE_CHECK_TEMPLATE_VERIFY_HASH) {
597+
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
598+
}
599+
600+
// if flags not enabled; treat as a NOP4
601+
if (!(flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH)) {
602+
break;
603+
}
604+
605+
if (stack.size() < 1) {
606+
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
607+
}
608+
609+
// If the argument was not 32 bytes, treat as OP_NOP4:
610+
switch (stack.back().size()) {
611+
case 32:
612+
{
613+
const Span<const unsigned char> hash{stack.back()};
614+
if (!checker.CheckDefaultCheckTemplateVerifyHash(hash)) {
615+
return set_error(serror, SCRIPT_ERR_TEMPLATE_MISMATCH);
616+
}
617+
break;
618+
}
619+
default:
620+
// future upgrade can add semantics for this opcode with different length args
621+
// so discourage use when applicable
622+
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_CHECK_TEMPLATE_VERIFY_HASH) {
623+
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
624+
}
625+
}
626+
}
627+
break;
628+
629+
case OP_NOP1: case OP_NOP5:
595630
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
596631
{
597632
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@@ -1377,6 +1412,18 @@ uint256 GetSpentAmountsSHA256(const std::vector<CTxOut>& outputs_spent)
13771412
HashWriter ss{};
13781413
for (const auto& txout : outputs_spent) {
13791414
ss << txout.nValue;
1415+
1416+
}
1417+
return ss.GetSHA256();
1418+
}
1419+
1420+
/** Compute the (single) SHA256 of the concatenation of all scriptSigs in a tx. */
1421+
template <class T>
1422+
uint256 GetScriptSigsSHA256(const T& txTo)
1423+
{
1424+
HashWriter ss{};
1425+
for (const auto& in : txTo.vin) {
1426+
ss << in.scriptSig;
13801427
}
13811428
return ss.GetSHA256();
13821429
}
@@ -1391,9 +1438,63 @@ uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
13911438
return ss.GetSHA256();
13921439
}
13931440

1441+
/* Not Exported, just convenience */
1442+
template<typename TxType>
1443+
uint256 GetDefaultCheckTemplateVerifyHashWithScript(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash,
1444+
const uint256& scriptSig_hash, const uint32_t input_index) {
1445+
auto h = HashWriter{}
1446+
<< tx.version
1447+
<< tx.nLockTime
1448+
<< scriptSig_hash
1449+
<< uint32_t(tx.vin.size())
1450+
<< sequences_hash
1451+
<< uint32_t(tx.vout.size())
1452+
<< outputs_hash
1453+
<< input_index;
1454+
return h.GetSHA256();
1455+
}
1456+
1457+
template<typename TxType>
1458+
uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash,
1459+
const uint32_t input_index) {
1460+
auto h = HashWriter{}
1461+
<< tx.version
1462+
<< tx.nLockTime
1463+
<< uint32_t(tx.vin.size())
1464+
<< sequences_hash
1465+
<< uint32_t(tx.vout.size())
1466+
<< outputs_hash
1467+
<< input_index;
1468+
return h.GetSHA256();
1469+
}
13941470

13951471
} // namespace
13961472

1473+
template<typename TxType>
1474+
uint256 GetDefaultCheckTemplateVerifyHash(const TxType& tx, uint32_t input_index) {
1475+
return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequencesSHA256(tx), input_index);
1476+
}
1477+
1478+
template<typename TxType>
1479+
static bool NoScriptSigs(const TxType& tx)
1480+
{
1481+
return std::all_of(tx.vin.begin(), tx.vin.end(), [](const CTxIn& c) { return c.scriptSig.empty(); });
1482+
}
1483+
1484+
template<typename TxType>
1485+
uint256 GetDefaultCheckTemplateVerifyHash(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash,
1486+
const uint32_t input_index) {
1487+
return NoScriptSigs(tx) ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) :
1488+
GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index);
1489+
}
1490+
1491+
template
1492+
uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
1493+
const uint32_t input_index);
1494+
template
1495+
uint256 GetDefaultCheckTemplateVerifyHash(const CMutableTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
1496+
const uint32_t input_index);
1497+
13971498
template <class T>
13981499
void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent_outputs, bool force)
13991500
{
@@ -1405,6 +1506,8 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
14051506
m_spent_outputs_ready = true;
14061507
}
14071508

1509+
// TODO: Improve this heuristic
1510+
bool uses_bip119_ctv = true;
14081511
// Determine which precomputation-impacting features this transaction uses.
14091512
bool uses_bip143_segwit = force;
14101513
bool uses_bip341_taproot = force;
@@ -1427,11 +1530,16 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
14271530
if (uses_bip341_taproot && uses_bip143_segwit) break; // No need to scan further if we already need all.
14281531
}
14291532

1430-
if (uses_bip143_segwit || uses_bip341_taproot) {
1533+
if (uses_bip143_segwit || uses_bip341_taproot || uses_bip119_ctv) {
14311534
// Computations shared between both sighash schemes.
14321535
m_prevouts_single_hash = GetPrevoutsSHA256(txTo);
14331536
m_sequences_single_hash = GetSequencesSHA256(txTo);
14341537
m_outputs_single_hash = GetOutputsSHA256(txTo);
1538+
1539+
// 0 hash used to signal if we should skip scriptSigs
1540+
// when re-computing for different indexes.
1541+
m_scriptSigs_single_hash = NoScriptSigs(txTo) ? uint256{} : GetScriptSigsSHA256(txTo);
1542+
m_bip119_ctv_ready = true;
14351543
}
14361544
if (uses_bip143_segwit) {
14371545
hashPrevouts = SHA256Uint256(m_prevouts_single_hash);
@@ -1781,6 +1889,22 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
17811889
return true;
17821890
}
17831891

1892+
template <class T>
1893+
bool GenericTransactionSignatureChecker<T>::CheckDefaultCheckTemplateVerifyHash(const Span<const unsigned char>& hash) const
1894+
{
1895+
// Should already be checked before calling...
1896+
assert(hash.size() == 32);
1897+
if (txdata && txdata->m_bip119_ctv_ready) {
1898+
assert(txTo != nullptr);
1899+
uint256 hash_tmpl = txdata->m_scriptSigs_single_hash.IsNull() ?
1900+
GetDefaultCheckTemplateVerifyHashEmptyScript(*txTo, txdata->m_outputs_single_hash, txdata->m_sequences_single_hash, nIn) :
1901+
GetDefaultCheckTemplateVerifyHashWithScript(*txTo, txdata->m_outputs_single_hash, txdata->m_sequences_single_hash,
1902+
txdata->m_scriptSigs_single_hash, nIn);
1903+
return std::equal(hash_tmpl.begin(), hash_tmpl.end(), hash.data());
1904+
} else {
1905+
return HandleMissingData(m_mdb);
1906+
}
1907+
}
17841908
// explicit instantiation
17851909
template class GenericTransactionSignatureChecker<CTransaction>;
17861910
template class GenericTransactionSignatureChecker<CMutableTransaction>;

0 commit comments

Comments
 (0)