13
13
#include < common/system.h>
14
14
#include < compat/compat.h>
15
15
#include < core_io.h>
16
+ #include < deploymentinfo.h>
17
+ #include < policy/policy.h>
18
+ #include < script/interpreter.h>
16
19
#include < streams.h>
20
+ #include < univalue.h>
21
+ #include < util/check.h>
17
22
#include < util/exception.h>
18
23
#include < util/strencodings.h>
19
24
#include < util/translation.h>
@@ -34,7 +39,15 @@ static void SetupBitcoinUtilArgs(ArgsManager &argsman)
34
39
35
40
argsman.AddArg (" -version" , " Print version and exit" , ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
36
41
42
+ // evalscript options
43
+ argsman.AddArg (" -sigversion" , " Specify a script sigversion (base, witness_v0, tapscript)." , ArgsManager::ALLOW_ANY, OptionsCategory::COMMAND_OPTIONS);
44
+ argsman.AddArg (" -script_flags" , " Specify SCRIPT_VERIFY flags." , ArgsManager::ALLOW_ANY, OptionsCategory::COMMAND_OPTIONS);
45
+ argsman.AddArg (" -tx" , " The tx (hex encoded)" , ArgsManager::ALLOW_ANY, OptionsCategory::COMMAND_OPTIONS);
46
+ argsman.AddArg (" -input" , " The index of the input being spent" , ArgsManager::ALLOW_ANY, OptionsCategory::COMMAND_OPTIONS);
47
+ argsman.AddArg (" -spent_output" , " The spent prevouts (hex encode TxOut, may be specified multiple times)." , ArgsManager::ALLOW_ANY, OptionsCategory::COMMAND_OPTIONS);
48
+
37
49
argsman.AddCommand (" grind" , " Perform proof of work on hex header string" );
50
+ argsman.AddCommand (" evalscript" , " Interpret a bitcoin script" , {" -sigversion" , " -script_flags" , " -tx" , " -input" , " -spent_output" });
38
51
39
52
SetupChainParamsBaseOptions (argsman);
40
53
}
@@ -146,6 +159,234 @@ static int Grind(const std::vector<std::string>& args, std::string& strPrint)
146
159
return EXIT_SUCCESS;
147
160
}
148
161
162
+ static UniValue stack2uv (const std::vector<std::vector<unsigned char >>& stack)
163
+ {
164
+ UniValue result{UniValue::VARR};
165
+ for (const auto & v : stack) {
166
+ result.push_back (HexStr (v));
167
+ }
168
+ return result;
169
+ }
170
+
171
+ static std::string sigver2str (SigVersion sigver)
172
+ {
173
+ switch (sigver) {
174
+ case SigVersion::BASE: return " base" ;
175
+ case SigVersion::WITNESS_V0: return " witness_v0" ;
176
+ case SigVersion::TAPROOT: return " taproot" ;
177
+ case SigVersion::TAPSCRIPT: return " tapscript" ;
178
+ }
179
+ return " unknown" ;
180
+ }
181
+
182
+ static uint32_t parse_verify_flags (const std::string& strFlags)
183
+ {
184
+ if (strFlags.empty () || strFlags == " MANDATORY" ) return MANDATORY_SCRIPT_VERIFY_FLAGS;
185
+ if (strFlags == " STANDARD" ) return STANDARD_SCRIPT_VERIFY_FLAGS;
186
+ if (strFlags == " NONE" ) return 0 ;
187
+
188
+ unsigned int flags = 0 ;
189
+ std::vector<std::string> words = util::SplitString (strFlags, ' ,' );
190
+
191
+ for (const std::string& word : words)
192
+ {
193
+ if (!g_verify_flag_names.count (word)) continue ;
194
+ flags |= g_verify_flag_names.at (word);
195
+ }
196
+ return flags;
197
+ }
198
+
199
+ // ! Public key to be used as internal key for dummy Taproot spends.
200
+ static const std::vector<unsigned char > NUMS_H{ParseHex (" 50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0" )};
201
+
202
+ namespace {
203
+ /* * Dummy signature checker which accepts all signatures. */
204
+ class DummySignatureChecker final : public BaseSignatureChecker
205
+ {
206
+ public:
207
+ DummySignatureChecker () = default ;
208
+ bool CheckECDSASignature (const std::vector<unsigned char >& sig, const std::vector<unsigned char >& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override { return sig.size () != 0 ; }
209
+ bool CheckSchnorrSignature (Span<const unsigned char > sig, Span<const unsigned char > pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const override { return sig.size () != 0 ; }
210
+ bool CheckLockTime (const CScriptNum& nLockTime) const override { return true ; }
211
+ bool CheckSequence (const CScriptNum& nSequence) const override { return true ; }
212
+ };
213
+ }
214
+
215
+ static int EvalScript (const ArgsManager& argsman, const std::vector<std::string>& args, std::string& strPrint)
216
+ {
217
+ UniValue result{UniValue::VOBJ};
218
+
219
+ uint32_t flags{0 };
220
+ PrecomputedTransactionData txdata;
221
+ ScriptExecutionData execdata;
222
+
223
+ std::unique_ptr<const CTransaction> txTo;
224
+ std::unique_ptr<BaseSignatureChecker> checker;
225
+
226
+ SigVersion sigversion = SigVersion::WITNESS_V0;
227
+
228
+ if (const auto verstr = argsman.GetArg (" -sigversion" ); verstr.has_value ()) {
229
+ if (*verstr == " base" ) {
230
+ sigversion = SigVersion::BASE;
231
+ } else if (*verstr == " witness_v0" ) {
232
+ sigversion = SigVersion::WITNESS_V0;
233
+ } else if (*verstr == " tapscript" ) {
234
+ sigversion = SigVersion::TAPSCRIPT;
235
+ } else {
236
+ strPrint = strprintf (" Unknown -sigversion=%s" , *verstr);
237
+ return EXIT_FAILURE;
238
+ }
239
+ }
240
+
241
+ const auto verifystr = argsman.GetArg (" -script_flags" );
242
+ flags = parse_verify_flags (verifystr.value_or (" " ));
243
+
244
+ CScript script{};
245
+ std::vector<std::vector<unsigned char > > stack{};
246
+ if (args.size () > 0 ) {
247
+ if (IsHex (args[0 ])) {
248
+ auto h = ParseHex (args[0 ]);
249
+ script = CScript (h.begin (), h.end ());
250
+ } else {
251
+ script = ParseScript (args[0 ]);
252
+ }
253
+
254
+ for (size_t i = 1 ; i < args.size (); ++i) {
255
+ if (args[i].size () == 0 ) {
256
+ stack.push_back ({});
257
+ } else if (IsHex (args[i])) {
258
+ stack.push_back (ParseHex (args[i]));
259
+ } else {
260
+ strPrint = strprintf (" Initial stack element not valid hex: %s" , args[i]);
261
+ return EXIT_FAILURE;
262
+ }
263
+ }
264
+ }
265
+
266
+ if (const auto txhex = argsman.GetArg (" -tx" ); txhex.has_value ()) {
267
+ const int input = argsman.GetIntArg (" -input" , 0 );
268
+ const auto spent_outputs_hex = argsman.GetArgs (" -spent_output" );
269
+
270
+ CMutableTransaction mut_tx;
271
+ if (!DecodeHexTx (mut_tx, *txhex)) {
272
+ strPrint = " Could not decode transaction from -tx argument" ;
273
+ return EXIT_FAILURE;
274
+ }
275
+ txTo = std::make_unique<CTransaction>(mut_tx);
276
+
277
+ if (spent_outputs_hex.size () != txTo->vin .size ()) {
278
+ strPrint = " When -tx is specified, must specify exactly one -spent_output for each input" ;
279
+ return EXIT_FAILURE;
280
+ }
281
+
282
+ std::vector<CTxOut> spent_outputs;
283
+ for (const auto & outhex : spent_outputs_hex) {
284
+ bool ok = false ;
285
+ if (IsHex (outhex)) {
286
+ CTxOut txout;
287
+ std::vector<unsigned char > out (ParseHex (outhex));
288
+ DataStream ss (out);
289
+ try {
290
+ ss >> txout;
291
+ if (ss.empty ()) {
292
+ spent_outputs.push_back (txout);
293
+ ok = true ;
294
+ }
295
+ } catch (const std::exception &) {
296
+ // fall through
297
+ }
298
+ }
299
+ if (!ok) {
300
+ strPrint = strprintf (" Could not parse -spent_output=%s" , outhex);
301
+ return EXIT_FAILURE;
302
+ }
303
+ }
304
+
305
+ const bool input_in_range = input >= 0 && static_cast <size_t >(input) < spent_outputs.size ();
306
+ CAmount amount = (input_in_range ? spent_outputs.at (input).nValue : 0 );
307
+ txdata.Init (*txTo, std::move (spent_outputs), /* force=*/ true );
308
+ checker = std::make_unique<TransactionSignatureChecker>(txTo.get (), input, amount, txdata, MissingDataBehavior::ASSERT_FAIL);
309
+
310
+ if (sigversion == SigVersion::TAPSCRIPT && input >= 0 && input_in_range) {
311
+ const CTxIn& txin = txTo->vin .at (input);
312
+ execdata.m_annex_present = false ;
313
+ if (txin.scriptWitness .stack .size () <= 1 ) {
314
+ // either key path spend or no witness, so nothing to do here
315
+ } else {
316
+ const auto & top = txin.scriptWitness .stack .back ();
317
+ if (top.size () >= 1 && top.at (0 ) == 0x50 ) {
318
+ execdata.m_annex_hash = (HashWriter{} << top).GetSHA256 ();
319
+ execdata.m_annex_present = true ;
320
+ }
321
+ }
322
+ execdata.m_annex_init = true ;
323
+ execdata.m_tapleaf_hash = ComputeTapleafHash (TAPROOT_LEAF_TAPSCRIPT & TAPROOT_LEAF_MASK, script);
324
+ execdata.m_tapleaf_hash_init = true ;
325
+ execdata.m_validation_weight_left = ::GetSerializeSize (stack) + ::GetSerializeSize (script) + VALIDATION_WEIGHT_OFFSET;
326
+ execdata.m_validation_weight_left_init = true ;
327
+ }
328
+ } else {
329
+ checker = std::make_unique<DummySignatureChecker>();
330
+ }
331
+
332
+ if (sigversion == SigVersion::TAPSCRIPT && !execdata.m_annex_init ) {
333
+ execdata.m_annex_present = false ;
334
+ execdata.m_annex_init = true ;
335
+ execdata.m_tapleaf_hash = uint256::ZERO;
336
+ execdata.m_tapleaf_hash_init = true ;
337
+ execdata.m_validation_weight_left = ::GetSerializeSize (stack) + ::GetSerializeSize (script) + VALIDATION_WEIGHT_OFFSET;
338
+ execdata.m_validation_weight_left_init = true ;
339
+ }
340
+
341
+ ScriptError serror{};
342
+
343
+ UniValue uv_flags{UniValue::VARR};
344
+ for (const auto & el : GetScriptFlagNames (flags)) {
345
+ uv_flags.push_back (el);
346
+ }
347
+ UniValue uv_script{UniValue::VOBJ};
348
+ ScriptToUniv (script, uv_script);
349
+ result.pushKV (" script" , uv_script);
350
+ result.pushKV (" sigversion" , sigver2str (sigversion));
351
+ result.pushKV (" script_flags" , uv_flags);
352
+
353
+ std::optional<bool > opsuccess_check;
354
+ if (sigversion == SigVersion::TAPSCRIPT) {
355
+ opsuccess_check = CheckTapscriptOpSuccess (script, flags, &serror);
356
+ }
357
+
358
+ bool success = (opsuccess_check.has_value () ? *opsuccess_check : EvalScript (stack, script, flags, *Assert (checker), sigversion, execdata, &serror));
359
+ if (opsuccess_check.has_value ()) {
360
+ result.pushKV (" opsuccess_found" , true );
361
+ } else if (success) {
362
+ if (stack.empty () || !CastToBool (stack.back ())) {
363
+ success = false ;
364
+ serror = SCRIPT_ERR_EVAL_FALSE;
365
+ } else if (stack.size () > 1 ) {
366
+ if (sigversion == SigVersion::WITNESS_V0 || sigversion == SigVersion::TAPSCRIPT) {
367
+ success = false ;
368
+ serror = SCRIPT_ERR_CLEANSTACK;
369
+ } else if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0 ) {
370
+ success = false ;
371
+ serror = SCRIPT_ERR_CLEANSTACK;
372
+ }
373
+ }
374
+ }
375
+
376
+ result.pushKV (" stack-after" , stack2uv (stack));
377
+
378
+ result.pushKV (" sigop-count" , (sigversion == SigVersion::TAPSCRIPT ? 0 : script.GetSigOpCount (true )));
379
+
380
+ result.pushKV (" success" , success);
381
+ if (!success) {
382
+ result.pushKV (" error" , ScriptErrorString (serror));
383
+ }
384
+
385
+ strPrint = result.write (2 );
386
+
387
+ return EXIT_SUCCESS;
388
+ }
389
+
149
390
MAIN_FUNCTION
150
391
{
151
392
ArgsManager& args = gArgs ;
@@ -175,6 +416,8 @@ MAIN_FUNCTION
175
416
try {
176
417
if (cmd->command == " grind" ) {
177
418
ret = Grind (cmd->args , strPrint);
419
+ } else if (cmd->command == " evalscript" ) {
420
+ ret = EvalScript (args, cmd->args , strPrint);
178
421
} else {
179
422
assert (false ); // unknown command should be caught earlier
180
423
}
0 commit comments