LCOV - code coverage report
Current view: top level - src - bitcoin-tx.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 228 359 63.5 %
Date: 2015-10-12 22:39:14 Functions: 20 28 71.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11