bitcoin-tx.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. // Copyright (c) 2009-2014 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. #include "base58.h"
  5. #include "clientversion.h"
  6. #include "coins.h"
  7. #include "consensus/consensus.h"
  8. #include "core_io.h"
  9. #include "keystore.h"
  10. #include "primitives/transaction.h"
  11. #include "script/script.h"
  12. #include "script/sign.h"
  13. #include "univalue/univalue.h"
  14. #include "util.h"
  15. #include "utilmoneystr.h"
  16. #include "utilstrencodings.h"
  17. #include <stdio.h>
  18. #include <boost/algorithm/string.hpp>
  19. #include <boost/assign/list_of.hpp>
  20. using namespace std;
  21. static bool fCreateBlank;
  22. static map<string,UniValue> registers;
  23. static bool AppInitRawTx(int argc, char* argv[])
  24. {
  25. //
  26. // Parameters
  27. //
  28. ParseParameters(argc, argv);
  29. // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
  30. if (!SelectParamsFromCommandLine()) {
  31. fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
  32. return false;
  33. }
  34. fCreateBlank = GetBoolArg("-create", false);
  35. if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
  36. {
  37. // First part of help message is specific to this utility
  38. std::string strUsage = _("Zcash zcash-tx utility version") + " " + FormatFullVersion() + "\n\n" +
  39. _("Usage:") + "\n" +
  40. " zcash-tx [options] <hex-tx> [commands] " + _("Update hex-encoded zcash transaction") + "\n" +
  41. " zcash-tx [options] -create [commands] " + _("Create hex-encoded zcash transaction") + "\n" +
  42. "\n";
  43. fprintf(stdout, "%s", strUsage.c_str());
  44. strUsage = HelpMessageGroup(_("Options:"));
  45. strUsage += HelpMessageOpt("-?", _("This help message"));
  46. strUsage += HelpMessageOpt("-create", _("Create new, empty TX."));
  47. strUsage += HelpMessageOpt("-json", _("Select JSON output"));
  48. strUsage += HelpMessageOpt("-txid", _("Output only the hex-encoded transaction id of the resultant transaction."));
  49. strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly."));
  50. strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
  51. fprintf(stdout, "%s", strUsage.c_str());
  52. strUsage = HelpMessageGroup(_("Commands:"));
  53. strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX"));
  54. strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX"));
  55. strUsage += HelpMessageOpt("in=TXID:VOUT", _("Add input to TX"));
  56. strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
  57. strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
  58. strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
  59. strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
  60. strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
  61. _("This command requires JSON registers:") +
  62. _("prevtxs=JSON object") + ", " +
  63. _("privatekeys=JSON object") + ". " +
  64. _("See signrawtransaction docs for format of sighash flags, JSON objects."));
  65. fprintf(stdout, "%s", strUsage.c_str());
  66. strUsage = HelpMessageGroup(_("Register Commands:"));
  67. strUsage += HelpMessageOpt("load=NAME:FILENAME", _("Load JSON file FILENAME into register NAME"));
  68. strUsage += HelpMessageOpt("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING"));
  69. fprintf(stdout, "%s", strUsage.c_str());
  70. return false;
  71. }
  72. return true;
  73. }
  74. static void RegisterSetJson(const string& key, const string& rawJson)
  75. {
  76. UniValue val;
  77. if (!val.read(rawJson)) {
  78. string strErr = "Cannot parse JSON for key " + key;
  79. throw runtime_error(strErr);
  80. }
  81. registers[key] = val;
  82. }
  83. static void RegisterSet(const string& strInput)
  84. {
  85. // separate NAME:VALUE in string
  86. size_t pos = strInput.find(':');
  87. if ((pos == string::npos) ||
  88. (pos == 0) ||
  89. (pos == (strInput.size() - 1)))
  90. throw runtime_error("Register input requires NAME:VALUE");
  91. string key = strInput.substr(0, pos);
  92. string valStr = strInput.substr(pos + 1, string::npos);
  93. RegisterSetJson(key, valStr);
  94. }
  95. static void RegisterLoad(const string& strInput)
  96. {
  97. // separate NAME:FILENAME in string
  98. size_t pos = strInput.find(':');
  99. if ((pos == string::npos) ||
  100. (pos == 0) ||
  101. (pos == (strInput.size() - 1)))
  102. throw runtime_error("Register load requires NAME:FILENAME");
  103. string key = strInput.substr(0, pos);
  104. string filename = strInput.substr(pos + 1, string::npos);
  105. FILE *f = fopen(filename.c_str(), "r");
  106. if (!f) {
  107. string strErr = "Cannot open file " + filename;
  108. throw runtime_error(strErr);
  109. }
  110. // load file chunks into one big buffer
  111. string valStr;
  112. while ((!feof(f)) && (!ferror(f))) {
  113. char buf[4096];
  114. int bread = fread(buf, 1, sizeof(buf), f);
  115. if (bread <= 0)
  116. break;
  117. valStr.insert(valStr.size(), buf, bread);
  118. }
  119. int error = ferror(f);
  120. fclose(f);
  121. if (error) {
  122. string strErr = "Error reading file " + filename;
  123. throw runtime_error(strErr);
  124. }
  125. // evaluate as JSON buffer register
  126. RegisterSetJson(key, valStr);
  127. }
  128. static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
  129. {
  130. int64_t newVersion = atoi64(cmdVal);
  131. if (newVersion < CTransaction::MIN_CURRENT_VERSION || newVersion > CTransaction::MAX_CURRENT_VERSION)
  132. throw runtime_error("Invalid TX version requested");
  133. tx.nVersion = (int) newVersion;
  134. }
  135. static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
  136. {
  137. int64_t newLocktime = atoi64(cmdVal);
  138. if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
  139. throw runtime_error("Invalid TX locktime requested");
  140. tx.nLockTime = (unsigned int) newLocktime;
  141. }
  142. static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
  143. {
  144. // separate TXID:VOUT in string
  145. size_t pos = strInput.find(':');
  146. if ((pos == string::npos) ||
  147. (pos == 0) ||
  148. (pos == (strInput.size() - 1)))
  149. throw runtime_error("TX input missing separator");
  150. // extract and validate TXID
  151. string strTxid = strInput.substr(0, pos);
  152. if ((strTxid.size() != 64) || !IsHex(strTxid))
  153. throw runtime_error("invalid TX input txid");
  154. uint256 txid(uint256S(strTxid));
  155. static const unsigned int minTxOutSz = 9;
  156. static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz;
  157. // extract and validate vout
  158. string strVout = strInput.substr(pos + 1, string::npos);
  159. int vout = atoi(strVout);
  160. if ((vout < 0) || (vout > (int)maxVout))
  161. throw runtime_error("invalid TX input vout");
  162. // append to transaction input list
  163. CTxIn txin(txid, vout);
  164. tx.vin.push_back(txin);
  165. }
  166. static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
  167. {
  168. // separate VALUE:ADDRESS in string
  169. size_t pos = strInput.find(':');
  170. if ((pos == string::npos) ||
  171. (pos == 0) ||
  172. (pos == (strInput.size() - 1)))
  173. throw runtime_error("TX output missing separator");
  174. // extract and validate VALUE
  175. string strValue = strInput.substr(0, pos);
  176. CAmount value;
  177. if (!ParseMoney(strValue, value))
  178. throw runtime_error("invalid TX output value");
  179. // extract and validate ADDRESS
  180. string strAddr = strInput.substr(pos + 1, string::npos);
  181. CBitcoinAddress addr(strAddr);
  182. if (!addr.IsValid())
  183. throw runtime_error("invalid TX output address");
  184. // build standard output script via GetScriptForDestination()
  185. CScript scriptPubKey = GetScriptForDestination(addr.Get());
  186. // construct TxOut, append to transaction output list
  187. CTxOut txout(value, scriptPubKey);
  188. tx.vout.push_back(txout);
  189. }
  190. static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput)
  191. {
  192. // separate VALUE:SCRIPT in string
  193. size_t pos = strInput.find(':');
  194. if ((pos == string::npos) ||
  195. (pos == 0))
  196. throw runtime_error("TX output missing separator");
  197. // extract and validate VALUE
  198. string strValue = strInput.substr(0, pos);
  199. CAmount value;
  200. if (!ParseMoney(strValue, value))
  201. throw runtime_error("invalid TX output value");
  202. // extract and validate script
  203. string strScript = strInput.substr(pos + 1, string::npos);
  204. CScript scriptPubKey = ParseScript(strScript); // throws on err
  205. // construct TxOut, append to transaction output list
  206. CTxOut txout(value, scriptPubKey);
  207. tx.vout.push_back(txout);
  208. }
  209. static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx)
  210. {
  211. // parse requested deletion index
  212. int inIdx = atoi(strInIdx);
  213. if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
  214. string strErr = "Invalid TX input index '" + strInIdx + "'";
  215. throw runtime_error(strErr.c_str());
  216. }
  217. // delete input from transaction
  218. tx.vin.erase(tx.vin.begin() + inIdx);
  219. }
  220. static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx)
  221. {
  222. // parse requested deletion index
  223. int outIdx = atoi(strOutIdx);
  224. if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {
  225. string strErr = "Invalid TX output index '" + strOutIdx + "'";
  226. throw runtime_error(strErr.c_str());
  227. }
  228. // delete output from transaction
  229. tx.vout.erase(tx.vout.begin() + outIdx);
  230. }
  231. static const unsigned int N_SIGHASH_OPTS = 6;
  232. static const struct {
  233. const char *flagStr;
  234. int flags;
  235. } sighashOptions[N_SIGHASH_OPTS] = {
  236. {"ALL", SIGHASH_ALL},
  237. {"NONE", SIGHASH_NONE},
  238. {"SINGLE", SIGHASH_SINGLE},
  239. {"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
  240. {"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
  241. {"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
  242. };
  243. static bool findSighashFlags(int& flags, const string& flagStr)
  244. {
  245. flags = 0;
  246. for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
  247. if (flagStr == sighashOptions[i].flagStr) {
  248. flags = sighashOptions[i].flags;
  249. return true;
  250. }
  251. }
  252. return false;
  253. }
  254. uint256 ParseHashUO(map<string,UniValue>& o, string strKey)
  255. {
  256. if (!o.count(strKey))
  257. return uint256();
  258. return ParseHashUV(o[strKey], strKey);
  259. }
  260. vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
  261. {
  262. if (!o.count(strKey)) {
  263. vector<unsigned char> emptyVec;
  264. return emptyVec;
  265. }
  266. return ParseHexUV(o[strKey], strKey);
  267. }
  268. static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
  269. {
  270. int nHashType = SIGHASH_ALL;
  271. if (flagStr.size() > 0)
  272. if (!findSighashFlags(nHashType, flagStr))
  273. throw runtime_error("unknown sighash flag/sign option");
  274. vector<CTransaction> txVariants;
  275. txVariants.push_back(tx);
  276. // mergedTx will end up with all the signatures; it
  277. // starts as a clone of the raw tx:
  278. CMutableTransaction mergedTx(txVariants[0]);
  279. bool fComplete = true;
  280. CCoinsView viewDummy;
  281. CCoinsViewCache view(&viewDummy);
  282. if (!registers.count("privatekeys"))
  283. throw runtime_error("privatekeys register variable must be set.");
  284. bool fGivenKeys = false;
  285. CBasicKeyStore tempKeystore;
  286. UniValue keysObj = registers["privatekeys"];
  287. fGivenKeys = true;
  288. for (unsigned int kidx = 0; kidx < keysObj.count(); kidx++) {
  289. if (!keysObj[kidx].isStr())
  290. throw runtime_error("privatekey not a string");
  291. CBitcoinSecret vchSecret;
  292. bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
  293. if (!fGood)
  294. throw runtime_error("privatekey not valid");
  295. CKey key = vchSecret.GetKey();
  296. tempKeystore.AddKey(key);
  297. }
  298. // Add previous txouts given in the RPC call:
  299. if (!registers.count("prevtxs"))
  300. throw runtime_error("prevtxs register variable must be set.");
  301. UniValue prevtxsObj = registers["prevtxs"];
  302. {
  303. for (unsigned int previdx = 0; previdx < prevtxsObj.count(); previdx++) {
  304. UniValue prevOut = prevtxsObj[previdx];
  305. if (!prevOut.isObject())
  306. throw runtime_error("expected prevtxs internal object");
  307. map<string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
  308. if (!prevOut.checkObject(types))
  309. throw runtime_error("prevtxs internal object typecheck fail");
  310. uint256 txid = ParseHashUV(prevOut["txid"], "txid");
  311. int nOut = atoi(prevOut["vout"].getValStr());
  312. if (nOut < 0)
  313. throw runtime_error("vout must be positive");
  314. vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
  315. CScript scriptPubKey(pkData.begin(), pkData.end());
  316. {
  317. CCoinsModifier coins = view.ModifyCoins(txid);
  318. if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
  319. string err("Previous output scriptPubKey mismatch:\n");
  320. err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
  321. scriptPubKey.ToString();
  322. throw runtime_error(err);
  323. }
  324. if ((unsigned int)nOut >= coins->vout.size())
  325. coins->vout.resize(nOut+1);
  326. coins->vout[nOut].scriptPubKey = scriptPubKey;
  327. coins->vout[nOut].nValue = 0; // we don't know the actual output value
  328. }
  329. // if redeemScript given and private keys given,
  330. // add redeemScript to the tempKeystore so it can be signed:
  331. if (fGivenKeys && scriptPubKey.IsPayToScriptHash() &&
  332. prevOut.exists("redeemScript")) {
  333. UniValue v = prevOut["redeemScript"];
  334. vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
  335. CScript redeemScript(rsData.begin(), rsData.end());
  336. tempKeystore.AddCScript(redeemScript);
  337. }
  338. }
  339. }
  340. const CKeyStore& keystore = tempKeystore;
  341. bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
  342. // Sign what we can:
  343. for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
  344. CTxIn& txin = mergedTx.vin[i];
  345. const CCoins* coins = view.AccessCoins(txin.prevout.hash);
  346. if (!coins || !coins->IsAvailable(txin.prevout.n)) {
  347. fComplete = false;
  348. continue;
  349. }
  350. const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
  351. txin.scriptSig.clear();
  352. // Only sign SIGHASH_SINGLE if there's a corresponding output:
  353. if (!fHashSingle || (i < mergedTx.vout.size()))
  354. SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
  355. // ... and merge in other signatures:
  356. BOOST_FOREACH(const CTransaction& txv, txVariants) {
  357. txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
  358. }
  359. if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
  360. fComplete = false;
  361. }
  362. if (fComplete) {
  363. // do nothing... for now
  364. // perhaps store this for later optional JSON output
  365. }
  366. tx = mergedTx;
  367. }
  368. class Secp256k1Init
  369. {
  370. public:
  371. Secp256k1Init() { ECC_Start(); }
  372. ~Secp256k1Init() { ECC_Stop(); }
  373. };
  374. static void MutateTx(CMutableTransaction& tx, const string& command,
  375. const string& commandVal)
  376. {
  377. boost::scoped_ptr<Secp256k1Init> ecc;
  378. if (command == "nversion")
  379. MutateTxVersion(tx, commandVal);
  380. else if (command == "locktime")
  381. MutateTxLocktime(tx, commandVal);
  382. else if (command == "delin")
  383. MutateTxDelInput(tx, commandVal);
  384. else if (command == "in")
  385. MutateTxAddInput(tx, commandVal);
  386. else if (command == "delout")
  387. MutateTxDelOutput(tx, commandVal);
  388. else if (command == "outaddr")
  389. MutateTxAddOutAddr(tx, commandVal);
  390. else if (command == "outscript")
  391. MutateTxAddOutScript(tx, commandVal);
  392. else if (command == "sign") {
  393. if (!ecc) { ecc.reset(new Secp256k1Init()); }
  394. MutateTxSign(tx, commandVal);
  395. }
  396. else if (command == "load")
  397. RegisterLoad(commandVal);
  398. else if (command == "set")
  399. RegisterSet(commandVal);
  400. else
  401. throw runtime_error("unknown command");
  402. }
  403. static void OutputTxJSON(const CTransaction& tx)
  404. {
  405. UniValue entry(UniValue::VOBJ);
  406. TxToUniv(tx, uint256(), entry);
  407. string jsonOutput = entry.write(4);
  408. fprintf(stdout, "%s\n", jsonOutput.c_str());
  409. }
  410. static void OutputTxHash(const CTransaction& tx)
  411. {
  412. string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
  413. fprintf(stdout, "%s\n", strHexHash.c_str());
  414. }
  415. static void OutputTxHex(const CTransaction& tx)
  416. {
  417. string strHex = EncodeHexTx(tx);
  418. fprintf(stdout, "%s\n", strHex.c_str());
  419. }
  420. static void OutputTx(const CTransaction& tx)
  421. {
  422. if (GetBoolArg("-json", false))
  423. OutputTxJSON(tx);
  424. else if (GetBoolArg("-txid", false))
  425. OutputTxHash(tx);
  426. else
  427. OutputTxHex(tx);
  428. }
  429. static string readStdin()
  430. {
  431. char buf[4096];
  432. string ret;
  433. while (!feof(stdin)) {
  434. size_t bread = fread(buf, 1, sizeof(buf), stdin);
  435. ret.append(buf, bread);
  436. if (bread < sizeof(buf))
  437. break;
  438. }
  439. if (ferror(stdin))
  440. throw runtime_error("error reading stdin");
  441. boost::algorithm::trim_right(ret);
  442. return ret;
  443. }
  444. static int CommandLineRawTx(int argc, char* argv[])
  445. {
  446. string strPrint;
  447. int nRet = 0;
  448. try {
  449. // Skip switches; Permit common stdin convention "-"
  450. while (argc > 1 && IsSwitchChar(argv[1][0]) &&
  451. (argv[1][1] != 0)) {
  452. argc--;
  453. argv++;
  454. }
  455. CTransaction txDecodeTmp;
  456. int startArg;
  457. if (!fCreateBlank) {
  458. // require at least one param
  459. if (argc < 2)
  460. throw runtime_error("too few parameters");
  461. // param: hex-encoded bitcoin transaction
  462. string strHexTx(argv[1]);
  463. if (strHexTx == "-") // "-" implies standard input
  464. strHexTx = readStdin();
  465. if (!DecodeHexTx(txDecodeTmp, strHexTx))
  466. throw runtime_error("invalid transaction encoding");
  467. startArg = 2;
  468. } else
  469. startArg = 1;
  470. CMutableTransaction tx(txDecodeTmp);
  471. for (int i = startArg; i < argc; i++) {
  472. string arg = argv[i];
  473. string key, value;
  474. size_t eqpos = arg.find('=');
  475. if (eqpos == string::npos)
  476. key = arg;
  477. else {
  478. key = arg.substr(0, eqpos);
  479. value = arg.substr(eqpos + 1);
  480. }
  481. MutateTx(tx, key, value);
  482. }
  483. OutputTx(tx);
  484. }
  485. catch (const boost::thread_interrupted&) {
  486. throw;
  487. }
  488. catch (const std::exception& e) {
  489. strPrint = string("error: ") + e.what();
  490. nRet = EXIT_FAILURE;
  491. }
  492. catch (...) {
  493. PrintExceptionContinue(NULL, "CommandLineRawTx()");
  494. throw;
  495. }
  496. if (strPrint != "") {
  497. fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
  498. }
  499. return nRet;
  500. }
  501. int main(int argc, char* argv[])
  502. {
  503. SetupEnvironment();
  504. try {
  505. if(!AppInitRawTx(argc, argv))
  506. return EXIT_FAILURE;
  507. }
  508. catch (const std::exception& e) {
  509. PrintExceptionContinue(&e, "AppInitRawTx()");
  510. return EXIT_FAILURE;
  511. } catch (...) {
  512. PrintExceptionContinue(NULL, "AppInitRawTx()");
  513. return EXIT_FAILURE;
  514. }
  515. int ret = EXIT_FAILURE;
  516. try {
  517. ret = CommandLineRawTx(argc, argv);
  518. }
  519. catch (const std::exception& e) {
  520. PrintExceptionContinue(&e, "CommandLineRawTx()");
  521. } catch (...) {
  522. PrintExceptionContinue(NULL, "CommandLineRawTx()");
  523. }
  524. return ret;
  525. }