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.
6 #include "clientversion.h"
8 #include "consensus/consensus.h"
9 #include "consensus/upgrades.h"
12 #include "primitives/transaction.h"
13 #include "script/script.h"
14 #include "script/sign.h"
17 #include "utilmoneystr.h"
18 #include "utilstrencodings.h"
22 #include <boost/algorithm/string.hpp>
23 #include <boost/assign/list_of.hpp>
28 #include "arith_uint256.h"
29 #include "komodo_structs.h"
30 #include "komodo_globals.h"
31 #include "komodo_defs.h"
33 #include "komodo_interest.h"
35 uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight)
40 static bool fCreateBlank;
41 static map<string,UniValue> registers;
43 static bool AppInitRawTx(int argc, char* argv[])
48 ParseParameters(argc, argv);
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");
56 fCreateBlank = GetBoolArg("-create", false);
58 if (argc<2 || mapArgs.count("-?") || mapArgs.count("-h") || mapArgs.count("-help"))
60 // First part of help message is specific to this utility
61 std::string strUsage = _("Zcash zcash-tx utility version") + " " + FormatFullVersion() + "\n\n" +
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" +
67 fprintf(stdout, "%s", strUsage.c_str());
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"));
77 fprintf(stdout, "%s", strUsage.c_str());
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"));
87 strUsage += HelpMessageOpt("sign=HEIGHT:SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
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."));
92 fprintf(stdout, "%s", strUsage.c_str());
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"));
97 fprintf(stdout, "%s", strUsage.c_str());
104 static void RegisterSetJson(const string& key, const string& rawJson)
107 if (!val.read(rawJson)) {
108 string strErr = "Cannot parse JSON for key " + key;
109 throw runtime_error(strErr);
112 registers[key] = val;
115 static void RegisterSet(const string& strInput)
117 // separate NAME:VALUE in string
118 size_t pos = strInput.find(':');
119 if ((pos == string::npos) ||
121 (pos == (strInput.size() - 1)))
122 throw runtime_error("Register input requires NAME:VALUE");
124 string key = strInput.substr(0, pos);
125 string valStr = strInput.substr(pos + 1, string::npos);
127 RegisterSetJson(key, valStr);
130 static void RegisterLoad(const string& strInput)
132 // separate NAME:FILENAME in string
133 size_t pos = strInput.find(':');
134 if ((pos == string::npos) ||
136 (pos == (strInput.size() - 1)))
137 throw runtime_error("Register load requires NAME:FILENAME");
139 string key = strInput.substr(0, pos);
140 string filename = strInput.substr(pos + 1, string::npos);
142 FILE *f = fopen(filename.c_str(), "r");
144 string strErr = "Cannot open file " + filename;
145 throw runtime_error(strErr);
148 // load file chunks into one big buffer
150 while ((!feof(f)) && (!ferror(f))) {
152 int bread = fread(buf, 1, sizeof(buf), f);
156 valStr.insert(valStr.size(), buf, bread);
159 int error = ferror(f);
163 string strErr = "Error reading file " + filename;
164 throw runtime_error(strErr);
167 // evaluate as JSON buffer register
168 RegisterSetJson(key, valStr);
171 static void MutateTxVersion(CMutableTransaction& tx, const string& cmdVal)
173 int64_t newVersion = atoi64(cmdVal);
174 if (newVersion < CTransaction::SPROUT_MIN_CURRENT_VERSION || newVersion > CTransaction::SPROUT_MAX_CURRENT_VERSION)
175 throw runtime_error("Invalid TX version requested");
177 tx.nVersion = (int) newVersion;
180 static void MutateTxExpiry(CMutableTransaction& tx, const string& cmdVal)
182 int64_t newExpiry = atoi64(cmdVal);
183 if (newExpiry >= TX_EXPIRY_HEIGHT_THRESHOLD) {
184 throw runtime_error("Invalid TX expiry requested");
186 tx.nExpiryHeight = (int) newExpiry;
189 static void MutateTxLocktime(CMutableTransaction& tx, const string& cmdVal)
191 int64_t newLocktime = atoi64(cmdVal);
192 if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
193 throw runtime_error("Invalid TX locktime requested");
195 tx.nLockTime = (unsigned int) newLocktime;
198 static void MutateTxAddInput(CMutableTransaction& tx, const string& strInput)
200 // separate TXID:VOUT in string
201 size_t pos = strInput.find(':');
202 if ((pos == string::npos) ||
204 (pos == (strInput.size() - 1)))
205 throw runtime_error("TX input missing separator");
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");
211 uint256 txid(uint256S(strTxid));
213 static const unsigned int minTxOutSz = 9;
214 static const unsigned int maxVout = MAX_BLOCK_SIZE / minTxOutSz;
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");
222 // append to transaction input list
223 CTxIn txin(txid, vout);
224 tx.vin.push_back(txin);
227 static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
229 // separate VALUE:ADDRESS in string
230 size_t pos = strInput.find(':');
231 if ((pos == string::npos) ||
233 (pos == (strInput.size() - 1)))
234 throw runtime_error("TX output missing separator");
236 // extract and validate VALUE
237 string strValue = strInput.substr(0, pos);
239 if (!ParseMoney(strValue, value))
240 throw runtime_error("invalid TX output value");
242 // extract and validate ADDRESS
243 string strAddr = strInput.substr(pos + 1, string::npos);
244 CBitcoinAddress addr(strAddr);
246 throw runtime_error("invalid TX output address");
248 // build standard output script via GetScriptForDestination()
249 CScript scriptPubKey = GetScriptForDestination(addr.Get());
251 // construct TxOut, append to transaction output list
252 CTxOut txout(value, scriptPubKey);
253 tx.vout.push_back(txout);
256 static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput)
258 // separate VALUE:SCRIPT in string
259 size_t pos = strInput.find(':');
260 if ((pos == string::npos) ||
262 throw runtime_error("TX output missing separator");
264 // extract and validate VALUE
265 string strValue = strInput.substr(0, pos);
267 if (!ParseMoney(strValue, value))
268 throw runtime_error("invalid TX output value");
270 // extract and validate script
271 string strScript = strInput.substr(pos + 1, string::npos);
272 CScript scriptPubKey = ParseScript(strScript); // throws on err
274 // construct TxOut, append to transaction output list
275 CTxOut txout(value, scriptPubKey);
276 tx.vout.push_back(txout);
279 static void MutateTxDelInput(CMutableTransaction& tx, const string& strInIdx)
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());
288 // delete input from transaction
289 tx.vin.erase(tx.vin.begin() + inIdx);
292 static void MutateTxDelOutput(CMutableTransaction& tx, const string& strOutIdx)
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());
301 // delete output from transaction
302 tx.vout.erase(tx.vout.begin() + outIdx);
305 static const unsigned int N_SIGHASH_OPTS = 6;
306 static const struct {
309 } sighashOptions[N_SIGHASH_OPTS] = {
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},
318 static bool findSighashFlags(int& flags, const string& flagStr)
322 for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
323 if (flagStr == sighashOptions[i].flagStr) {
324 flags = sighashOptions[i].flags;
332 uint256 ParseHashUO(map<string,UniValue>& o, string strKey)
334 if (!o.count(strKey))
336 return ParseHashUV(o[strKey], strKey);
339 vector<unsigned char> ParseHexUO(map<string,UniValue>& o, string strKey)
341 if (!o.count(strKey)) {
342 vector<unsigned char> emptyVec;
345 return ParseHexUV(o[strKey], strKey);
348 static CAmount AmountFromValue(const UniValue& value)
350 if (!value.isNum() && !value.isStr())
351 throw runtime_error("Amount is not a number or string");
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");
360 static void MutateTxSign(CMutableTransaction& tx, const string& strInput)
362 // separate HEIGHT:SIGHASH-FLAGS in string
363 size_t pos = strInput.find(':');
365 (pos == (strInput.size() - 1)))
366 throw runtime_error("Invalid sighash flag separator");
368 // extract and validate HEIGHT
369 string strHeight = strInput.substr(0, pos);
370 int nHeight = atoi(strHeight);
372 throw runtime_error("invalid height");
375 // extract and validate SIGHASH-FLAGS
376 int nHashType = SIGHASH_ALL;
378 if (pos != string::npos) {
379 flagStr = strInput.substr(pos + 1, string::npos);
381 if (flagStr.size() > 0)
382 if (!findSighashFlags(nHashType, flagStr))
383 throw runtime_error("unknown sighash flag/sign option");
385 vector<CTransaction> txVariants;
386 txVariants.push_back(tx);
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;
393 CCoinsViewCache view(&viewDummy);
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"];
402 for (size_t kidx = 0; kidx < keysObj.size(); kidx++) {
403 if (!keysObj[kidx].isStr())
404 throw runtime_error("privatekey not a string");
405 CBitcoinSecret vchSecret;
406 bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
408 throw runtime_error("privatekey not valid");
410 CKey key = vchSecret.GetKey();
411 tempKeystore.AddKey(key);
414 // Add previous txouts given in the RPC call:
415 if (!registers.count("prevtxs"))
416 throw runtime_error("prevtxs register variable must be set.");
417 UniValue prevtxsObj = registers["prevtxs"];
419 for (size_t previdx = 0; previdx < prevtxsObj.size(); previdx++) {
420 UniValue prevOut = prevtxsObj[previdx];
421 if (!prevOut.isObject())
422 throw runtime_error("expected prevtxs internal object");
424 map<string,UniValue::VType> types = boost::assign::map_list_of("txid", UniValue::VSTR)("vout",UniValue::VNUM)("scriptPubKey",UniValue::VSTR);
425 if (!prevOut.checkObject(types))
426 throw runtime_error("prevtxs internal object typecheck fail");
428 uint256 txid = ParseHashUV(prevOut["txid"], "txid");
430 int nOut = atoi(prevOut["vout"].getValStr());
432 throw runtime_error("vout must be positive");
434 vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
435 CScript scriptPubKey(pkData.begin(), pkData.end());
438 CCoinsModifier coins = view.ModifyCoins(txid);
439 if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) {
440 string err("Previous output scriptPubKey mismatch:\n");
441 err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
442 scriptPubKey.ToString();
443 throw runtime_error(err);
445 if ((unsigned int)nOut >= coins->vout.size())
446 coins->vout.resize(nOut+1);
447 coins->vout[nOut].scriptPubKey = scriptPubKey;
448 coins->vout[nOut].nValue = 0;
449 if (prevOut.exists("amount")) {
450 coins->vout[nOut].nValue = AmountFromValue(prevOut["amount"]);
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);
466 const CKeyStore& keystore = tempKeystore;
468 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
470 // Grab the consensus branch ID for the given height
471 auto consensusBranchId = CurrentEpochBranchId(nHeight, Params().GetConsensus());
474 for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
475 CTxIn& txin = mergedTx.vin[i];
476 const CCoins* coins = view.AccessCoins(txin.prevout.hash);
477 if (!coins || !coins->IsAvailable(txin.prevout.n)) {
481 const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey;
482 const CAmount& amount = coins->vout[txin.prevout.n].nValue;
484 SignatureData sigdata;
485 // Only sign SIGHASH_SINGLE if there's a corresponding output:
486 if (!fHashSingle || (i < mergedTx.vout.size()))
487 ProduceSignature(MutableTransactionSignatureCreator(&keystore, &mergedTx, i, amount, nHashType), prevPubKey, sigdata, consensusBranchId);
489 // ... and merge in other signatures:
490 BOOST_FOREACH(const CTransaction& txv, txVariants)
491 sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i), consensusBranchId);
492 UpdateTransaction(mergedTx, i, sigdata);
494 if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i, amount), consensusBranchId))
499 // do nothing... for now
500 // perhaps store this for later optional JSON output
508 ECCVerifyHandle globalVerifyHandle;
519 static void MutateTx(CMutableTransaction& tx, const string& command,
520 const string& commandVal)
522 boost::scoped_ptr<Secp256k1Init> ecc;
524 if (command == "nversion")
525 MutateTxVersion(tx, commandVal);
526 else if (command == "locktime")
527 MutateTxLocktime(tx, commandVal);
528 else if (command == "expiry")
529 MutateTxExpiry(tx, commandVal);
531 else if (command == "delin")
532 MutateTxDelInput(tx, commandVal);
533 else if (command == "in")
534 MutateTxAddInput(tx, commandVal);
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);
543 else if (command == "sign") {
544 if (!ecc) { ecc.reset(new Secp256k1Init()); }
545 MutateTxSign(tx, commandVal);
548 else if (command == "load")
549 RegisterLoad(commandVal);
551 else if (command == "set")
552 RegisterSet(commandVal);
555 throw runtime_error("unknown command");
558 static void OutputTxJSON(const CTransaction& tx)
560 UniValue entry(UniValue::VOBJ);
561 TxToUniv(tx, uint256(), entry);
563 string jsonOutput = entry.write(4);
564 fprintf(stdout, "%s\n", jsonOutput.c_str());
567 static void OutputTxHash(const CTransaction& tx)
569 string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
571 fprintf(stdout, "%s\n", strHexHash.c_str());
574 static void OutputTxHex(const CTransaction& tx)
576 string strHex = EncodeHexTx(tx);
578 fprintf(stdout, "%s\n", strHex.c_str());
581 static void OutputTx(const CTransaction& tx)
583 if (GetBoolArg("-json", false))
585 else if (GetBoolArg("-txid", false))
591 static string readStdin()
596 while (!feof(stdin)) {
597 size_t bread = fread(buf, 1, sizeof(buf), stdin);
598 ret.append(buf, bread);
599 if (bread < sizeof(buf))
604 throw runtime_error("error reading stdin");
606 boost::algorithm::trim_right(ret);
611 static int CommandLineRawTx(int argc, char* argv[])
616 // Skip switches; Permit common stdin convention "-"
617 while (argc > 1 && IsSwitchChar(argv[1][0]) &&
623 CTransaction txDecodeTmp;
627 // require at least one param
629 throw runtime_error("too few parameters");
631 // param: hex-encoded bitcoin transaction
632 string strHexTx(argv[1]);
633 if (strHexTx == "-") // "-" implies standard input
634 strHexTx = readStdin();
636 if (!DecodeHexTx(txDecodeTmp, strHexTx))
637 throw runtime_error("invalid transaction encoding");
643 CMutableTransaction tx(txDecodeTmp);
645 for (int i = startArg; i < argc; i++) {
646 string arg = argv[i];
648 size_t eqpos = arg.find('=');
649 if (eqpos == string::npos)
652 key = arg.substr(0, eqpos);
653 value = arg.substr(eqpos + 1);
656 MutateTx(tx, key, value);
662 catch (const boost::thread_interrupted&) {
665 catch (const std::exception& e) {
666 strPrint = string("error: ") + e.what();
670 PrintExceptionContinue(NULL, "CommandLineRawTx()");
674 if (strPrint != "") {
675 fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
680 int main(int argc, char* argv[])
685 if(!AppInitRawTx(argc, argv))
688 catch (const std::exception& e) {
689 PrintExceptionContinue(&e, "AppInitRawTx()");
692 PrintExceptionContinue(NULL, "AppInitRawTx()");
696 int ret = EXIT_FAILURE;
698 ret = CommandLineRawTx(argc, argv);
700 catch (const std::exception& e) {
701 PrintExceptionContinue(&e, "CommandLineRawTx()");
703 PrintExceptionContinue(NULL, "CommandLineRawTx()");