24 #include <boost/algorithm/string.hpp>
25 #include <boost/assign/list_of.hpp>
27 #define MAX_FILE_LENGTH (1024 * 1024) // 1MB
30 static bool fCreateBlank;
31 static std::map<std::string, UniValue> registers;
34 static bool AppInitRawTx(
int argc,
char* argv[])
43 fprintf(stderr,
"Error: Invalid combination of -regtest and -testnet.\n");
51 std::string strUsage =
_(
"PRCY prcycoin-tx utility version") +
" " +
FormatFullVersion() +
"\n\n" +
53 " prcycoin-tx [options] <hex-tx> [commands] " +
_(
"Update hex-encoded prcycoin transaction") +
"\n" +
54 " prcycoin-tx [options] -create [commands] " +
_(
"Create hex-encoded prcycoin transaction") +
"\n" +
57 fprintf(stdout,
"%s", strUsage.c_str());
63 strUsage +=
HelpMessageOpt(
"-txid",
_(
"Output only the hex-encoded transaction id of the resultant transaction."));
64 strUsage +=
HelpMessageOpt(
"-regtest",
_(
"Enter regression test mode, which uses a special chain in which blocks can be solved instantly."));
67 fprintf(stdout,
"%s", strUsage.c_str());
76 strUsage +=
HelpMessageOpt(
"outaddr=VALUE:ADDRESS",
_(
"Add address-based output to TX"));
77 strUsage +=
HelpMessageOpt(
"outscript=VALUE:SCRIPT",
_(
"Add raw script output to TX"));
78 strUsage +=
HelpMessageOpt(
"sign=SIGHASH-FLAGS",
_(
"Add zero or more signatures to transaction") +
". " +
79 _(
"This command requires JSON registers:") +
80 _(
"prevtxs=JSON object") +
", " +
81 _(
"privatekeys=JSON object") +
". " +
82 _(
"See signrawtransaction docs for format of sighash flags, JSON objects."));
83 fprintf(stdout,
"%s", strUsage.c_str());
86 strUsage +=
HelpMessageOpt(
"load=NAME:FILENAME",
_(
"Load JSON file FILENAME into register NAME"));
87 strUsage +=
HelpMessageOpt(
"set=NAME:JSON-STRING",
_(
"Set register NAME to given JSON-STRING"));
88 fprintf(stdout,
"%s", strUsage.c_str());
95 static void RegisterSetJson(
const std::string&
key,
const std::string& rawJson)
98 if (!val.
read(rawJson)) {
99 std::string strErr =
"Cannot parse JSON for key " +
key;
100 throw std::runtime_error(strErr);
103 registers[
key] = val;
106 static void RegisterSet(
const std::string& strInput)
109 size_t pos = strInput.find(
':');
110 if ((pos == std::string::npos) ||
112 (pos == (strInput.size() - 1)))
113 throw std::runtime_error(
"Register input requires NAME:VALUE");
115 std::string
key = strInput.substr(0, pos);
116 std::string valStr = strInput.substr(pos + 1, std::string::npos);
118 RegisterSetJson(
key, valStr);
121 static void RegisterLoad(
const std::string& strInput)
124 size_t pos = strInput.find(
':');
125 if ((pos == std::string::npos) ||
127 (pos == (strInput.size() - 1)))
128 throw std::runtime_error(
"Register load requires NAME:FILENAME");
130 std::string
key = strInput.substr(0, pos);
131 std::string filename = strInput.substr(pos + 1, std::string::npos);
135 std::string strErr =
"Cannot open file " + filename;
136 throw std::runtime_error(strErr);
144 int bread = fread(buf, 1,
sizeof(buf), f);
148 totalLength += bread;
149 valStr.insert(valStr.size(), buf, bread);
153 std::string strErr =
"Error reading file " + filename;
154 throw std::runtime_error(strErr);
158 std::string strErr =
"Error reading big file " + filename;
159 throw std::runtime_error(strErr);
165 RegisterSetJson(
key, valStr);
170 int64_t newVersion =
atoi64(cmdVal);
172 throw std::runtime_error(
"Invalid TX version requested");
179 int64_t newLocktime =
atoi64(cmdVal);
180 if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
181 throw std::runtime_error(
"Invalid TX locktime requested");
183 tx.
nLockTime = (
unsigned int)newLocktime;
189 size_t pos = strInput.find(
':');
190 if ((pos == std::string::npos) ||
192 (pos == (strInput.size() - 1)))
193 throw std::runtime_error(
"TX input missing separator");
196 std::string strTxid = strInput.substr(0, pos);
197 if ((strTxid.size() != 64) || !
IsHex(strTxid))
198 throw std::runtime_error(
"invalid TX input txid");
201 static const unsigned int minTxOutSz = 9;
202 unsigned int nMaxSize = MAX_BLOCK_SIZE_LEGACY;
203 static const unsigned int maxVout = nMaxSize / minTxOutSz;
206 std::string strVout = strInput.substr(pos + 1, std::string::npos);
207 int vout =
atoi(strVout);
208 if ((vout < 0) || (vout > (
int)maxVout))
209 throw std::runtime_error(
"invalid TX input vout");
212 CTxIn txin(txid, vout);
213 tx.
vin.push_back(txin);
219 size_t pos = strInput.find(
':');
220 if ((pos == std::string::npos) ||
222 (pos == (strInput.size() - 1)))
223 throw std::runtime_error(
"TX output missing separator");
226 std::string strValue = strInput.substr(0, pos);
229 throw std::runtime_error(
"invalid TX output value");
232 std::string strAddr = strInput.substr(pos + 1, std::string::npos);
235 throw std::runtime_error(
"invalid TX output address");
241 CTxOut txout(value, scriptPubKey);
242 tx.
vout.push_back(txout);
248 size_t pos = strInput.find(
':');
249 if ((pos == std::string::npos) ||
251 throw std::runtime_error(
"TX output missing separator");
254 std::string strValue = strInput.substr(0, pos);
257 throw std::runtime_error(
"invalid TX output value");
260 std::string strScript = strInput.substr(pos + 1, std::string::npos);
264 CTxOut txout(value, scriptPubKey);
265 tx.
vout.push_back(txout);
271 int inIdx =
atoi(strInIdx);
272 if (inIdx < 0 || inIdx >= (
int)tx.
vin.size()) {
273 std::string strErr =
"Invalid TX input index '" + strInIdx +
"'";
274 throw std::runtime_error(strErr.c_str());
278 tx.
vin.erase(tx.
vin.begin() + inIdx);
284 int outIdx =
atoi(strOutIdx);
285 if (outIdx < 0 || outIdx >= (
int)tx.
vout.size()) {
286 std::string strErr =
"Invalid TX output index '" + strOutIdx +
"'";
287 throw std::runtime_error(strErr.c_str());
291 tx.
vout.erase(tx.
vout.begin() + outIdx);
294 static const unsigned int N_SIGHASH_OPTS = 6;
295 static const struct {
298 } sighashOptions[N_SIGHASH_OPTS] = {
307 static bool findSighashFlags(
int&
flags,
const std::string&
flagStr)
311 for (
unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
313 flags = sighashOptions[i].flags;
323 if (!o.count(strKey))
328 std::vector<unsigned char>
ParseHexUO(std::map<std::string, UniValue>& o, std::string strKey)
330 if (!o.count(strKey)) {
331 std::vector<unsigned char> emptyVec;
342 if (!findSighashFlags(nHashType,
flagStr))
343 throw std::runtime_error(
"unknown sighash flag/sign option");
345 std::vector<CTransaction> txVariants;
346 txVariants.push_back(tx);
351 bool fComplete =
true;
355 if (!registers.count(
"privatekeys"))
356 throw std::runtime_error(
"privatekeys register variable must be set.");
357 bool fGivenKeys =
false;
359 UniValue keysObj = registers[
"privatekeys"];
362 for (
unsigned int kidx = 0; kidx < keysObj.
size(); kidx++) {
363 if (!keysObj[kidx].isStr())
364 throw std::runtime_error(
"privatekey not a string");
366 bool fGood = vchSecret.
SetString(keysObj[kidx].getValStr());
368 throw std::runtime_error(
"privatekey not valid");
375 if (!registers.count(
"prevtxs"))
376 throw std::runtime_error(
"prevtxs register variable must be set.");
377 UniValue prevtxsObj = registers[
"prevtxs"];
379 for (
unsigned int previdx = 0; previdx < prevtxsObj.
size(); previdx++) {
380 UniValue prevOut = prevtxsObj[previdx];
382 throw std::runtime_error(
"expected prevtxs internal object");
386 throw std::runtime_error(
"prevtxs internal object typecheck fail");
390 int nOut =
atoi(prevOut[
"vout"].getValStr());
392 throw std::runtime_error(
"vout must be positive");
394 std::vector<unsigned char> pkData(
ParseHexUV(prevOut[
"scriptPubKey"],
"scriptPubKey"));
395 CScript scriptPubKey(pkData.begin(), pkData.end());
399 if (coins->
IsAvailable(nOut) && coins->
vout[nOut].scriptPubKey != scriptPubKey) {
400 std::string err(
"Previous output scriptPubKey mismatch:\n");
401 err = err + coins->
vout[nOut].scriptPubKey.ToString() +
"\nvs:\n" +
403 throw std::runtime_error(err);
405 if ((
unsigned int)nOut >= coins->
vout.size())
406 coins->
vout.resize(nOut + 1);
407 coins->
vout[nOut].scriptPubKey = scriptPubKey;
408 coins->
vout[nOut].nValue = 0;
414 prevOut.
exists(
"redeemScript")) {
415 UniValue v = prevOut[
"redeemScript"];
416 std::vector<unsigned char> rsData(
ParseHexUV(v,
"redeemScript"));
417 CScript redeemScript(rsData.begin(), rsData.end());
423 const CKeyStore& keystore = tempKeystore;
428 for (
unsigned int i = 0; i < mergedTx.vin.size(); i++) {
429 CTxIn& txin = mergedTx.vin[i];
439 if (!fHashSingle || (i < mergedTx.vout.size()))
458 static void MutateTx(
CMutableTransaction& tx,
const std::string& command,
const std::string& commandVal)
460 if (command ==
"nversion")
461 MutateTxVersion(tx, commandVal);
462 else if (command ==
"locktime")
463 MutateTxLocktime(tx, commandVal);
465 else if (command ==
"delin")
466 MutateTxDelInput(tx, commandVal);
467 else if (command ==
"in")
468 MutateTxAddInput(tx, commandVal);
470 else if (command ==
"delout")
471 MutateTxDelOutput(tx, commandVal);
472 else if (command ==
"outaddr")
473 MutateTxAddOutAddr(tx, commandVal);
474 else if (command ==
"outscript")
475 MutateTxAddOutScript(tx, commandVal);
477 else if (command ==
"sign")
478 MutateTxSign(tx, commandVal);
480 else if (command ==
"load")
481 RegisterLoad(commandVal);
483 else if (command ==
"set")
484 RegisterSet(commandVal);
487 throw std::runtime_error(
"unknown command");
495 std::string jsonOutput = entry.write(4);
496 fprintf(stdout,
"%s\n", jsonOutput.c_str());
503 fprintf(stdout,
"%s\n", strHexHash.c_str());
510 fprintf(stdout,
"%s\n", strHex.c_str());
523 static std::string readStdin()
530 size_t bread = fread(buf, 1,
sizeof(buf), stdin);
531 ret.append(buf, bread);
532 if (bread <
sizeof(buf))
535 totalLength += bread;
539 throw std::runtime_error(
"error reading stdin");
541 throw std::runtime_error(
"error reading stdin max length");
543 boost::algorithm::trim_right(ret);
548 static int CommandLineRawTx(
int argc,
char* argv[])
550 std::string strPrint;
566 throw std::runtime_error(
"too few parameters");
569 std::string strHexTx(argv[1]);
571 strHexTx = readStdin();
574 throw std::runtime_error(
"invalid transaction encoding");
582 for (
int i = startArg; i < argc; i++) {
583 std::string arg = argv[i];
584 std::string
key, value;
585 size_t eqpos = arg.find(
'=');
586 if (eqpos == std::string::npos)
589 key = arg.substr(0, eqpos);
590 value = arg.substr(eqpos + 1);
593 MutateTx(tx,
key, value);
599 catch (
const boost::thread_interrupted&) {
601 }
catch (
const std::exception& e) {
602 strPrint = std::string(
"error: ") + e.what();
609 if (strPrint !=
"") {
610 fprintf((nRet == 0 ? stdout : stderr),
"%s\n", strPrint.c_str());
615 int main(
int argc,
char* argv[])
620 if (!AppInitRawTx(argc, argv))
622 }
catch (
const std::exception& e) {
630 int ret = EXIT_FAILURE;
632 ret = CommandLineRawTx(argc, argv);
633 }
catch (
const std::exception& e) {