6 #if defined(HAVE_CONFIG_H)
26 #include <boost/algorithm/string.hpp>
28 static bool fCreateBlank;
29 static std::map<std::string, UniValue> registers;
30 static const int CONTINUE_EXECUTION=-1;
36 static int AppInitRawTx(
int argc,
char*
argv[])
46 }
catch(
const std::exception& e) {
47 fprintf(stderr,
"Error: %s\n", e.what());
56 "Usage: pivx-tx [options] <hex-tx> [commands] Update hex-encoded pivx transaction\n" +
57 "or: pivx-tx [options] -create [commands] Create hex-encoded pivx transaction\n" +
60 fprintf(stdout,
"%s", strUsage.c_str());
66 strUsage +=
HelpMessageOpt(
"-txid",
"Output only the hex-encoded transaction id of the resultant transaction.");
67 strUsage +=
HelpMessageOpt(
"-regtest",
"Enter regression test mode, which uses a special chain in which blocks can be solved instantly.");
70 fprintf(stdout,
"%s", strUsage.c_str());
79 strUsage +=
HelpMessageOpt(
"outaddr=VALUE:ADDRESS",
"Add address-based output to TX");
80 strUsage +=
HelpMessageOpt(
"outscript=VALUE:SCRIPT",
"Add raw script output to TX");
81 strUsage +=
HelpMessageOpt(
"sign=SIGHASH-FLAGS",
"Add zero or more signatures to transaction. "
82 "This command requires JSON registers:"
83 "prevtxs=JSON object, "
84 "privatekeys=JSON object. "
85 "See signrawtransaction docs for format of sighash flags, JSON objects.");
86 fprintf(stdout,
"%s", strUsage.c_str());
89 strUsage +=
HelpMessageOpt(
"load=NAME:FILENAME",
"Load JSON file FILENAME into register NAME");
90 strUsage +=
HelpMessageOpt(
"set=NAME:JSON-STRING",
"Set register NAME to given JSON-STRING");
91 fprintf(stdout,
"%s", strUsage.c_str());
94 fprintf(stderr,
"Error: too few parameters\n");
99 return CONTINUE_EXECUTION;
102 static void RegisterSetJson(
const std::string& key,
const std::string& rawJson)
105 if (!val.
read(rawJson)) {
106 std::string strErr =
"Cannot parse JSON for key " + key;
107 throw std::runtime_error(strErr);
110 registers[key] = val;
113 static void RegisterSet(
const std::string& strInput)
116 size_t pos = strInput.find(
':');
117 if ((pos == std::string::npos) ||
119 (pos == (strInput.size() - 1)))
120 throw std::runtime_error(
"Register input requires NAME:VALUE");
122 std::string key = strInput.substr(0, pos);
123 std::string valStr = strInput.substr(pos + 1, std::string::npos);
125 RegisterSetJson(key, valStr);
128 static void RegisterLoad(
const std::string& strInput)
131 size_t pos = strInput.find(
':');
132 if ((pos == std::string::npos) ||
134 (pos == (strInput.size() - 1)))
135 throw std::runtime_error(
"Register load requires NAME:FILENAME");
137 std::string key = strInput.substr(0, pos);
138 std::string filename = strInput.substr(pos + 1, std::string::npos);
140 FILE* f =
fopen(filename.c_str(),
"r");
142 std::string strErr =
"Cannot open file " + filename;
143 throw std::runtime_error(strErr);
148 while ((!feof(f)) && (!ferror(f))) {
150 int bread = fread(buf, 1,
sizeof(buf), f);
154 valStr.insert(valStr.size(), buf, bread);
158 std::string strErr =
"Error reading file " + filename;
159 throw std::runtime_error(strErr);
165 RegisterSetJson(key, valStr);
168 static CAmount ExtractAndValidateValue(
const std::string& strValue)
172 throw std::runtime_error(
"invalid TX output value");
179 if (!
ParseInt64(cmdVal, &newVersion) || newVersion < 1 || newVersion >= CTransaction::TxVersion::TOOHIGH)
180 throw std::runtime_error(
"Invalid TX version requested: '" + cmdVal +
"'");
188 if (!
ParseInt64(cmdVal, &newLocktime) || newLocktime < 0LL || newLocktime > 0xffffffffLL)
189 throw std::runtime_error(
"Invalid TX locktime requested: '" + cmdVal +
"'");
191 tx.
nLockTime = (
unsigned int)newLocktime;
196 std::vector<std::string> vStrInputParts;
197 boost::split(vStrInputParts, strInput, boost::is_any_of(
":"));
200 if (vStrInputParts.size()<2)
201 throw std::runtime_error(
"TX input missing separator");
206 throw std::runtime_error(
"invalid TX input txid");
209 static const unsigned int minTxOutSz = 9;
210 unsigned int nMaxSize = MAX_BLOCK_SIZE_LEGACY;
211 static const unsigned int maxVout = nMaxSize / minTxOutSz;
214 const std::string& strVout = vStrInputParts[1];
216 if (!
ParseInt64(strVout, &vout) || vout < 0 || vout >
static_cast<int64_t
>(maxVout))
217 throw std::runtime_error(
"invalid TX input vout '" + strVout +
"'");
221 if (vStrInputParts.size() > 2)
222 nSequenceIn = std::stoul(vStrInputParts[2]);
225 tx.
vin.emplace_back(txid, vout,
CScript(), nSequenceIn);
231 std::vector<std::string> vStrInputParts;
232 boost::split(vStrInputParts, strInput, boost::is_any_of(
":"));
234 if (vStrInputParts.size() != 2)
235 throw std::runtime_error(
"TX output missing or too many separators");
238 CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
241 std::string strAddr = vStrInputParts[1];
244 throw std::runtime_error(
"invalid TX output address");
249 tx.
vout.emplace_back(value, scriptPubKey);
255 std::vector<std::string> vStrInputParts;
256 boost::split(vStrInputParts, strInput, boost::is_any_of(
":"));
258 if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
259 throw std::runtime_error(
"TX output missing or too many separators");
262 CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
266 if (!pubkey.IsFullyValid())
267 throw std::runtime_error(
"invalid TX output pubkey");
271 bool bScriptHash =
false;
272 if (vStrInputParts.size() == 3) {
273 std::string
flags = vStrInputParts[2];
274 bScriptHash = (
flags.find(
'S') != std::string::npos);
282 tx.
vout.emplace_back(value, scriptPubKey);
288 std::vector<std::string> vStrInputParts;
289 boost::split(vStrInputParts, strInput, boost::is_any_of(
":"));
292 if (vStrInputParts.size() < 3)
293 throw std::runtime_error(
"Not enough multisig parameters");
296 CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
299 uint32_t required = stoul(vStrInputParts[1]);
302 uint32_t numkeys = stoul(vStrInputParts[2]);
305 if (vStrInputParts.size() < numkeys + 3)
306 throw std::runtime_error(
"incorrect number of multisig pubkeys");
308 if (required < 1 || required > MAX_PUBKEYS_PER_MULTISIG || numkeys < 1 || numkeys > MAX_PUBKEYS_PER_MULTISIG || numkeys < required)
309 throw std::runtime_error(
"multisig parameter mismatch. Required " \
310 + std::to_string(required) +
" of " + std::to_string(numkeys) +
"signatures.");
313 std::vector<CPubKey> pubkeys;
314 for(
int pos = 1; pos <= int(numkeys); pos++) {
316 if (!pubkey.IsFullyValid())
317 throw std::runtime_error(
"invalid TX output pubkey");
318 pubkeys.push_back(pubkey);
322 bool bScriptHash =
false;
323 if (vStrInputParts.size() == numkeys + 4) {
324 std::string
flags = vStrInputParts.back();
325 bScriptHash = (
flags.find(
'S') != std::string::npos);
327 else if (vStrInputParts.size() > numkeys + 4) {
329 throw std::runtime_error(
"Too many parameters");
335 if (scriptPubKey.
size() > MAX_SCRIPT_ELEMENT_SIZE) {
337 "redeemScript exceeds size limit: %d > %d", scriptPubKey.
size(), MAX_SCRIPT_ELEMENT_SIZE));
344 tx.
vout.emplace_back(value, scriptPubKey);
350 std::vector<std::string> vStrInputParts;
351 boost::split(vStrInputParts, strInput, boost::is_any_of(
":"));
352 if (vStrInputParts.size() < 2)
353 throw std::runtime_error(
"TX output missing separator");
356 CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
359 std::string strScript = vStrInputParts[1];
362 if (scriptPubKey.
size() > MAX_SCRIPT_SIZE) {
364 "script exceeds size limit: %d > %d", scriptPubKey.
size(), MAX_SCRIPT_SIZE));
368 tx.
vout.emplace_back(value, scriptPubKey);
374 int inIdx =
atoi(strInIdx);
375 if (inIdx < 0 || inIdx >= (
int)tx.
vin.size()) {
376 std::string strErr =
"Invalid TX input index '" + strInIdx +
"'";
377 throw std::runtime_error(strErr.c_str());
381 tx.
vin.erase(tx.
vin.begin() + inIdx);
387 int outIdx =
atoi(strOutIdx);
388 if (outIdx < 0 || outIdx >= (
int)tx.
vout.size()) {
389 std::string strErr =
"Invalid TX output index '" + strOutIdx +
"'";
390 throw std::runtime_error(strErr.c_str());
394 tx.
vout.erase(tx.
vout.begin() + outIdx);
397 static const unsigned int N_SIGHASH_OPTS = 6;
398 static const struct {
401 } sighashOptions[N_SIGHASH_OPTS] = {
410 static bool findSighashFlags(
int&
flags,
const std::string&
flagStr)
414 for (
unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
416 flags = sighashOptions[i].flags;
424 static inline int64_t roundint64(
double d)
426 return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
432 throw std::runtime_error(
"Amount is not a number or string");
434 if (dAmount <= 0.0 || dAmount > 21000000.0)
435 throw std::runtime_error(
"Invalid amount");
436 CAmount nAmount = roundint64(dAmount * COIN);
437 if (!
Params().GetConsensus().MoneyRange(nAmount))
438 throw std::runtime_error(
"Amount out of range");
447 if (!findSighashFlags(nHashType,
flagStr))
448 throw std::runtime_error(
"unknown sighash flag/sign option");
450 std::vector<CTransaction> txVariants;
451 txVariants.push_back(tx);
456 bool fComplete =
true;
460 if (!registers.count(
"privatekeys"))
461 throw std::runtime_error(
"privatekeys register variable must be set.");
462 bool fGivenKeys =
false;
464 UniValue keysObj = registers[
"privatekeys"];
467 for (
unsigned int kidx = 0; kidx < keysObj.
size(); kidx++) {
468 if (!keysObj[kidx].isStr())
469 throw std::runtime_error(
"privatekey not a string");
472 throw std::runtime_error(
"privatekey not valid");
478 if (!registers.count(
"prevtxs"))
479 throw std::runtime_error(
"prevtxs register variable must be set.");
480 UniValue prevtxsObj = registers[
"prevtxs"];
482 for (
unsigned int previdx = 0; previdx < prevtxsObj.
size(); previdx++) {
483 UniValue prevOut = prevtxsObj[previdx];
485 throw std::runtime_error(
"expected prevtxs internal object");
487 std::map<std::string, UniValue::VType> types = {
493 throw std::runtime_error(
"prevtxs internal object typecheck fail");
497 int nOut =
atoi(prevOut[
"vout"].getValStr());
499 throw std::runtime_error(
"vout must be positive");
502 std::vector<unsigned char> pkData(
ParseHexUV(prevOut[
"scriptPubKey"],
"scriptPubKey"));
503 CScript scriptPubKey(pkData.begin(), pkData.end());
506 const Coin& coin = view.AccessCoin(out);
508 std::string err(
"Previous output scriptPubKey mismatch:\n");
511 throw std::runtime_error(err);
518 if (prevOut.
exists(
"amount")) {
519 newcoin.
out.
nValue = AmountFromValue(prevOut[
"amount"]);
526 prevOut.
exists(
"redeemScript")) {
527 UniValue v = prevOut[
"redeemScript"];
528 std::vector<unsigned char> rsData(
ParseHexUV(v,
"redeemScript"));
529 CScript redeemScript(rsData.begin(), rsData.end());
535 const CKeyStore& keystore = tempKeystore;
540 for (
unsigned int i = 0; i < mergedTx.vin.size(); i++) {
541 CTxIn& txin = mergedTx.vin[i];
552 SigVersion sigversion = mergedTx.GetRequiredSigVersion();
554 if (!fHashSingle || (i < mergedTx.vout.size()))
594 static void MutateTx(
CMutableTransaction& tx,
const std::string& command,
const std::string& commandVal)
596 std::unique_ptr<Secp256k1Init> ecc;
597 if (command ==
"nversion") {
598 MutateTxVersion(tx, commandVal);
599 }
else if (command ==
"locktime") {
600 MutateTxLocktime(tx, commandVal);
601 }
else if (command ==
"delin") {
602 MutateTxDelInput(tx, commandVal);
603 }
else if (command ==
"in") {
604 MutateTxAddInput(tx, commandVal);
605 }
else if (command ==
"delout") {
606 MutateTxDelOutput(tx, commandVal);
607 }
else if (command ==
"outaddr") {
608 MutateTxAddOutAddr(tx, commandVal);
609 }
else if (command ==
"outpubkey") {
611 MutateTxAddOutPubKey(tx, commandVal);
612 }
else if (command ==
"outmultisig") {
614 MutateTxAddOutMultiSig(tx, commandVal);
615 }
else if (command ==
"outscript") {
616 MutateTxAddOutScript(tx, commandVal);
617 }
else if (command ==
"sign") {
619 MutateTxSign(tx, commandVal);
620 }
else if (command ==
"load") {
621 RegisterLoad(commandVal);
622 }
else if (command ==
"set") {
623 RegisterSet(commandVal);
625 throw std::runtime_error(
"unknown command");
634 std::string jsonOutput = entry.write(4);
635 fprintf(stdout,
"%s\n", jsonOutput.c_str());
642 fprintf(stdout,
"%s\n", strHexHash.c_str());
649 fprintf(stdout,
"%s\n", strHex.c_str());
662 static std::string readStdin()
667 while (!feof(stdin)) {
668 size_t bread = fread(buf, 1,
sizeof(buf), stdin);
669 ret.append(buf, bread);
670 if (bread <
sizeof(buf))
675 throw std::runtime_error(
"error reading stdin");
677 boost::algorithm::trim_right(ret);
682 static int CommandLineRawTx(
int argc,
char*
argv[])
684 std::string strPrint;
700 throw std::runtime_error(
"too few parameters");
703 std::string strHexTx(
argv[1]);
705 strHexTx = readStdin();
708 throw std::runtime_error(
"invalid transaction encoding");
714 for (
int i = startArg; i < argc; i++) {
715 std::string arg =
argv[i];
716 std::string key, value;
717 size_t eqpos = arg.find(
'=');
718 if (eqpos == std::string::npos)
721 key = arg.substr(0, eqpos);
722 value = arg.substr(eqpos + 1);
725 MutateTx(tx, key, value);
731 catch (
const boost::thread_interrupted&) {
733 }
catch (
const std::exception& e) {
734 strPrint = std::string(
"error: ") + e.what();
741 if (strPrint !=
"") {
742 fprintf((nRet == 0 ? stdout : stderr),
"%s\n", strPrint.c_str());
752 int ret = AppInitRawTx(argc,
argv);
753 if (ret != CONTINUE_EXECUTION)
755 }
catch (
const std::exception& e) {
763 int ret = EXIT_FAILURE;
765 ret = CommandLineRawTx(argc,
argv);
766 }
catch (
const std::exception& e) {
int64_t CAmount
Amount in PIV (Can be negative)
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given chain name.
const CChainParams & Params()
Return the currently selected parameters.
void ParseParameters(int argc, const char *const argv[])
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Basic key store, that keeps keys in an address->secret map.
virtual bool AddCScript(const CScript &redeemScript)
Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki.
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Abstract view on the open txout dataset.
An encapsulated private key.
bool IsValid() const
Check whether this private key is valid.
A virtual base class for key stores.
virtual bool AddKey(const CKey &key)
An outpoint - a combination of a transaction hash and an index n into its vout.
An encapsulated public key.
Serialized script, used inside transaction inputs and outputs.
bool IsPayToScriptHash() const
A reference to a CScript: the Hash160 of its serialization (see script.h)
The basic transaction that is broadcasted on the network and contained in blocks.
const uint256 & GetHash() const
An input of a transaction.
static const uint32_t SEQUENCE_FINAL
CTxOut out
unspent transaction output
uint32_t nHeight
at which height the containing transaction was included in the active block chain
Users of this module must hold an ECCVerifyHandle.
ECCVerifyHandle globalVerifyHandle
bool checkObject(const std::map< std::string, UniValue::VType > &memberTypes) const
bool exists(const std::string &key) const
bool read(const char *raw, size_t len)
std::string GetHex() const
std::string FormatFullVersion()
std::string EncodeHexTx(const CTransaction &tx)
CScript ParseScript(std::string s)
bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
std::vector< unsigned char > ParseHexUV(const UniValue &v, const std::string &strName)
std::string ScriptToAsmStr(const CScript &script, const bool fAttemptSighashDecode=false)
Create the assembly string representation of a CScript object.
uint256 ParseHashStr(const std::string &, const std::string &strName)
uint256 ParseHashUV(const UniValue &v, const std::string &strName)
void TxToUniv(const CTransaction &tx, const uint256 &hashBlock, UniValue &entry)
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, unsigned int flags, const BaseSignatureChecker &checker, SigVersion sigversion, ScriptError *serror)
void ECC_Start()
Initialize the elliptic curve support.
void ECC_Stop()
Deinitialize the elliptic curve support.
CKey DecodeSecret(const std::string &str)
bool IsValidDestination(const CWDestination &address)
CWDestination DecodeDestination(const std::string &strAddress)
FILE * fopen(const fs::path &p, const char *mode)
int main(int argc, char *argv[])
void UpdateTransaction(CMutableTransaction &tx, unsigned int nIn, const SignatureData &data)
SignatureData DataFromTransaction(const CMutableTransaction &tx, unsigned int nIn)
Extract signature data from a transaction, and insert it.
SignatureData CombineSignatures(const CScript &scriptPubKey, const BaseSignatureChecker &checker, const SignatureData &scriptSig1, const SignatureData &scriptSig2)
Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 pl...
bool ProduceSignature(const BaseSignatureCreator &creator, const CScript &fromPubKey, SignatureData &sigdata, SigVersion sigversion, bool fColdStake, ScriptError *serror)
Produce a script signature using a generic signature creator.
CScript GetScriptForMultisig(int nRequired, const std::vector< CPubKey > &keys)
Generate a multisig script.
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
A mutable version of CTransaction.
std::vector< CTxOut > vout
void PrintExceptionContinue(const std::exception *pex, const char *pszThread)
std::string HelpMessageGroup(const std::string &message)
Format a string to be used as group of options in help messages.
std::string HelpMessageOpt(const std::string &option, const std::string &message)
Format a string to be used as option description in help messages.
bool IsSwitchChar(char c)
const uint256 UINT256_ZERO
constant uint256 instances
bool ParseMoney(const std::string &str, CAmount &nRet)
std::vector< unsigned char > ParseHex(const char *psz)
int atoi(const std::string &str)
bool ParseInt64(const std::string &str, int64_t *out)
Convert string to signed 64-bit integer with strict parse error feedback.