Fix exception
[VerusCoin.git] / src / komodo-tx.cpp
CommitLineData
f914f1a7 1// Copyright (c) 2009-2014 The Bitcoin Core developers
78253fcb 2// Distributed under the MIT software license, see the accompanying
cbe39a38
JG
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include "base58.h"
71697f97 6#include "clientversion.h"
afd4b94b 7#include "coins.h"
691161d4 8#include "consensus/consensus.h"
be126699 9#include "consensus/upgrades.h"
691161d4 10#include "core_io.h"
cbe39a38 11#include "keystore.h"
691161d4 12#include "primitives/transaction.h"
c4408a6c 13#include "script/script.h"
e088d65a 14#include "script/sign.h"
a10a6e2a 15#include <univalue.h>
611116d4
PK
16#include "util.h"
17#include "utilmoneystr.h"
691161d4 18#include "utilstrencodings.h"
cbe39a38
JG
19
20#include <stdio.h>
611116d4 21
fb14452c 22#include <boost/algorithm/string.hpp>
611116d4 23#include <boost/assign/list_of.hpp>
cbe39a38 24
611116d4 25using namespace std;
cbe39a38 26
fa627dbe 27#include "uint256.h"
28#include "arith_uint256.h"
97fdbcc2 29#include "komodo_structs.h"
fa627dbe 30#include "komodo_globals.h"
5416af1d 31#include "komodo_defs.h"
fa627dbe 32
6ef202b2 33#include "komodo_interest.h"
34
c60397dd 35uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight)
a933451c 36{
37 return(0);
38}
39
cbe39a38
JG
40static bool fCreateBlank;
41static map<string,UniValue> registers;
cbe39a38
JG
42
43static bool AppInitRawTx(int argc, char* argv[])
44{
45 //
46 // Parameters
47 //
48 ParseParameters(argc, argv);
49
50 // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
51 if (!SelectParamsFromCommandLine()) {
52 fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
53 return false;
54 }
55
56 fCreateBlank = GetBoolArg("-create", false);
57
af6edac0 58 if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
cbe39a38
JG
59 {
60 // First part of help message is specific to this utility
66a89c08 61 std::string strUsage = _("Zcash zcash-tx utility version") + " " + FormatFullVersion() + "\n\n" +
cbe39a38 62 _("Usage:") + "\n" +
66a89c08
JG
63 " zcash-tx [options] <hex-tx> [commands] " + _("Update hex-encoded zcash transaction") + "\n" +
64 " zcash-tx [options] -create [commands] " + _("Create hex-encoded zcash transaction") + "\n" +
cbe39a38
JG
65 "\n";
66
67 fprintf(stdout, "%s", strUsage.c_str());
68
1fdb9fa3
LV
69 strUsage = HelpMessageGroup(_("Options:"));
70 strUsage += HelpMessageOpt("-?", _("This help message"));
71 strUsage += HelpMessageOpt("-create", _("Create new, empty TX."));
72 strUsage += HelpMessageOpt("-json", _("Select JSON output"));
73 strUsage += HelpMessageOpt("-txid", _("Output only the hex-encoded transaction id of the resultant transaction."));
74 strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly."));
75 strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
cbe39a38
JG
76
77 fprintf(stdout, "%s", strUsage.c_str());
78
1fdb9fa3
LV
79 strUsage = HelpMessageGroup(_("Commands:"));
80 strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX"));
81 strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX"));
82 strUsage += HelpMessageOpt("in=TXID:VOUT", _("Add input to TX"));
83 strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
84 strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
85 strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
86 strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
be126699 87 strUsage += HelpMessageOpt("sign=HEIGHT:SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
1fdb9fa3
LV
88 _("This command requires JSON registers:") +
89 _("prevtxs=JSON object") + ", " +
90 _("privatekeys=JSON object") + ". " +
91 _("See signrawtransaction docs for format of sighash flags, JSON objects."));
cbe39a38
JG
92 fprintf(stdout, "%s", strUsage.c_str());
93
1fdb9fa3
LV
94 strUsage = HelpMessageGroup(_("Register Commands:"));
95 strUsage += HelpMessageOpt("load=NAME:FILENAME", _("Load JSON file FILENAME into register NAME"));
96 strUsage += HelpMessageOpt("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING"));
cbe39a38
JG
97 fprintf(stdout, "%s", strUsage.c_str());
98
99 return false;
100 }
101 return true;
102}
103
104static void RegisterSetJson(const string& key, const string& rawJson)
105{
106 UniValue val;
107 if (!val.read(rawJson)) {
108 string strErr = "Cannot parse JSON for key " + key;
109 throw runtime_error(strErr);
110 }
111
112 registers[key] = val;
113}
114
115static void RegisterSet(const string& strInput)
116{
117 // separate NAME:VALUE in string
118 size_t pos = strInput.find(':');
119 if ((pos == string::npos) ||
120 (pos == 0) ||
121 (pos == (strInput.size() - 1)))
122 throw runtime_error("Register input requires NAME:VALUE");
123
124 string key = strInput.substr(0, pos);
125 string valStr = strInput.substr(pos + 1, string::npos);
126
127 RegisterSetJson(key, valStr);
128}
129
130static void RegisterLoad(const string& strInput)
131{
132 // separate NAME:FILENAME in string
133 size_t pos = strInput.find(':');
134 if ((pos == string::npos) ||
135 (pos == 0) ||
136 (pos == (strInput.size() - 1)))
137 throw runtime_error("Register load requires NAME:FILENAME");
138
139 string key = strInput.substr(0, pos);
140 string filename = strInput.substr(pos + 1, string::npos);
141
142 FILE *f = fopen(filename.c_str(), "r");
143 if (!f) {
144 string strErr = "Cannot open file " + filename;
145 throw runtime_error(strErr);
146 }
147
148 // load file chunks into one big buffer
149 string valStr;
150 while ((!feof(f)) && (!ferror(f))) {
151 char buf[4096];
152 int bread = fread(buf, 1, sizeof(buf), f);
153 if (bread <= 0)
154 break;
155
156 valStr.insert(valStr.size(), buf, bread);
157 }
158
f6355e69
CR
159 int error = ferror(f);
160 fclose(f);
161
162 if (error) {
cbe39a38
JG
163 string strErr = "Error reading file " + filename;
164 throw runtime_error(strErr);
165 }
166
cbe39a38
JG
167 // evaluate as JSON buffer register
168 RegisterSetJson(key, valStr);
169}
170
171static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
172{
173 int64_t newVersion = atoi64(cmdVal);
072099d7 174 if (newVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION || newVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION)
cbe39a38
JG
175 throw runtime_error("Invalid TX version requested");
176
177 tx.nVersion = (int) newVersion;
178}
179
9bb37bf0
JG
180static void MutateTxExpiry(CMutableTransaction& tx, const string& cmdVal)
181{
182 int64_t newExpiry = atoi64(cmdVal);
183 if (newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) {
184 throw runtime_error("Invalid TX expiry requested");
185 }
186 tx.nExpiryHeight = (int) newExpiry;
187}
188
cbe39a38
JG
189static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
190{
191 int64_t newLocktime = atoi64(cmdVal);
192 if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
193 throw runtime_error("Invalid TX locktime requested");
194
195 tx.nLockTime = (unsigned int) newLocktime;
196}
197
198static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
199{
200 // separate TXID:VOUT in string
201 size_t pos = strInput.find(':');
202 if ((pos == string::npos) ||
203 (pos == 0) ||
204 (pos == (strInput.size() - 1)))
205 throw runtime_error("TX input missing separator");
206
207 // extract and validate TXID
208 string strTxid = strInput.substr(0, pos);
209 if ((strTxid.size() != 64) || !IsHex(strTxid))
210 throw runtime_error("invalid TX input txid");
34cdc411 211 uint256 txid(uint256S(strTxid));
cbe39a38
JG
212
213 static const unsigned int minTxOutSz = 9;
214 static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz;
215
216 // extract and validate vout
217 string strVout = strInput.substr(pos + 1, string::npos);
218 int vout = atoi(strVout);
219 if ((vout < 0) || (vout > (int)maxVout))
220 throw runtime_error("invalid TX input vout");
221
222 // append to transaction input list
223 CTxIn txin(txid, vout);
224 tx.vin.push_back(txin);
225}
226
227static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
228{
229 // separate VALUE:ADDRESS in string
230 size_t pos = strInput.find(':');
231 if ((pos == string::npos) ||
232 (pos == 0) ||
233 (pos == (strInput.size() - 1)))
234 throw runtime_error("TX output missing separator");
235
236 // extract and validate VALUE
237 string strValue = strInput.substr(0, pos);
a372168e 238 CAmount value;
cbe39a38
JG
239 if (!ParseMoney(strValue, value))
240 throw runtime_error("invalid TX output value");
241
242 // extract and validate ADDRESS
243 string strAddr = strInput.substr(pos + 1, string::npos);
244 CBitcoinAddress addr(strAddr);
245 if (!addr.IsValid())
246 throw runtime_error("invalid TX output address");
247
0be990ba
PW
248 // build standard output script via GetScriptForDestination()
249 CScript scriptPubKey = GetScriptForDestination(addr.Get());
cbe39a38
JG
250
251 // construct TxOut, append to transaction output list
252 CTxOut txout(value, scriptPubKey);
253 tx.vout.push_back(txout);
254}
255
256static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput)
257{
258 // separate VALUE:SCRIPT in string
259 size_t pos = strInput.find(':');
260 if ((pos == string::npos) ||
15ef1b90 261 (pos == 0))
cbe39a38
JG
262 throw runtime_error("TX output missing separator");
263
264 // extract and validate VALUE
265 string strValue = strInput.substr(0, pos);
a372168e 266 CAmount value;
cbe39a38
JG
267 if (!ParseMoney(strValue, value))
268 throw runtime_error("invalid TX output value");
269
270 // extract and validate script
271 string strScript = strInput.substr(pos + 1, string::npos);
272 CScript scriptPubKey = ParseScript(strScript); // throws on err
273
274 // construct TxOut, append to transaction output list
275 CTxOut txout(value, scriptPubKey);
276 tx.vout.push_back(txout);
277}
278
279static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx)
280{
281 // parse requested deletion index
282 int inIdx = atoi(strInIdx);
283 if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
284 string strErr = "Invalid TX input index '" + strInIdx + "'";
285 throw runtime_error(strErr.c_str());
286 }
287
288 // delete input from transaction
289 tx.vin.erase(tx.vin.begin() + inIdx);
290}
291
292static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx)
293{
294 // parse requested deletion index
295 int outIdx = atoi(strOutIdx);
296 if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {
297 string strErr = "Invalid TX output index '" + strOutIdx + "'";
298 throw runtime_error(strErr.c_str());
299 }
300
301 // delete output from transaction
302 tx.vout.erase(tx.vout.begin() + outIdx);
303}
304
305static const unsigned int N_SIGHASH_OPTS = 6;
306static const struct {
307 const char *flagStr;
308 int flags;
309} sighashOptions[N_SIGHASH_OPTS] = {
616c2430
CF
310 {"ALL", SIGHASH_ALL},
311 {"NONE", SIGHASH_NONE},
312 {"SINGLE", SIGHASH_SINGLE},
313 {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
314 {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
315 {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
cbe39a38
JG
316};
317
318static bool findSighashFlags(int& flags, const string& flagStr)
319{
320 flags = 0;
321
322 for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
323 if (flagStr == sighashOptions[i].flagStr) {
324 flags = sighashOptions[i].flags;
325 return true;
326 }
327 }
328
329 return false;
330}
331
332uint256 ParseHashUO(map<string,UniValue>& o, string strKey)
333{
334 if (!o.count(strKey))
4f152496 335 return uint256();
cbe39a38
JG
336 return ParseHashUV(o[strKey], strKey);
337}
338
339vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
340{
341 if (!o.count(strKey)) {
342 vector<unsigned char> emptyVec;
343 return emptyVec;
344 }
345 return ParseHexUV(o[strKey], strKey);
346}
347
157a5d0d
PW
348static CAmount AmountFromValue(const UniValue& value)
349{
350 if (!value.isNum() && !value.isStr())
351 throw runtime_error("Amount is not a number or string");
352 CAmount amount;
353 if (!ParseFixedPoint(value.getValStr(), 8, &amount))
354 throw runtime_error("Invalid amount");
355 if (!MoneyRange(amount))
356 throw runtime_error("Amount out of range");
357 return amount;
358}
8ad9f27f 359
be126699 360static void MutateTxSign(CMutableTransaction& tx, const string& strInput)
cbe39a38 361{
be126699
JG
362 // separate HEIGHT:SIGHASH-FLAGS in string
363 size_t pos = strInput.find(':');
364 if ((pos == 0) ||
365 (pos == (strInput.size() - 1)))
366 throw runtime_error("Invalid sighash flag separator");
367
368 // extract and validate HEIGHT
369 string strHeight = strInput.substr(0, pos);
370 int nHeight = atoi(strHeight);
371 if (nHeight <= 0) {
372 throw runtime_error("invalid height");
373 }
cbe39a38 374
be126699
JG
375 // extract and validate SIGHASH-FLAGS
376 int nHashType = SIGHASH_ALL;
377 string flagStr;
378 if (pos != string::npos) {
379 flagStr = strInput.substr(pos + 1, string::npos);
380 }
cbe39a38
JG
381 if (flagStr.size() > 0)
382 if (!findSighashFlags(nHashType, flagStr))
383 throw runtime_error("unknown sighash flag/sign option");
384
385 vector<CTransaction> txVariants;
386 txVariants.push_back(tx);
387
388 // mergedTx will end up with all the signatures; it
389 // starts as a clone of the raw tx:
390 CMutableTransaction mergedTx(txVariants[0]);
391 bool fComplete = true;
392 CCoinsView viewDummy;
7c70438d 393 CCoinsViewCache view(&viewDummy);
cbe39a38
JG
394
395 if (!registers.count("privatekeys"))
396 throw runtime_error("privatekeys register variable must be set.");
397 bool fGivenKeys = false;
398 CBasicKeyStore tempKeystore;
399 UniValue keysObj = registers["privatekeys"];
400 fGivenKeys = true;
401
cc71666a 402 for (size_t kidx = 0; kidx < keysObj.size(); kidx++) {
cbe39a38
JG
403 if (!keysObj[kidx].isStr())
404 throw runtime_error("privatekey not a string");
405 CBitcoinSecret vchSecret;
406 bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
407 if (!fGood)
408 throw runtime_error("privatekey not valid");
409
410 CKey key = vchSecret.GetKey();
411 tempKeystore.AddKey(key);
412 }
413
414 // Add previous txouts given in the RPC call:
415 if (!registers.count("prevtxs"))
416 throw runtime_error("prevtxs register variable must be set.");
2a3d988b 417 UniValue prevtxsObj = registers["prevtxs"];
cbe39a38 418 {
cc71666a 419 for (size_t previdx = 0; previdx < prevtxsObj.size(); previdx++) {
cbe39a38
JG
420 UniValue prevOut = prevtxsObj[previdx];
421 if (!prevOut.isObject())
422 throw runtime_error("expected prevtxs internal object");
423
856e862f 424 map<string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
cbe39a38
JG
425 if (!prevOut.checkObject(types))
426 throw runtime_error("prevtxs internal object typecheck fail");
427
a089c509 428 uint256 txid = ParseHashUV(prevOut["txid"], "txid");
cbe39a38
JG
429
430 int nOut = atoi(prevOut["vout"].getValStr());
431 if (nOut < 0)
432 throw runtime_error("vout must be positive");
433
a089c509 434 vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
cbe39a38
JG
435 CScript scriptPubKey(pkData.begin(), pkData.end());
436
f28aec01
PW
437 {
438 CCoinsModifier coins = view.ModifyCoins(txid);
439 if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
cbe39a38 440 string err("Previous output scriptPubKey mismatch:\n");
f28aec01 441 err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
cbe39a38
JG
442 scriptPubKey.ToString();
443 throw runtime_error(err);
444 }
f28aec01
PW
445 if ((unsigned int)nOut >= coins->vout.size())
446 coins->vout.resize(nOut+1);
447 coins->vout[nOut].scriptPubKey = scriptPubKey;
157a5d0d
PW
448 coins->vout[nOut].nValue = 0;
449 if (prevOut.exists("amount")) {
450 coins->vout[nOut].nValue = AmountFromValue(prevOut["amount"]);
451 }
cbe39a38 452 }
cbe39a38
JG
453
454 // if redeemScript given and private keys given,
455 // add redeemScript to the tempKeystore so it can be signed:
456 if (fGivenKeys && scriptPubKey.IsPayToScriptHash() &&
457 prevOut.exists("redeemScript")) {
458 UniValue v = prevOut["redeemScript"];
459 vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
460 CScript redeemScript(rsData.begin(), rsData.end());
461 tempKeystore.AddCScript(redeemScript);
462 }
463 }
464 }
465
466 const CKeyStore& keystore = tempKeystore;
467
468 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
469
be126699
JG
470 // Grab the consensus branch ID for the given height
471 auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
472
cbe39a38
JG
473 // Sign what we can:
474 for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
475 CTxIn& txin = mergedTx.vin[i];
629d75fa
PW
476 const CCoins* coins = view.AccessCoins(txin.prevout.hash);
477 if (!coins || !coins->IsAvailable(txin.prevout.n)) {
cbe39a38
JG
478 fComplete = false;
479 continue;
480 }
629d75fa 481 const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
2d42e1a9 482 const CAmount& amount = coins->vout[txin.prevout.n].nValue;
cbe39a38 483
157a5d0d 484 SignatureData sigdata;
cbe39a38
JG
485 // Only sign SIGHASH_SINGLE if there's a corresponding output:
486 if (!fHashSingle || (i < mergedTx.vout.size()))
be126699 487 ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
cbe39a38
JG
488
489 // ... and merge in other signatures:
157a5d0d 490 BOOST_FOREACH(const CTransaction& txv, txVariants)
be126699 491 sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
157a5d0d
PW
492 UpdateTransaction(mergedTx, i, sigdata);
493
be126699 494 if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId))
cbe39a38
JG
495 fComplete = false;
496 }
497
498 if (fComplete) {
499 // do nothing... for now
500 // perhaps store this for later optional JSON output
501 }
502
503 tx = mergedTx;
504}
505
a56054be
PW
506class Secp256k1Init
507{
3d02d0f6
PW
508 ECCVerifyHandle globalVerifyHandle;
509
a56054be 510public:
3d02d0f6
PW
511 Secp256k1Init() {
512 ECC_Start();
513 }
514 ~Secp256k1Init() {
515 ECC_Stop();
516 }
a56054be
PW
517};
518
cbe39a38
JG
519static void MutateTx(CMutableTransaction& tx, const string& command,
520 const string& commandVal)
521{
a56054be
PW
522 boost::scoped_ptr<Secp256k1Init> ecc;
523
cbe39a38
JG
524 if (command == "nversion")
525 MutateTxVersion(tx, commandVal);
526 else if (command == "locktime")
527 MutateTxLocktime(tx, commandVal);
9bb37bf0
JG
528 else if (command == "expiry")
529 MutateTxExpiry(tx, commandVal);
cbe39a38
JG
530
531 else if (command == "delin")
532 MutateTxDelInput(tx, commandVal);
533 else if (command == "in")
534 MutateTxAddInput(tx, commandVal);
535
536 else if (command == "delout")
537 MutateTxDelOutput(tx, commandVal);
538 else if (command == "outaddr")
539 MutateTxAddOutAddr(tx, commandVal);
540 else if (command == "outscript")
541 MutateTxAddOutScript(tx, commandVal);
542
a56054be
PW
543 else if (command == "sign") {
544 if (!ecc) { ecc.reset(new Secp256k1Init()); }
cbe39a38 545 MutateTxSign(tx, commandVal);
a56054be 546 }
cbe39a38
JG
547
548 else if (command == "load")
549 RegisterLoad(commandVal);
550
551 else if (command == "set")
552 RegisterSet(commandVal);
553
554 else
555 throw runtime_error("unknown command");
556}
557
558static void OutputTxJSON(const CTransaction& tx)
559{
560 UniValue entry(UniValue::VOBJ);
4f152496 561 TxToUniv(tx, uint256(), entry);
cbe39a38
JG
562
563 string jsonOutput = entry.write(4);
564 fprintf(stdout, "%s\n", jsonOutput.c_str());
565}
566
84877904 567static void OutputTxHash(const CTransaction& tx)
568{
805344dc 569 string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
84877904 570
571 fprintf(stdout, "%s\n", strHexHash.c_str());
572}
573
cbe39a38
JG
574static void OutputTxHex(const CTransaction& tx)
575{
576 string strHex = EncodeHexTx(tx);
577
578 fprintf(stdout, "%s\n", strHex.c_str());
579}
580
581static void OutputTx(const CTransaction& tx)
582{
583 if (GetBoolArg("-json", false))
584 OutputTxJSON(tx);
84877904 585 else if (GetBoolArg("-txid", false))
586 OutputTxHash(tx);
cbe39a38
JG
587 else
588 OutputTxHex(tx);
589}
590
fb14452c
JG
591static string readStdin()
592{
593 char buf[4096];
594 string ret;
595
596 while (!feof(stdin)) {
597 size_t bread = fread(buf, 1, sizeof(buf), stdin);
598 ret.append(buf, bread);
599 if (bread < sizeof(buf))
600 break;
601 }
602
603 if (ferror(stdin))
604 throw runtime_error("error reading stdin");
605
606 boost::algorithm::trim_right(ret);
607
608 return ret;
609}
610
cbe39a38
JG
611static int CommandLineRawTx(int argc, char* argv[])
612{
613 string strPrint;
614 int nRet = 0;
615 try {
fb14452c
JG
616 // Skip switches; Permit common stdin convention "-"
617 while (argc > 1 && IsSwitchChar(argv[1][0]) &&
618 (argv[1][1] != 0)) {
cbe39a38
JG
619 argc--;
620 argv++;
621 }
622
623 CTransaction txDecodeTmp;
624 int startArg;
625
626 if (!fCreateBlank) {
627 // require at least one param
628 if (argc < 2)
629 throw runtime_error("too few parameters");
630
631 // param: hex-encoded bitcoin transaction
632 string strHexTx(argv[1]);
fb14452c
JG
633 if (strHexTx == "-") // "-" implies standard input
634 strHexTx = readStdin();
cbe39a38
JG
635
636 if (!DecodeHexTx(txDecodeTmp, strHexTx))
637 throw runtime_error("invalid transaction encoding");
638
639 startArg = 2;
640 } else
641 startArg = 1;
642
643 CMutableTransaction tx(txDecodeTmp);
644
645 for (int i = startArg; i < argc; i++) {
646 string arg = argv[i];
647 string key, value;
648 size_t eqpos = arg.find('=');
649 if (eqpos == string::npos)
650 key = arg;
651 else {
652 key = arg.substr(0, eqpos);
653 value = arg.substr(eqpos + 1);
654 }
655
656 MutateTx(tx, key, value);
657 }
658
659 OutputTx(tx);
660 }
661
27df4123 662 catch (const boost::thread_interrupted&) {
cbe39a38
JG
663 throw;
664 }
27df4123 665 catch (const std::exception& e) {
cbe39a38
JG
666 strPrint = string("error: ") + e.what();
667 nRet = EXIT_FAILURE;
668 }
669 catch (...) {
670 PrintExceptionContinue(NULL, "CommandLineRawTx()");
671 throw;
672 }
673
674 if (strPrint != "") {
675 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
676 }
677 return nRet;
678}
679
680int main(int argc, char* argv[])
681{
682 SetupEnvironment();
683
684 try {
685 if(!AppInitRawTx(argc, argv))
686 return EXIT_FAILURE;
687 }
27df4123 688 catch (const std::exception& e) {
cbe39a38
JG
689 PrintExceptionContinue(&e, "AppInitRawTx()");
690 return EXIT_FAILURE;
691 } catch (...) {
692 PrintExceptionContinue(NULL, "AppInitRawTx()");
693 return EXIT_FAILURE;
694 }
695
696 int ret = EXIT_FAILURE;
697 try {
698 ret = CommandLineRawTx(argc, argv);
699 }
27df4123 700 catch (const std::exception& e) {
cbe39a38
JG
701 PrintExceptionContinue(&e, "CommandLineRawTx()");
702 } catch (...) {
703 PrintExceptionContinue(NULL, "CommandLineRawTx()");
704 }
705 return ret;
706}
This page took 0.381867 seconds and 4 git commands to generate.