@@ -419,6 +419,19 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con
419
419
assert (false );
420
420
}
421
421
422
+ // ! Unspendable internal pubkey suggested in BIP-341.
423
+ const std::vector<unsigned char > BIP341_NUMS_POINT{
424
+ 0x50 , 0x92 , 0x9b , 0x74 , 0xc1 , 0xa0 , 0x49 , 0x54 , 0xb7 , 0x8b , 0x4b , 0x60 , 0x35 , 0xe9 , 0x7a , 0x5e ,
425
+ 0x07 , 0x8a , 0x5a , 0x0f , 0x28 , 0xec , 0x96 , 0xd5 , 0x47 , 0xbf , 0xee , 0x9a , 0xce , 0x80 , 0x3a , 0xc0 ,
426
+ };
427
+
428
+ // ! Flag to mark an OP_CHECKCONTRACVERIFY as referring to an input.
429
+ const int CCV_FLAG_CHECK_INPUT = -1 ;
430
+ // ! Flag to specify that an OP_CHECKCONTRACVERIFY which refers to an output does not check the output amount.
431
+ const int CCV_FLAG_IGNORE_OUTPUT_AMOUNT = 1 ;
432
+ // ! Flag to specify that an OP_CHECKCONTRACVERIFY referring to an output deducts the amount of its output from the current input amount for future calls.
433
+ const int CCV_FLAG_DEDUCT_OUTPUT_AMOUNT = 2 ;
434
+
422
435
bool EvalScript (std::vector<std::vector<unsigned char > >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
423
436
{
424
437
static const CScriptNum bnZero (0 );
@@ -1171,6 +1184,51 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
1171
1184
}
1172
1185
break ;
1173
1186
1187
+ case OP_CHECKCONTRACTVERIFY:
1188
+ {
1189
+ // OP_CHECKCONTRACTVERIFY is only available in Tapscript
1190
+ if (sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0) return set_error (serror, SCRIPT_ERR_BAD_OPCODE);
1191
+
1192
+ // we expect at least the flag to be on the stack
1193
+ if (stack.empty ())
1194
+ return set_error (serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
1195
+
1196
+ // initially, read only a single parameter at the top of stack
1197
+ int flags = CScriptNum (stacktop (-1 ), fRequireMinimal ).getint ();
1198
+ if (flags < -1 || flags > CCV_FLAG_DEDUCT_OUTPUT_AMOUNT) {
1199
+ // undefined values of the flags; keep OP_SUCCESS behavior
1200
+ // in order to enable future upgrades via soft-fork
1201
+ stack = { {1 } };
1202
+ return set_success (serror);
1203
+ }
1204
+
1205
+ // all currently defined versions require exactly 5 stack elements
1206
+
1207
+ // (data index pk taptree flags -- )
1208
+ if (stack.size () < 5 )
1209
+ return set_error (serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
1210
+
1211
+ valtype& data = stacktop (-5 );
1212
+ int index = CScriptNum (stacktop (-4 ), fRequireMinimal ).getint ();
1213
+ valtype& pk = stacktop (-3 );
1214
+ valtype& taptree = stacktop (-2 );
1215
+
1216
+ if (!pk.empty () && pk != std::vector<unsigned char >{0x81 } && pk.size () != 32 ) {
1217
+ return set_error (serror, SCRIPT_ERR_CHECKCONTRACTVERIFY_WRONG_ARGS);
1218
+ }
1219
+
1220
+ if (!checker.CheckContract (flags, index , pk, data, taptree, execdata, serror)) {
1221
+ return false ; // serror is set
1222
+ }
1223
+
1224
+ popstack (stack);
1225
+ popstack (stack);
1226
+ popstack (stack);
1227
+ popstack (stack);
1228
+ popstack (stack);
1229
+ }
1230
+ break ;
1231
+
1174
1232
case OP_CHECKMULTISIG:
1175
1233
case OP_CHECKMULTISIGVERIFY:
1176
1234
{
@@ -1965,6 +2023,94 @@ bool GenericTransactionSignatureChecker<T>::CheckDefaultCheckTemplateVerifyHash(
1965
2023
return HandleMissingData (m_mdb);
1966
2024
}
1967
2025
}
2026
+
2027
+ template <class T >
2028
+ bool GenericTransactionSignatureChecker<T>::CheckContract(int flags, int index, const std::vector<unsigned char >& pubkey, const std::vector<unsigned char >& data, const std::vector<unsigned char >& taptree, ScriptExecutionData& ScriptExecutionData, ScriptError* serror) const
2029
+ {
2030
+ assert (ScriptExecutionData.m_internal_key .has_value ());
2031
+
2032
+ if (!(txdata->m_bip341_taproot_ready && txdata->m_spent_outputs_ready )) {
2033
+ return HandleMissingData (m_mdb);
2034
+ }
2035
+
2036
+ bool use_current_taptree = taptree.size () == 1 && taptree.data ()[0 ] == 0x81 ;
2037
+ bool use_current_pubkey = pubkey.size () == 1 && pubkey.data ()[0 ] == 0x81 ;
2038
+
2039
+ uint256 merkle_tree;
2040
+ const uint256 *merkle_tree_ptr = nullptr ;
2041
+ if (taptree.empty ()) {
2042
+ // no taptweak, leave nullptr
2043
+ } else if (use_current_taptree) {
2044
+ merkle_tree_ptr = &ScriptExecutionData.m_taproot_merkle_root ;
2045
+ } else if (taptree.size () == 32 ) {
2046
+ merkle_tree = uint256 (taptree);
2047
+ merkle_tree_ptr = &merkle_tree;
2048
+ } else {
2049
+ return set_error (serror, SCRIPT_ERR_CHECKCONTRACTVERIFY_WRONG_ARGS);
2050
+ }
2051
+
2052
+ XOnlyPubKey initialXOnlyKey;
2053
+ if (use_current_pubkey) {
2054
+ initialXOnlyKey = ScriptExecutionData.m_internal_key .value ();
2055
+ } else {
2056
+ const std::vector<unsigned char > initial_pubkey (pubkey.empty () ? BIP341_NUMS_POINT : pubkey);
2057
+ initialXOnlyKey = XOnlyPubKey{Span<const unsigned char >{initial_pubkey.data (), initial_pubkey.data () + 32 }};
2058
+ }
2059
+
2060
+ if (index == -1 ) {
2061
+ index = nIn;
2062
+ }
2063
+
2064
+ auto indexLimit = (flags == CCV_FLAG_CHECK_INPUT ? txTo->vin .size () : txTo->vout .size ());
2065
+ if (index < 0 || index >= static_cast <int >(indexLimit)) {
2066
+ return set_error (serror, SCRIPT_ERR_CHECKCONTRACTVERIFY_OUT_OF_BOUNDS);
2067
+ }
2068
+
2069
+ CScript scriptPubKey = (flags == CCV_FLAG_CHECK_INPUT) ? txdata->m_spent_outputs [index ].scriptPubKey : txTo->vout .at (index ).scriptPubKey ;
2070
+
2071
+ if (scriptPubKey.size () != 1 + 1 + 32 || scriptPubKey[0 ] != OP_1 || scriptPubKey[1 ] != 32 ) {
2072
+ return set_error (serror, SCRIPT_ERR_CHECKCONTRACTVERIFY_WRONG_ARGS);
2073
+ }
2074
+
2075
+ const XOnlyPubKey finalXOnlyKey{Span<const unsigned char >{scriptPubKey.data () + 2 , scriptPubKey.data () + 34 }};
2076
+
2077
+ if (!finalXOnlyKey.CheckDoubleTweak (initialXOnlyKey, data, merkle_tree_ptr)) {
2078
+ return set_error (serror, SCRIPT_ERR_CHECKCONTRACTVERIFY_MISMATCH);
2079
+ }
2080
+
2081
+
2082
+ if (!ScriptExecutionData.m_ccv_amount_init ) {
2083
+ ScriptExecutionData.m_ccv_amount = amount;
2084
+ ScriptExecutionData.m_ccv_amount_init = true ;
2085
+ }
2086
+
2087
+ switch (flags) {
2088
+ case 0 :
2089
+ // default behavior for outputs: add amount for the cumulative deferred check
2090
+ ScriptExecutionData.AddDeferredAggregateOutputAmountCheck (index , ScriptExecutionData.m_ccv_amount );
2091
+ break ;
2092
+ case CCV_FLAG_IGNORE_OUTPUT_AMOUNT:
2093
+ // amount checking is disabled
2094
+ break ;
2095
+ case CCV_FLAG_DEDUCT_OUTPUT_AMOUNT:
2096
+ // subtract amount from input
2097
+ if (txTo->vout [index ].nValue > ScriptExecutionData.m_ccv_amount ) {
2098
+ return set_error (serror, SCRIPT_ERR_CHECKCONTRACTVERIFY_WRONG_AMOUNT);
2099
+ }
2100
+ ScriptExecutionData.m_ccv_amount -= txTo->vout [index ].nValue ;
2101
+
2102
+ // This output must not be used by another output check,
2103
+ // unless it is with the CCV_FLAG_IGNORE_OUTPUT_AMOUNT flag
2104
+ ScriptExecutionData.AddDeferredExclusiveOutputAmountCheck (index );
2105
+
2106
+ break ;
2107
+ default :
2108
+ break ;
2109
+ }
2110
+
2111
+ return true ;
2112
+ }
2113
+
1968
2114
// explicit instantiation
1969
2115
template class GenericTransactionSignatureChecker <CTransaction>;
1970
2116
template class GenericTransactionSignatureChecker <CMutableTransaction>;
@@ -2060,7 +2206,7 @@ uint256 ComputeTaprootMerkleRoot(Span<const unsigned char> control, const uint25
2060
2206
return k;
2061
2207
}
2062
2208
2063
- static bool VerifyTaprootCommitment (const std::vector<unsigned char >& control, const std::vector<unsigned char >& program, const uint256& tapleaf_hash, std::optional<XOnlyPubKey>& internal_key)
2209
+ static bool VerifyTaprootCommitment (const std::vector<unsigned char >& control, const std::vector<unsigned char >& program, const uint256& tapleaf_hash, uint256& merkle_root, std::optional<XOnlyPubKey>& internal_key)
2064
2210
{
2065
2211
assert (control.size () >= TAPROOT_CONTROL_BASE_SIZE);
2066
2212
assert (program.size () >= uint256::size ());
@@ -2070,7 +2216,7 @@ static bool VerifyTaprootCommitment(const std::vector<unsigned char>& control, c
2070
2216
// ! The output pubkey (taken from the scriptPubKey).
2071
2217
const XOnlyPubKey q{program};
2072
2218
// Compute the Merkle root from the leaf and the provided path.
2073
- const uint256 merkle_root = ComputeTaprootMerkleRoot (control, tapleaf_hash);
2219
+ merkle_root = ComputeTaprootMerkleRoot (control, tapleaf_hash);
2074
2220
// Verify that the output pubkey matches the tweaked internal pubkey, after correcting for parity.
2075
2221
return q.CheckTapTweak (p, merkle_root, control[0 ] & 1 );
2076
2222
}
@@ -2133,10 +2279,12 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
2133
2279
return set_error (serror, SCRIPT_ERR_TAPROOT_WRONG_CONTROL_SIZE);
2134
2280
}
2135
2281
execdata.m_tapleaf_hash = ComputeTapleafHash (control[0 ] & TAPROOT_LEAF_MASK, script);
2136
- if (!VerifyTaprootCommitment (control, program, execdata.m_tapleaf_hash , execdata.m_internal_key )) {
2282
+ if (!VerifyTaprootCommitment (control, program, execdata.m_tapleaf_hash , execdata.m_taproot_merkle_root , execdata. m_internal_key )) {
2137
2283
return set_error (serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
2138
2284
}
2139
2285
execdata.m_tapleaf_hash_init = true ;
2286
+ execdata.m_taproot_merkle_root_init = true ;
2287
+
2140
2288
if ((control[0 ] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT) {
2141
2289
// Tapscript (leaf version 0xc0)
2142
2290
exec_script = CScript (script.begin (), script.end ());
0 commit comments