Line data Source code
1 : // Copyright (c) 2009-2020 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #if defined(HAVE_CONFIG_H)
6 : #include <config/bitcoin-config.h>
7 : #endif
8 :
9 : #include <clientversion.h>
10 : #include <coins.h>
11 : #include <consensus/consensus.h>
12 : #include <core_io.h>
13 : #include <key_io.h>
14 : #include <policy/rbf.h>
15 : #include <primitives/transaction.h>
16 : #include <script/script.h>
17 : #include <script/sign.h>
18 : #include <script/signingprovider.h>
19 : #include <univalue.h>
20 : #include <util/moneystr.h>
21 : #include <util/rbf.h>
22 : #include <util/strencodings.h>
23 : #include <util/string.h>
24 : #include <util/system.h>
25 : #include <util/translation.h>
26 :
27 : #include <functional>
28 : #include <memory>
29 : #include <stdio.h>
30 :
31 : #include <boost/algorithm/string.hpp>
32 :
33 : static bool fCreateBlank;
34 81 : static std::map<std::string,UniValue> registers;
35 : static const int CONTINUE_EXECUTION=-1;
36 :
37 81 : const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
38 :
39 81 : static void SetupBitcoinTxArgs(ArgsManager &argsman)
40 : {
41 81 : SetupHelpOptions(argsman);
42 :
43 81 : argsman.AddArg("-create", "Create new, empty TX.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
44 81 : argsman.AddArg("-json", "Select JSON output", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
45 81 : argsman.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
46 81 : SetupChainParamsBaseOptions(argsman);
47 :
48 81 : argsman.AddArg("delin=N", "Delete input N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
49 81 : argsman.AddArg("delout=N", "Delete output N from TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
50 81 : argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
51 81 : argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
52 81 : argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
53 81 : argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
54 81 : argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
55 81 : argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. "
56 : "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
57 81 : "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
58 81 : argsman.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", "Add pay-to-pubkey output to TX. "
59 : "Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. "
60 81 : "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
61 81 : argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. "
62 : "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
63 81 : "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
64 81 : argsman.AddArg("replaceable(=N)", "Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
65 81 : argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. "
66 : "This command requires JSON registers:"
67 : "prevtxs=JSON object, "
68 : "privatekeys=JSON object. "
69 81 : "See signrawtransactionwithkey docs for format of sighash flags, JSON objects.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
70 :
71 81 : argsman.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS);
72 81 : argsman.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", ArgsManager::ALLOW_ANY, OptionsCategory::REGISTER_COMMANDS);
73 81 : }
74 :
75 : //
76 : // This function returns either one of EXIT_ codes when it's expected to stop the process or
77 : // CONTINUE_EXECUTION when it's expected to continue further.
78 : //
79 81 : static int AppInitRawTx(int argc, char* argv[])
80 : {
81 : //
82 : // Parameters
83 : //
84 81 : SetupBitcoinTxArgs(gArgs);
85 81 : std::string error;
86 81 : if (!gArgs.ParseParameters(argc, argv, error)) {
87 0 : tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
88 0 : return EXIT_FAILURE;
89 : }
90 :
91 : // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause)
92 : try {
93 81 : SelectParams(gArgs.GetChainName());
94 0 : } catch (const std::exception& e) {
95 0 : tfm::format(std::cerr, "Error: %s\n", e.what());
96 : return EXIT_FAILURE;
97 0 : }
98 :
99 81 : fCreateBlank = gArgs.GetBoolArg("-create", false);
100 :
101 81 : if (argc < 2 || HelpRequested(gArgs)) {
102 : // First part of help message is specific to this utility
103 0 : std::string strUsage = PACKAGE_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n\n" +
104 0 : "Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction\n" +
105 0 : "or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction\n" +
106 : "\n";
107 0 : strUsage += gArgs.GetHelpMessage();
108 :
109 0 : tfm::format(std::cout, "%s", strUsage);
110 :
111 0 : if (argc < 2) {
112 0 : tfm::format(std::cerr, "Error: too few parameters\n");
113 0 : return EXIT_FAILURE;
114 : }
115 0 : return EXIT_SUCCESS;
116 0 : }
117 81 : return CONTINUE_EXECUTION;
118 81 : }
119 :
120 14 : static void RegisterSetJson(const std::string& key, const std::string& rawJson)
121 : {
122 14 : UniValue val;
123 14 : if (!val.read(rawJson)) {
124 0 : std::string strErr = "Cannot parse JSON for key " + key;
125 0 : throw std::runtime_error(strErr);
126 0 : }
127 :
128 14 : registers[key] = val;
129 14 : }
130 :
131 14 : static void RegisterSet(const std::string& strInput)
132 : {
133 : // separate NAME:VALUE in string
134 14 : size_t pos = strInput.find(':');
135 28 : if ((pos == std::string::npos) ||
136 14 : (pos == 0) ||
137 14 : (pos == (strInput.size() - 1)))
138 0 : throw std::runtime_error("Register input requires NAME:VALUE");
139 :
140 14 : std::string key = strInput.substr(0, pos);
141 14 : std::string valStr = strInput.substr(pos + 1, std::string::npos);
142 :
143 14 : RegisterSetJson(key, valStr);
144 14 : }
145 :
146 0 : static void RegisterLoad(const std::string& strInput)
147 : {
148 : // separate NAME:FILENAME in string
149 0 : size_t pos = strInput.find(':');
150 0 : if ((pos == std::string::npos) ||
151 0 : (pos == 0) ||
152 0 : (pos == (strInput.size() - 1)))
153 0 : throw std::runtime_error("Register load requires NAME:FILENAME");
154 :
155 0 : std::string key = strInput.substr(0, pos);
156 0 : std::string filename = strInput.substr(pos + 1, std::string::npos);
157 :
158 0 : FILE *f = fopen(filename.c_str(), "r");
159 0 : if (!f) {
160 0 : std::string strErr = "Cannot open file " + filename;
161 0 : throw std::runtime_error(strErr);
162 0 : }
163 :
164 : // load file chunks into one big buffer
165 0 : std::string valStr;
166 0 : while ((!feof(f)) && (!ferror(f))) {
167 0 : char buf[4096];
168 0 : int bread = fread(buf, 1, sizeof(buf), f);
169 0 : if (bread <= 0)
170 0 : break;
171 :
172 0 : valStr.insert(valStr.size(), buf, bread);
173 0 : }
174 :
175 0 : int error = ferror(f);
176 0 : fclose(f);
177 :
178 0 : if (error) {
179 0 : std::string strErr = "Error reading file " + filename;
180 0 : throw std::runtime_error(strErr);
181 0 : }
182 :
183 : // evaluate as JSON buffer register
184 0 : RegisterSetJson(key, valStr);
185 0 : }
186 :
187 50 : static CAmount ExtractAndValidateValue(const std::string& strValue)
188 : {
189 50 : CAmount value;
190 50 : if (!ParseMoney(strValue, value))
191 0 : throw std::runtime_error("invalid TX output value");
192 100 : return value;
193 50 : }
194 :
195 28 : static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
196 : {
197 28 : int64_t newVersion;
198 28 : if (!ParseInt64(cmdVal, &newVersion) || newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
199 1 : throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");
200 :
201 27 : tx.nVersion = (int) newVersion;
202 28 : }
203 :
204 3 : static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
205 : {
206 3 : int64_t newLocktime;
207 3 : if (!ParseInt64(cmdVal, &newLocktime) || newLocktime < 0LL || newLocktime > 0xffffffffLL)
208 1 : throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'");
209 :
210 2 : tx.nLockTime = (unsigned int) newLocktime;
211 3 : }
212 :
213 1 : static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
214 : {
215 : // parse requested index
216 1 : int64_t inIdx;
217 1 : if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
218 1 : throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
219 : }
220 :
221 : // set the nSequence to MAX_INT - 2 (= RBF opt in flag)
222 : int cnt = 0;
223 0 : for (CTxIn& txin : tx.vin) {
224 0 : if (strInIdx == "" || cnt == inIdx) {
225 0 : if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {
226 0 : txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
227 0 : }
228 : }
229 0 : ++cnt;
230 : }
231 1 : }
232 :
233 28 : static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
234 : {
235 28 : std::vector<std::string> vStrInputParts;
236 28 : boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
237 :
238 : // separate TXID:VOUT in string
239 28 : if (vStrInputParts.size()<2)
240 0 : throw std::runtime_error("TX input missing separator");
241 :
242 : // extract and validate TXID
243 28 : uint256 txid;
244 28 : if (!ParseHashStr(vStrInputParts[0], txid)) {
245 3 : throw std::runtime_error("invalid TX input txid");
246 : }
247 :
248 : static const unsigned int minTxOutSz = 9;
249 : static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
250 :
251 : // extract and validate vout
252 25 : const std::string& strVout = vStrInputParts[1];
253 25 : int64_t vout;
254 25 : if (!ParseInt64(strVout, &vout) || vout < 0 || vout > static_cast<int64_t>(maxVout))
255 1 : throw std::runtime_error("invalid TX input vout '" + strVout + "'");
256 :
257 : // extract the optional sequence number
258 : uint32_t nSequenceIn = CTxIn::SEQUENCE_FINAL;
259 24 : if (vStrInputParts.size() > 2)
260 4 : nSequenceIn = std::stoul(vStrInputParts[2]);
261 :
262 : // append to transaction input list
263 24 : CTxIn txin(txid, vout, CScript(), nSequenceIn);
264 24 : tx.vin.push_back(txin);
265 28 : }
266 :
267 15 : static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
268 : {
269 : // Separate into VALUE:ADDRESS
270 15 : std::vector<std::string> vStrInputParts;
271 15 : boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
272 :
273 15 : if (vStrInputParts.size() != 2)
274 2 : throw std::runtime_error("TX output missing or too many separators");
275 :
276 : // Extract and validate VALUE
277 13 : CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
278 :
279 : // extract and validate ADDRESS
280 13 : std::string strAddr = vStrInputParts[1];
281 13 : CTxDestination destination = DecodeDestination(strAddr);
282 13 : if (!IsValidDestination(destination)) {
283 0 : throw std::runtime_error("invalid TX output address");
284 : }
285 13 : CScript scriptPubKey = GetScriptForDestination(destination);
286 :
287 : // construct TxOut, append to transaction output list
288 13 : CTxOut txout(value, scriptPubKey);
289 13 : tx.vout.push_back(txout);
290 15 : }
291 :
292 9 : static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput)
293 : {
294 : // Separate into VALUE:PUBKEY[:FLAGS]
295 9 : std::vector<std::string> vStrInputParts;
296 9 : boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
297 :
298 9 : if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
299 2 : throw std::runtime_error("TX output missing or too many separators");
300 :
301 : // Extract and validate VALUE
302 7 : CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
303 :
304 : // Extract and validate PUBKEY
305 7 : CPubKey pubkey(ParseHex(vStrInputParts[1]));
306 7 : if (!pubkey.IsFullyValid())
307 0 : throw std::runtime_error("invalid TX output pubkey");
308 7 : CScript scriptPubKey = GetScriptForRawPubKey(pubkey);
309 :
310 : // Extract and validate FLAGS
311 : bool bSegWit = false;
312 : bool bScriptHash = false;
313 7 : if (vStrInputParts.size() == 3) {
314 5 : std::string flags = vStrInputParts[2];
315 5 : bSegWit = (flags.find('W') != std::string::npos);
316 5 : bScriptHash = (flags.find('S') != std::string::npos);
317 5 : }
318 :
319 7 : if (bSegWit) {
320 5 : if (!pubkey.IsCompressed()) {
321 1 : throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
322 : }
323 : // Build a P2WPKH script
324 4 : scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(pubkey));
325 4 : }
326 6 : if (bScriptHash) {
327 : // Get the ID for the script, and then construct a P2SH destination for it.
328 2 : scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
329 2 : }
330 :
331 : // construct TxOut, append to transaction output list
332 6 : CTxOut txout(value, scriptPubKey);
333 6 : tx.vout.push_back(txout);
334 9 : }
335 :
336 10 : static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput)
337 : {
338 : // Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
339 10 : std::vector<std::string> vStrInputParts;
340 10 : boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
341 :
342 : // Check that there are enough parameters
343 10 : if (vStrInputParts.size()<3)
344 0 : throw std::runtime_error("Not enough multisig parameters");
345 :
346 : // Extract and validate VALUE
347 10 : CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
348 :
349 : // Extract REQUIRED
350 10 : uint32_t required = stoul(vStrInputParts[1]);
351 :
352 : // Extract NUMKEYS
353 10 : uint32_t numkeys = stoul(vStrInputParts[2]);
354 :
355 : // Validate there are the correct number of pubkeys
356 10 : if (vStrInputParts.size() < numkeys + 3)
357 0 : throw std::runtime_error("incorrect number of multisig pubkeys");
358 :
359 10 : if (required < 1 || required > MAX_PUBKEYS_PER_MULTISIG || numkeys < 1 || numkeys > MAX_PUBKEYS_PER_MULTISIG || numkeys < required)
360 0 : throw std::runtime_error("multisig parameter mismatch. Required " \
361 0 : + ToString(required) + " of " + ToString(numkeys) + "signatures.");
362 :
363 : // extract and validate PUBKEYs
364 10 : std::vector<CPubKey> pubkeys;
365 40 : for(int pos = 1; pos <= int(numkeys); pos++) {
366 30 : CPubKey pubkey(ParseHex(vStrInputParts[pos + 2]));
367 30 : if (!pubkey.IsFullyValid())
368 0 : throw std::runtime_error("invalid TX output pubkey");
369 30 : pubkeys.push_back(pubkey);
370 30 : }
371 :
372 : // Extract FLAGS
373 : bool bSegWit = false;
374 : bool bScriptHash = false;
375 10 : if (vStrInputParts.size() == numkeys + 4) {
376 8 : std::string flags = vStrInputParts.back();
377 8 : bSegWit = (flags.find('W') != std::string::npos);
378 8 : bScriptHash = (flags.find('S') != std::string::npos);
379 8 : }
380 2 : else if (vStrInputParts.size() > numkeys + 4) {
381 : // Validate that there were no more parameters passed
382 0 : throw std::runtime_error("Too many parameters");
383 : }
384 :
385 10 : CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
386 :
387 10 : if (bSegWit) {
388 20 : for (const CPubKey& pubkey : pubkeys) {
389 15 : if (!pubkey.IsCompressed()) {
390 1 : throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
391 : }
392 : }
393 : // Build a P2WSH with the multisig script
394 4 : scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey));
395 4 : }
396 9 : if (bScriptHash) {
397 5 : if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
398 0 : throw std::runtime_error(strprintf(
399 0 : "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
400 : }
401 : // Get the ID for the script, and then construct a P2SH destination for it.
402 5 : scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
403 5 : }
404 :
405 : // construct TxOut, append to transaction output list
406 9 : CTxOut txout(value, scriptPubKey);
407 9 : tx.vout.push_back(txout);
408 11 : }
409 :
410 6 : static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput)
411 : {
412 6 : CAmount value = 0;
413 :
414 : // separate [VALUE:]DATA in string
415 6 : size_t pos = strInput.find(':');
416 :
417 6 : if (pos==0)
418 0 : throw std::runtime_error("TX output value not specified");
419 :
420 6 : if (pos != std::string::npos) {
421 : // Extract and validate VALUE
422 3 : value = ExtractAndValidateValue(strInput.substr(0, pos));
423 3 : }
424 :
425 : // extract and validate DATA
426 6 : std::string strData = strInput.substr(pos + 1, std::string::npos);
427 :
428 6 : if (!IsHex(strData))
429 2 : throw std::runtime_error("invalid TX output data");
430 :
431 4 : std::vector<unsigned char> data = ParseHex(strData);
432 :
433 4 : CTxOut txout(value, CScript() << OP_RETURN << data);
434 4 : tx.vout.push_back(txout);
435 6 : }
436 :
437 17 : static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
438 : {
439 : // separate VALUE:SCRIPT[:FLAGS]
440 17 : std::vector<std::string> vStrInputParts;
441 17 : boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
442 17 : if (vStrInputParts.size() < 2)
443 0 : throw std::runtime_error("TX output missing separator");
444 :
445 : // Extract and validate VALUE
446 17 : CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
447 :
448 : // extract and validate script
449 17 : std::string strScript = vStrInputParts[1];
450 17 : CScript scriptPubKey = ParseScript(strScript);
451 :
452 : // Extract FLAGS
453 : bool bSegWit = false;
454 : bool bScriptHash = false;
455 12 : if (vStrInputParts.size() == 3) {
456 6 : std::string flags = vStrInputParts.back();
457 6 : bSegWit = (flags.find('W') != std::string::npos);
458 6 : bScriptHash = (flags.find('S') != std::string::npos);
459 6 : }
460 :
461 12 : if (scriptPubKey.size() > MAX_SCRIPT_SIZE) {
462 0 : throw std::runtime_error(strprintf(
463 0 : "script exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_SIZE));
464 : }
465 :
466 12 : if (bSegWit) {
467 4 : scriptPubKey = GetScriptForDestination(WitnessV0ScriptHash(scriptPubKey));
468 4 : }
469 12 : if (bScriptHash) {
470 4 : if (scriptPubKey.size() > MAX_SCRIPT_ELEMENT_SIZE) {
471 0 : throw std::runtime_error(strprintf(
472 0 : "redeemScript exceeds size limit: %d > %d", scriptPubKey.size(), MAX_SCRIPT_ELEMENT_SIZE));
473 : }
474 4 : scriptPubKey = GetScriptForDestination(ScriptHash(scriptPubKey));
475 4 : }
476 :
477 : // construct TxOut, append to transaction output list
478 12 : CTxOut txout(value, scriptPubKey);
479 12 : tx.vout.push_back(txout);
480 17 : }
481 :
482 4 : static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
483 : {
484 : // parse requested deletion index
485 4 : int64_t inIdx;
486 4 : if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
487 2 : throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
488 : }
489 :
490 : // delete input from transaction
491 2 : tx.vin.erase(tx.vin.begin() + inIdx);
492 4 : }
493 :
494 4 : static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
495 : {
496 : // parse requested deletion index
497 4 : int64_t outIdx;
498 4 : if (!ParseInt64(strOutIdx, &outIdx) || outIdx < 0 || outIdx >= static_cast<int64_t>(tx.vout.size())) {
499 2 : throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'");
500 : }
501 :
502 : // delete output from transaction
503 2 : tx.vout.erase(tx.vout.begin() + outIdx);
504 4 : }
505 :
506 : static const unsigned int N_SIGHASH_OPTS = 6;
507 : static const struct {
508 : const char *flagStr;
509 : int flags;
510 : } sighashOptions[N_SIGHASH_OPTS] = {
511 : {"ALL", SIGHASH_ALL},
512 : {"NONE", SIGHASH_NONE},
513 : {"SINGLE", SIGHASH_SINGLE},
514 : {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
515 : {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
516 : {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
517 : };
518 :
519 7 : static bool findSighashFlags(int& flags, const std::string& flagStr)
520 : {
521 7 : flags = 0;
522 :
523 7 : for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
524 7 : if (flagStr == sighashOptions[i].flagStr) {
525 7 : flags = sighashOptions[i].flags;
526 7 : return true;
527 : }
528 : }
529 :
530 0 : return false;
531 7 : }
532 :
533 0 : static CAmount AmountFromValue(const UniValue& value)
534 : {
535 0 : if (!value.isNum() && !value.isStr())
536 0 : throw std::runtime_error("Amount is not a number or string");
537 0 : CAmount amount;
538 0 : if (!ParseFixedPoint(value.getValStr(), 8, &amount))
539 0 : throw std::runtime_error("Invalid amount");
540 0 : if (!MoneyRange(amount))
541 0 : throw std::runtime_error("Amount out of range");
542 0 : return amount;
543 0 : }
544 :
545 7 : static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
546 : {
547 7 : int nHashType = SIGHASH_ALL;
548 :
549 7 : if (flagStr.size() > 0)
550 7 : if (!findSighashFlags(nHashType, flagStr))
551 0 : throw std::runtime_error("unknown sighash flag/sign option");
552 :
553 : // mergedTx will end up with all the signatures; it
554 : // starts as a clone of the raw tx:
555 7 : CMutableTransaction mergedTx{tx};
556 7 : const CMutableTransaction txv{tx};
557 7 : CCoinsView viewDummy;
558 7 : CCoinsViewCache view(&viewDummy);
559 :
560 7 : if (!registers.count("privatekeys"))
561 0 : throw std::runtime_error("privatekeys register variable must be set.");
562 7 : FillableSigningProvider tempKeystore;
563 7 : UniValue keysObj = registers["privatekeys"];
564 :
565 14 : for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
566 7 : if (!keysObj[kidx].isStr())
567 0 : throw std::runtime_error("privatekey not a std::string");
568 7 : CKey key = DecodeSecret(keysObj[kidx].getValStr());
569 7 : if (!key.IsValid()) {
570 0 : throw std::runtime_error("privatekey not valid");
571 : }
572 7 : tempKeystore.AddKey(key);
573 7 : }
574 :
575 : // Add previous txouts given in the RPC call:
576 7 : if (!registers.count("prevtxs"))
577 0 : throw std::runtime_error("prevtxs register variable must be set.");
578 7 : UniValue prevtxsObj = registers["prevtxs"];
579 : {
580 14 : for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {
581 7 : UniValue prevOut = prevtxsObj[previdx];
582 7 : if (!prevOut.isObject())
583 0 : throw std::runtime_error("expected prevtxs internal object");
584 :
585 21 : std::map<std::string, UniValue::VType> types = {
586 7 : {"txid", UniValue::VSTR},
587 7 : {"vout", UniValue::VNUM},
588 7 : {"scriptPubKey", UniValue::VSTR},
589 : };
590 7 : if (!prevOut.checkObject(types))
591 1 : throw std::runtime_error("prevtxs internal object typecheck fail");
592 :
593 6 : uint256 txid;
594 6 : if (!ParseHashStr(prevOut["txid"].get_str(), txid)) {
595 3 : throw std::runtime_error("txid must be hexadecimal string (not '" + prevOut["txid"].get_str() + "')");
596 : }
597 :
598 3 : const int nOut = prevOut["vout"].get_int();
599 3 : if (nOut < 0)
600 0 : throw std::runtime_error("vout must be positive");
601 :
602 3 : COutPoint out(txid, nOut);
603 3 : std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
604 3 : CScript scriptPubKey(pkData.begin(), pkData.end());
605 :
606 : {
607 3 : const Coin& coin = view.AccessCoin(out);
608 3 : if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
609 0 : std::string err("Previous output scriptPubKey mismatch:\n");
610 0 : err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
611 0 : ScriptToAsmStr(scriptPubKey);
612 0 : throw std::runtime_error(err);
613 0 : }
614 3 : Coin newcoin;
615 3 : newcoin.out.scriptPubKey = scriptPubKey;
616 3 : newcoin.out.nValue = 0;
617 3 : if (prevOut.exists("amount")) {
618 0 : newcoin.out.nValue = AmountFromValue(prevOut["amount"]);
619 0 : }
620 3 : newcoin.nHeight = 1;
621 3 : view.AddCoin(out, std::move(newcoin), true);
622 3 : }
623 :
624 : // if redeemScript given and private keys given,
625 : // add redeemScript to the tempKeystore so it can be signed:
626 3 : if ((scriptPubKey.IsPayToScriptHash() || scriptPubKey.IsPayToWitnessScriptHash()) &&
627 0 : prevOut.exists("redeemScript")) {
628 0 : UniValue v = prevOut["redeemScript"];
629 0 : std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
630 0 : CScript redeemScript(rsData.begin(), rsData.end());
631 0 : tempKeystore.AddCScript(redeemScript);
632 0 : }
633 7 : }
634 : }
635 :
636 : const FillableSigningProvider& keystore = tempKeystore;
637 :
638 3 : bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
639 :
640 : // Sign what we can:
641 6 : for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
642 3 : CTxIn& txin = mergedTx.vin[i];
643 3 : const Coin& coin = view.AccessCoin(txin.prevout);
644 3 : if (coin.IsSpent()) {
645 0 : continue;
646 : }
647 3 : const CScript& prevPubKey = coin.out.scriptPubKey;
648 3 : const CAmount& amount = coin.out.nValue;
649 :
650 3 : SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out);
651 : // Only sign SIGHASH_SINGLE if there's a corresponding output:
652 3 : if (!fHashSingle || (i < mergedTx.vout.size()))
653 3 : ProduceSignature(keystore, MutableTransactionSignatureCreator(&mergedTx, i, amount, nHashType), prevPubKey, sigdata);
654 :
655 3 : UpdateInput(txin, sigdata);
656 3 : }
657 :
658 3 : tx = mergedTx;
659 11 : }
660 :
661 : class Secp256k1Init
662 : {
663 : ECCVerifyHandle globalVerifyHandle;
664 :
665 : public:
666 52 : Secp256k1Init() {
667 26 : ECC_Start();
668 52 : }
669 52 : ~Secp256k1Init() {
670 26 : ECC_Stop();
671 52 : }
672 : };
673 :
674 146 : static void MutateTx(CMutableTransaction& tx, const std::string& command,
675 : const std::string& commandVal)
676 : {
677 146 : std::unique_ptr<Secp256k1Init> ecc;
678 :
679 146 : if (command == "nversion")
680 28 : MutateTxVersion(tx, commandVal);
681 118 : else if (command == "locktime")
682 3 : MutateTxLocktime(tx, commandVal);
683 115 : else if (command == "replaceable") {
684 1 : MutateTxRBFOptIn(tx, commandVal);
685 : }
686 :
687 114 : else if (command == "delin")
688 4 : MutateTxDelInput(tx, commandVal);
689 110 : else if (command == "in")
690 28 : MutateTxAddInput(tx, commandVal);
691 :
692 82 : else if (command == "delout")
693 4 : MutateTxDelOutput(tx, commandVal);
694 78 : else if (command == "outaddr")
695 15 : MutateTxAddOutAddr(tx, commandVal);
696 63 : else if (command == "outpubkey") {
697 9 : ecc.reset(new Secp256k1Init());
698 9 : MutateTxAddOutPubKey(tx, commandVal);
699 54 : } else if (command == "outmultisig") {
700 10 : ecc.reset(new Secp256k1Init());
701 10 : MutateTxAddOutMultiSig(tx, commandVal);
702 44 : } else if (command == "outscript")
703 17 : MutateTxAddOutScript(tx, commandVal);
704 27 : else if (command == "outdata")
705 6 : MutateTxAddOutData(tx, commandVal);
706 :
707 21 : else if (command == "sign") {
708 7 : ecc.reset(new Secp256k1Init());
709 7 : MutateTxSign(tx, commandVal);
710 : }
711 :
712 14 : else if (command == "load")
713 0 : RegisterLoad(commandVal);
714 :
715 14 : else if (command == "set")
716 14 : RegisterSet(commandVal);
717 :
718 : else
719 0 : throw std::runtime_error("unknown command");
720 146 : }
721 :
722 26 : static void OutputTxJSON(const CTransaction& tx)
723 : {
724 26 : UniValue entry(UniValue::VOBJ);
725 26 : TxToUniv(tx, uint256(), entry);
726 :
727 26 : std::string jsonOutput = entry.write(4);
728 26 : tfm::format(std::cout, "%s\n", jsonOutput);
729 26 : }
730 :
731 0 : static void OutputTxHash(const CTransaction& tx)
732 : {
733 0 : std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
734 :
735 0 : tfm::format(std::cout, "%s\n", strHexHash);
736 0 : }
737 :
738 27 : static void OutputTxHex(const CTransaction& tx)
739 : {
740 27 : std::string strHex = EncodeHexTx(tx);
741 :
742 27 : tfm::format(std::cout, "%s\n", strHex);
743 27 : }
744 :
745 53 : static void OutputTx(const CTransaction& tx)
746 : {
747 53 : if (gArgs.GetBoolArg("-json", false))
748 26 : OutputTxJSON(tx);
749 27 : else if (gArgs.GetBoolArg("-txid", false))
750 0 : OutputTxHash(tx);
751 : else
752 27 : OutputTxHex(tx);
753 53 : }
754 :
755 12 : static std::string readStdin()
756 : {
757 12 : char buf[4096];
758 12 : std::string ret;
759 :
760 22 : while (!feof(stdin)) {
761 22 : size_t bread = fread(buf, 1, sizeof(buf), stdin);
762 22 : ret.append(buf, bread);
763 22 : if (bread < sizeof(buf))
764 12 : break;
765 10 : }
766 :
767 12 : if (ferror(stdin))
768 0 : throw std::runtime_error("error reading stdin");
769 :
770 12 : boost::algorithm::trim_right(ret);
771 :
772 : return ret;
773 12 : }
774 :
775 81 : static int CommandLineRawTx(int argc, char* argv[])
776 : {
777 81 : std::string strPrint;
778 : int nRet = 0;
779 : try {
780 : // Skip switches; Permit common stdin convention "-"
781 174 : while (argc > 1 && IsSwitchChar(argv[1][0]) &&
782 105 : (argv[1][1] != 0)) {
783 93 : argc--;
784 93 : argv++;
785 : }
786 :
787 81 : CMutableTransaction tx;
788 : int startArg;
789 :
790 81 : if (!fCreateBlank) {
791 : // require at least one param
792 16 : if (argc < 2)
793 0 : throw std::runtime_error("too few parameters");
794 :
795 : // param: hex-encoded bitcoin transaction
796 16 : std::string strHexTx(argv[1]);
797 16 : if (strHexTx == "-") // "-" implies standard input
798 12 : strHexTx = readStdin();
799 :
800 16 : if (!DecodeHexTx(tx, strHexTx, true))
801 0 : throw std::runtime_error("invalid transaction encoding");
802 :
803 : startArg = 2;
804 16 : } else
805 : startArg = 1;
806 :
807 227 : for (int i = startArg; i < argc; i++) {
808 146 : std::string arg = argv[i];
809 146 : std::string key, value;
810 146 : size_t eqpos = arg.find('=');
811 146 : if (eqpos == std::string::npos)
812 0 : key = arg;
813 : else {
814 146 : key = arg.substr(0, eqpos);
815 146 : value = arg.substr(eqpos + 1);
816 : }
817 :
818 146 : MutateTx(tx, key, value);
819 146 : }
820 :
821 53 : OutputTx(CTransaction(tx));
822 81 : }
823 : catch (const std::exception& e) {
824 28 : strPrint = std::string("error: ") + e.what();
825 : nRet = EXIT_FAILURE;
826 28 : }
827 : catch (...) {
828 0 : PrintExceptionContinue(nullptr, "CommandLineRawTx()");
829 0 : throw;
830 28 : }
831 :
832 81 : if (strPrint != "") {
833 28 : tfm::format(nRet == 0 ? std::cout : std::cerr, "%s\n", strPrint);
834 : }
835 : return nRet;
836 109 : }
837 :
838 81 : int main(int argc, char* argv[])
839 : {
840 81 : SetupEnvironment();
841 :
842 : try {
843 81 : int ret = AppInitRawTx(argc, argv);
844 81 : if (ret != CONTINUE_EXECUTION)
845 0 : return ret;
846 81 : }
847 : catch (const std::exception& e) {
848 0 : PrintExceptionContinue(&e, "AppInitRawTx()");
849 : return EXIT_FAILURE;
850 0 : } catch (...) {
851 0 : PrintExceptionContinue(nullptr, "AppInitRawTx()");
852 : return EXIT_FAILURE;
853 0 : }
854 :
855 : int ret = EXIT_FAILURE;
856 : try {
857 81 : ret = CommandLineRawTx(argc, argv);
858 81 : }
859 : catch (const std::exception& e) {
860 0 : PrintExceptionContinue(&e, "CommandLineRawTx()");
861 0 : } catch (...) {
862 0 : PrintExceptionContinue(nullptr, "CommandLineRawTx()");
863 0 : }
864 : return ret;
865 81 : }
|