Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement BIP 119 Validation (OP_CHECKTEMPLATEVERIFY) #3

Merged
merged 20 commits into from
Sep 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
6f63cdd
[TESTS] Update Transaction Tests to permit setting a flag as always o…
JeremyRubin Sep 2, 2021
0644d50
[TESTS] Allow tx_invalid.json tests to include flag rules for if_unse…
JeremyRubin Sep 11, 2021
b515b44
Add StandardTemplateHash definition
JeremyRubin Oct 16, 2019
ce1cc5b
Add SignatureChecker method for checking DefaultCheckTemplateVerifyHash.
JeremyRubin Oct 16, 2019
880e2b6
Add OP_CHECKTEMPLATEVERIFY Opcode as OP_NOP4
JeremyRubin Oct 16, 2019
3520060
Fixup: Make CTV Opcode use Span
JeremyRubin Jan 26, 2022
99f291b
Change printing of NOP4 to CheckTemplateVerify (separate commit for e…
JeremyRubin Sep 2, 2021
fc21035
[Anti-DoS Caching] Precompute the DefaultCheckTemplateVerifyHash
JeremyRubin Oct 16, 2019
317ca86
[Refactor] Document and pack the fields in the PrecomputedData
JeremyRubin Sep 2, 2021
c24d124
[Anti-DoS Caching] No longer Cache CTV Hash at input index 0
JeremyRubin Jan 20, 2022
3bbcc52
[Anti-DoS Caching] Make PrecomputedTransactionData non-const and lazi…
JeremyRubin Jan 20, 2022
85ee571
[Anti-DoS Caching] Refactor BIP-119 LazyInit to use lambda for depend…
JeremyRubin Jan 26, 2022
9040de7
Make Bare OP_CHECKTEMPLATEVERIFY basic transactions standard
JeremyRubin Oct 16, 2019
c7b0d35
OP_CHECKTEMPLATEVERIFY Deployment parameters
JeremyRubin Oct 16, 2019
e00c43f
[TESTS] Add OP_CHECKTEMPLATEVERIFY functional tests
JeremyRubin Oct 16, 2019
6d6e866
[TESTS] add tx_valid.json tests for BIP-119 CheckTemplateVerify
JeremyRubin Sep 2, 2021
41b37a6
[TESTS] Add tx_invalid.json examples for BIP-119 CheckTemplateVerify
JeremyRubin Sep 12, 2021
d76ca15
[TESTS] Add CTV Hash Computation Unit Test & Mutation Tester
JeremyRubin Sep 12, 2021
f39c5b2
OP_CHECKTEMPLATEVERIFY Deployment parameters for signet/inquisition
ajtowns Aug 31, 2022
eb8652d
OP_CHECKTEMPLATEVERIFY: Special case deployment parameters for CTV si…
ajtowns Sep 5, 2022
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
2 changes: 2 additions & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ JSON_TEST_FILES = \
test/data/bip341_wallet_vectors.json \
test/data/base58_encode_decode.json \
test/data/blockfilters.json \
test/data/ctvhash.json \
test/data/key_io_valid.json \
test/data/key_io_invalid.json \
test/data/script_tests.json \
Expand Down Expand Up @@ -86,6 +87,7 @@ BITCOIN_TESTS =\
test/compilerbug_tests.cpp \
test/compress_tests.cpp \
test/crypto_tests.cpp \
test/ctvhash_tests.cpp \
test/cuckoocache_tests.cpp \
test/dbwrapper_tests.cpp \
test/denialofservice_tests.cpp \
Expand Down
22 changes: 22 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class CMainParams : public CChainParams {
consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = SetupDeployment{.activate = 0x30000000, .abandon = 0, .never = true};
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{.bip = 119, .bip_version = 0, .never = true};

consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000002927cdceccbd5209e81e80db");
consensus.defaultAssumeValid = uint256S("0x000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091"); // 724466
Expand Down Expand Up @@ -237,6 +238,7 @@ class CTestNetParams : public CChainParams {
consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = SetupDeployment{.activate = 0x30000000, .abandon = 0, .never = true};
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{.bip = 119, .bip_version = 0, .never = true};

consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000064728c7be6fe4b2f961");
consensus.defaultAssumeValid = uint256S("0x00000000000163cfb1f97c4e4098a3692c8053ad9cab5ad9c86b338b5c00b8b7"); // 2143398
Expand Down Expand Up @@ -306,6 +308,7 @@ class SigNetParams : public CChainParams {
std::vector<uint8_t> bin;
vSeeds.clear();

bool is_special_ctv_signet = false;
if (!args.IsArgSet("-signetchallenge")) {
bin = ParseHex("512103ad5e0edad18cb1f0fc0d28a3d4f1f3e445640337489abb10404f2d1e086be430210359ef5021964fe22d6f8e05b2463c9540ce96883fe3b278760f048f5189f2e6c452ae");
vSeeds.emplace_back("seed.signet.bitcoin.sprovoost.nl.");
Expand All @@ -329,6 +332,9 @@ class SigNetParams : public CChainParams {
if (signet_challenge.size() != 1) {
throw std::runtime_error(strprintf("%s: -signetchallenge cannot be multiple values.", __func__));
}
if (signet_challenge[0] == "512102946e8ba8eca597194e7ed90377d9bbebc5d17a9609ab3e35e706612ee882759351ae") {
is_special_ctv_signet = true;
}
bin = ParseHex(signet_challenge[0]);

consensus.nMinimumChainWork = uint256{};
Expand Down Expand Up @@ -368,6 +374,21 @@ class SigNetParams : public CChainParams {
consensus.MinBIP9WarningHeight = 0;
consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = SetupDeployment{.activate = 0x30000000, .abandon = 0, .never = true};
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{
.bip = 119,
.bip_version = 0,
.start = 1654041600, // 2022-06-01
.timeout = 1969660800, // 2032-06-01
};
if (is_special_ctv_signet) {
// custom deployment parameters for compat
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{
.start = 1608242730, // 2020-12-18 (first block on ctv signet)
.timeout = 1969660800, // 2032-06-01
.activate = 0x20000000, // default version signals for activation
.abandon = 0, // consensus invalid due to BIP34
};
}
RenounceDeployments(args, consensus.vDeployments);

// message start is defined as the first 4 bytes of the sha256d of the block script
Expand Down Expand Up @@ -431,6 +452,7 @@ class CRegTestParams : public CChainParams {

// 0x3000_0000 = bit 28 plus versionbits signalling; 0x5000_0000 = bit 38 plus VERSIONBITS_TOP_ABANDON
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY] = SetupDeployment{.start = 0, .timeout = Consensus::HereticalDeployment::NO_TIMEOUT, .activate = 0x30000000, .abandon = 0x50000000};
consensus.vDeployments[Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY] = SetupDeployment{.bip = 119, .bip_version = 0, .always = true};

consensus.nMinimumChainWork = uint256{};
consensus.defaultAssumeValid = uint256{};
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_

enum DeploymentPos : uint16_t {
DEPLOYMENT_TESTDUMMY,
DEPLOYMENT_CHECKTEMPLATEVERIFY, // Deployment of CTV (BIP 119)
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp
MAX_VERSION_BITS_DEPLOYMENTS
};
Expand Down
5 changes: 5 additions & 0 deletions src/deploymentinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B
/*.name =*/ "testdummy",
/*.gbt_force =*/ true,
},
{
/*.name =*/ "checktemplateverify",
/*.gbt_force =*/ true,
},
};

std::string DeploymentName(Consensus::BuriedDeployment dep)
Expand Down Expand Up @@ -58,6 +62,7 @@ const std::map<std::string, uint32_t> g_verify_flag_names{
FLAG_NAME(DISCOURAGE_UPGRADABLE_PUBKEYTYPE)
FLAG_NAME(DISCOURAGE_OP_SUCCESS)
FLAG_NAME(DISCOURAGE_UPGRADABLE_TAPROOT_VERSION)
FLAG_NAME(DEFAULT_CHECK_TEMPLATE_VERIFY_HASH)
};
#undef FLAG_NAME

Expand Down
2 changes: 1 addition & 1 deletion src/node/psbt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)

result.inputs.resize(psbtx.tx->vin.size());

const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);

for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
PSBTInput& input = psbtx.inputs[i];
Expand Down
5 changes: 5 additions & 0 deletions src/policy/policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,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_CHECK_TEMPLATE_VERIFY_HASH) {
// 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;
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/policy/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
SCRIPT_VERIFY_TAPROOT |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE;
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE |
SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH;

/** 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
4 changes: 2 additions & 2 deletions src/psbt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ PrecomputedTransactionData PrecomputePSBTData(const PartiallySignedTransaction&
return txdata;
}

bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, PrecomputedTransactionData* txdata, int sighash, SignatureData* out_sigdata, bool finalize)
{
PSBTInput& input = psbt.inputs.at(index);
const CMutableTransaction& tx = *psbt.tx;
Expand Down Expand Up @@ -337,7 +337,7 @@ bool FinalizePSBT(PartiallySignedTransaction& psbtx)
// PartiallySignedTransaction did not understand them), this will combine them into a final
// script.
bool complete = true;
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
complete &= SignPSBTInput(DUMMY_SIGNING_PROVIDER, psbtx, i, &txdata, SIGHASH_ALL, nullptr, true);
}
Expand Down
2 changes: 1 addition & 1 deletion src/psbt.h
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ bool PSBTInputSigned(const PSBTInput& input);
* txdata should be the output of PrecomputePSBTData (which can be shared across
* multiple SignPSBTInput calls). If it is nullptr, a dummy signature will be created.
**/
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, const PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);
bool SignPSBTInput(const SigningProvider& provider, PartiallySignedTransaction& psbt, int index, PrecomputedTransactionData* txdata, int sighash = SIGHASH_ALL, SignatureData* out_sigdata = nullptr, bool finalize = true);

/** Counts the unsigned inputs of a PSBT. */
size_t CountPSBTUnsignedInputs(const PartiallySignedTransaction& psbt);
Expand Down
1 change: 1 addition & 0 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1657,6 +1657,7 @@ UniValue DeploymentInfo(const CBlockIndex* blockindex, const Consensus::Params&
SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_SEGWIT);
SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT);
SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CHECKTEMPLATEVERIFY);
return softforks;
}
} // anon namespace
Expand Down
6 changes: 5 additions & 1 deletion src/rpc/rawtransaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,8 @@ static RPCHelpMan decodescript()
case TxoutType::SCRIPTHASH:
case TxoutType::WITNESS_UNKNOWN:
case TxoutType::WITNESS_V1_TAPROOT:
// don't wrap CTV because P2SH CTV is a hash cycle
case TxoutType::TX_BARE_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH:
// Should not be wrapped
return false;
} // no default case, so the compiler can warn about missing cases
Expand Down Expand Up @@ -648,6 +650,8 @@ static RPCHelpMan decodescript()
case TxoutType::WITNESS_V0_KEYHASH:
case TxoutType::WITNESS_V0_SCRIPTHASH:
case TxoutType::WITNESS_V1_TAPROOT:
// don't wrap CTV because P2SH CTV is a hash cycle
case TxoutType::TX_BARE_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH:
// Should not be wrapped
return false;
} // no default case, so the compiler can warn about missing cases
Expand Down Expand Up @@ -1822,7 +1826,7 @@ static RPCHelpMan utxoupdatepsbt()
}

// Fill the inputs
const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
PSBTInput& input = psbtx.inputs.at(i);

Expand Down
2 changes: 1 addition & 1 deletion src/script/bitcoinconsensus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptP
// Regardless of the verification result, the tx did not error.
set_error(err, bitcoinconsensus_ERR_OK);

PrecomputedTransactionData txdata(tx);
PrecomputedTransactionData txdata(tx, nullptr);
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), &tx.vin[nIn].scriptWitness, flags, TransactionSignatureChecker(&tx, nIn, amount, txdata, MissingDataBehavior::FAIL), nullptr);
} catch (const std::exception&) {
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
Expand Down
Loading