dash/src/dash-tx.cpp

806 lines
26 KiB
C++
Raw Normal View History

// Copyright (c) 2009-2015 The Bitcoin Core developers
2014-12-13 05:09:33 +01:00
// Distributed under the MIT software license, see the accompanying
2015-04-03 00:51:08 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
Merge #7192: Unify product name to as few places as possible 027fdb8 When/if the copyright line does not mention Bitcoin Core developers, add a second line to copyrights in -version, About dialog, and splash screen (Luke Dashjr) cc2095e Rewrite FormatParagraph to handle newlines within input strings correctly (Luke Dashjr) cddffaf Bugfix: Include COPYRIGHT_HOLDERS_SUBSTITUTION in Makefile substitutions so it gets passed to extract-strings correctly (Luke Dashjr) 29598e4 Move PACKAGE_URL to configure.ac (Luke Dashjr) 78ec83d splashscreen: Resize text to fit exactly (Luke Dashjr) 3cae140 Bugfix: Actually use _COPYRIGHT_HOLDERS_SUBSTITUTION everywhere (Luke Dashjr) 4d5a3df Bugfix: gitian-descriptors: Add missing python-setuptools requirement for OS X (biplist module) (Luke Dashjr) e4ab5e5 Bugfix: Correct copyright year in Mac DMG background image (Luke Dashjr) 917b1d0 Set copyright holders displayed in notices separately from the package name (Luke Dashjr) c39a6ff Travis & gitian-osx: Use depends for ds_store and mac_alias modules (Luke Dashjr) 902ccde depends: Add mac_alias to depends (Luke Dashjr) 82a2d98 depends: Add ds_store to depends (Cory Fields) de619a3 depends: Pass PYTHONPATH along to configure (Cory Fields) e611b6e macdeploy: Use rsvg-convert rather than cairosvg (Luke Dashjr) 63bcdc5 More complicated package name substitution for Mac deployment (Luke Dashjr) 1a6c67c Parameterise 2009 in translatable copyright strings (Luke Dashjr) d5f4683 Unify package name to as few places as possible without major changes (Luke Dashjr)
2016-02-04 13:41:58 +01:00
#if defined(HAVE_CONFIG_H)
#include "config/dash-config.h"
#endif
2015-04-03 00:51:08 +02:00
#include "base58.h"
#include "clientversion.h"
#include "coins.h"
#include "consensus/consensus.h"
#include "core_io.h"
2015-04-03 00:51:08 +02:00
#include "keystore.h"
#include "policy/policy.h"
#include "primitives/transaction.h"
2015-04-03 00:51:08 +02:00
#include "script/script.h"
#include "script/sign.h"
#include <univalue.h>
2015-04-03 00:51:08 +02:00
#include "util.h"
#include "utilmoneystr.h"
#include "utilstrencodings.h"
2015-04-03 00:51:08 +02:00
#include <stdio.h>
#include <boost/algorithm/string.hpp>
#include "stacktraces.h"
2015-04-03 00:51:08 +02:00
static bool fCreateBlank;
static std::map<std::string,UniValue> registers;
static const int CONTINUE_EXECUTION=-1;
2015-04-03 00:51:08 +02:00
//
// This function returns either one of EXIT_ codes when it's expected to stop the process or
// CONTINUE_EXECUTION when it's expected to continue further.
//
static int AppInitRawTx(int argc, char* argv[])
2015-04-03 00:51:08 +02:00
{
//
// Parameters
//
gArgs.ParseParameters(argc, argv);
2015-04-03 00:51:08 +02:00
Enable stacktrace support in gitian builds (#3006) * Remove use of -rdynamic This causes check-symbols to fail horribly and also turned out to be not required when using libbacktrace. It was only required when using "backtrace()" from "<execinfo.h>" * Remove spurious ], from configure.ac * Add -DENABLE_STACKTRACES=1 to CMakeLists.txt * Remove unused method my_backtrace_simple_callback * Use fs::path().filename() instead of basename() * Add static g_exeFileName and g_exeFileBaseName * Use .exe.dbg file when available * Use uint64_t instead of uintptr_t * Implement GetBaseAddress() for unix and win32 * Implement unified crash_info and use it everywhere before printing crash info * Print a serialized version of crash_info when there is no debug info * Implement "-printcrashinfo" command line option * Compile stacktrace support unconditionally and only make crash hooks conditional This also renames the --enable-stacktraces option to --enable-crash-hooks * Enable crash hooks in win/linux Gitian builds * Try to load .debug file on MacOS and enable crash hooks for osx Gitian builds * Check for dsymutil and if it needs --flat * Create .debug files in osx Gitian build * Handle review comments * Also print crash description when no stacktrace is available * Unconditionally add -g1 debug information Instead of making it dependent on "--enable-crash-hooks". We will need the debug info every time now, even in release builds. * Put MacOS debug info into dSYM symbols instead of plain .debug files * Implement MacOS specific GetBaseAddress
2019-07-02 06:16:11 +02:00
if (gArgs.IsArgSet("-printcrashinfo")) {
std::cout << GetCrashInfoStrFromSerializedStr(gArgs.GetArg("-printcrashinfo", "")) << std::endl;
return true;
}
2015-04-03 00:51:08 +02:00
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
SelectParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
return EXIT_FAILURE;
2015-04-03 00:51:08 +02:00
}
fCreateBlank = gArgs.GetBoolArg("-create", false);
2015-04-03 00:51:08 +02:00
if (argc<2 || gArgs.IsArgSet("-?") || gArgs.IsArgSet("-h") || gArgs.IsArgSet("-help"))
2015-04-03 00:51:08 +02:00
{
// First part of help message is specific to this utility
Merge #7192: Unify product name to as few places as possible 027fdb8 When/if the copyright line does not mention Bitcoin Core developers, add a second line to copyrights in -version, About dialog, and splash screen (Luke Dashjr) cc2095e Rewrite FormatParagraph to handle newlines within input strings correctly (Luke Dashjr) cddffaf Bugfix: Include COPYRIGHT_HOLDERS_SUBSTITUTION in Makefile substitutions so it gets passed to extract-strings correctly (Luke Dashjr) 29598e4 Move PACKAGE_URL to configure.ac (Luke Dashjr) 78ec83d splashscreen: Resize text to fit exactly (Luke Dashjr) 3cae140 Bugfix: Actually use _COPYRIGHT_HOLDERS_SUBSTITUTION everywhere (Luke Dashjr) 4d5a3df Bugfix: gitian-descriptors: Add missing python-setuptools requirement for OS X (biplist module) (Luke Dashjr) e4ab5e5 Bugfix: Correct copyright year in Mac DMG background image (Luke Dashjr) 917b1d0 Set copyright holders displayed in notices separately from the package name (Luke Dashjr) c39a6ff Travis & gitian-osx: Use depends for ds_store and mac_alias modules (Luke Dashjr) 902ccde depends: Add mac_alias to depends (Luke Dashjr) 82a2d98 depends: Add ds_store to depends (Cory Fields) de619a3 depends: Pass PYTHONPATH along to configure (Cory Fields) e611b6e macdeploy: Use rsvg-convert rather than cairosvg (Luke Dashjr) 63bcdc5 More complicated package name substitution for Mac deployment (Luke Dashjr) 1a6c67c Parameterise 2009 in translatable copyright strings (Luke Dashjr) d5f4683 Unify package name to as few places as possible without major changes (Luke Dashjr)
2016-02-04 13:41:58 +01:00
std::string strUsage = strprintf(_("%s dash-tx utility version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n\n" +
2015-04-03 00:51:08 +02:00
_("Usage:") + "\n" +
2015-04-05 23:56:58 +02:00
" dash-tx [options] <hex-tx> [commands] " + _("Update hex-encoded dash transaction") + "\n" +
" dash-tx [options] -create [commands] " + _("Create hex-encoded dash transaction") + "\n" +
2015-04-03 00:51:08 +02:00
"\n";
fprintf(stdout, "%s", strUsage.c_str());
strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("This help message"));
strUsage += HelpMessageOpt("-create", _("Create new, empty TX."));
strUsage += HelpMessageOpt("-json", _("Select JSON output"));
strUsage += HelpMessageOpt("-txid", _("Output only the hex-encoded transaction id of the resultant transaction."));
AppendParamsHelpMessages(strUsage);
2015-04-03 00:51:08 +02:00
fprintf(stdout, "%s", strUsage.c_str());
strUsage = HelpMessageGroup(_("Commands:"));
strUsage += HelpMessageOpt("delin=N", _("Delete input N from TX"));
strUsage += HelpMessageOpt("delout=N", _("Delete output N from TX"));
strUsage += HelpMessageOpt("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX"));
strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
strUsage += HelpMessageOpt("outpubkey=VALUE:PUBKEY[:FLAGS]", _("Add pay-to-pubkey output to TX") + ". " +
_("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."));
strUsage += HelpMessageOpt("outdata=[VALUE:]DATA", _("Add data-based output to TX"));
strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT[:FLAGS]", _("Add raw script output to TX") + ". " +
_("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."));
strUsage += HelpMessageOpt("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", _("Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS") + ". " +
_("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."));
strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
_("This command requires JSON registers:") +
_("prevtxs=JSON object") + ", " +
_("privatekeys=JSON object") + ". " +
_("See signrawtransaction docs for format of sighash flags, JSON objects."));
2015-04-03 00:51:08 +02:00
fprintf(stdout, "%s", strUsage.c_str());
strUsage = HelpMessageGroup(_("Register Commands:"));
strUsage += HelpMessageOpt("load=NAME:FILENAME", _("Load JSON file FILENAME into register NAME"));
strUsage += HelpMessageOpt("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING"));
2015-04-03 00:51:08 +02:00
fprintf(stdout, "%s", strUsage.c_str());
if (argc < 2) {
fprintf(stderr, "Error: too few parameters\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
2015-04-03 00:51:08 +02:00
}
return CONTINUE_EXECUTION;
2015-04-03 00:51:08 +02:00
}
static void RegisterSetJson(const std::string& key, const std::string& rawJson)
2015-04-03 00:51:08 +02:00
{
UniValue val;
if (!val.read(rawJson)) {
std::string strErr = "Cannot parse JSON for key " + key;
throw std::runtime_error(strErr);
2015-04-03 00:51:08 +02:00
}
registers[key] = val;
}
static void RegisterSet(const std::string& strInput)
2015-04-03 00:51:08 +02:00
{
// separate NAME:VALUE in string
size_t pos = strInput.find(':');
if ((pos == std::string::npos) ||
2015-04-03 00:51:08 +02:00
(pos == 0) ||
(pos == (strInput.size() - 1)))
throw std::runtime_error("Register input requires NAME:VALUE");
2015-04-03 00:51:08 +02:00
std::string key = strInput.substr(0, pos);
std::string valStr = strInput.substr(pos + 1, std::string::npos);
2015-04-03 00:51:08 +02:00
RegisterSetJson(key, valStr);
}
static void RegisterLoad(const std::string& strInput)
2015-04-03 00:51:08 +02:00
{
// separate NAME:FILENAME in string
size_t pos = strInput.find(':');
if ((pos == std::string::npos) ||
2015-04-03 00:51:08 +02:00
(pos == 0) ||
(pos == (strInput.size() - 1)))
throw std::runtime_error("Register load requires NAME:FILENAME");
2015-04-03 00:51:08 +02:00
std::string key = strInput.substr(0, pos);
std::string filename = strInput.substr(pos + 1, std::string::npos);
2015-04-03 00:51:08 +02:00
FILE *f = fopen(filename.c_str(), "r");
if (!f) {
std::string strErr = "Cannot open file " + filename;
throw std::runtime_error(strErr);
2015-04-03 00:51:08 +02:00
}
// load file chunks into one big buffer
std::string valStr;
2015-04-03 00:51:08 +02:00
while ((!feof(f)) && (!ferror(f))) {
char buf[4096];
int bread = fread(buf, 1, sizeof(buf), f);
if (bread <= 0)
break;
valStr.insert(valStr.size(), buf, bread);
}
int error = ferror(f);
fclose(f);
if (error) {
std::string strErr = "Error reading file " + filename;
throw std::runtime_error(strErr);
2015-04-03 00:51:08 +02:00
}
// evaluate as JSON buffer register
RegisterSetJson(key, valStr);
}
static CAmount ExtractAndValidateValue(const std::string& strValue)
{
CAmount value;
if (!ParseMoney(strValue, value))
throw std::runtime_error("invalid TX output value");
return value;
}
static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
2015-04-03 00:51:08 +02:00
{
int64_t newVersion = atoi64(cmdVal);
if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
throw std::runtime_error("Invalid TX version requested");
2015-04-03 00:51:08 +02:00
tx.nVersion = (int) newVersion;
}
static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
2015-04-03 00:51:08 +02:00
{
int64_t newLocktime = atoi64(cmdVal);
if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
throw std::runtime_error("Invalid TX locktime requested");
2015-04-03 00:51:08 +02:00
tx.nLockTime = (unsigned int) newLocktime;
}
static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInput)
2015-04-03 00:51:08 +02:00
{
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
2015-04-03 00:51:08 +02:00
// separate TXID:VOUT in string
if (vStrInputParts.size()<2)
throw std::runtime_error("TX input missing separator");
2015-04-03 00:51:08 +02:00
// extract and validate TXID
std::string strTxid = vStrInputParts[0];
2015-04-03 00:51:08 +02:00
if ((strTxid.size() != 64) || !IsHex(strTxid))
throw std::runtime_error("invalid TX input txid");
uint256 txid(uint256S(strTxid));
2015-04-03 00:51:08 +02:00
static const unsigned int minTxOutSz = 9;
static const unsigned int maxVout = MaxBlockSize(true) / minTxOutSz;
2015-04-03 00:51:08 +02:00
// extract and validate vout
std::string strVout = vStrInputParts[1];
2015-04-03 00:51:08 +02:00
int vout = atoi(strVout);
if ((vout < 0) || (vout > (int)maxVout))
throw std::runtime_error("invalid TX input vout");
2015-04-03 00:51:08 +02:00
// extract the optional sequence number
uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();
if (vStrInputParts.size() > 2)
nSequenceIn = std::stoul(vStrInputParts[2]);
2015-04-03 00:51:08 +02:00
// append to transaction input list
CTxIn txin(txid, vout, CScript(), nSequenceIn);
2015-04-03 00:51:08 +02:00
tx.vin.push_back(txin);
}
static void MutateTxAddOutAddr(CMutableTransaction& tx, const std::string& strInput)
2015-04-03 00:51:08 +02:00
{
// Separate into VALUE:ADDRESS
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
2015-04-03 00:51:08 +02:00
if (vStrInputParts.size() != 2)
throw std::runtime_error("TX output missing or too many separators");
// Extract and validate VALUE
CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
2015-04-03 00:51:08 +02:00
// extract and validate ADDRESS
std::string strAddr = vStrInputParts[1];
2015-04-03 00:51:08 +02:00
CBitcoinAddress addr(strAddr);
if (!addr.IsValid())
throw std::runtime_error("invalid TX output address");
2015-04-03 00:51:08 +02:00
// build standard output script via GetScriptForDestination()
CScript scriptPubKey = GetScriptForDestination(addr.Get());
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
tx.vout.push_back(txout);
}
static void MutateTxAddOutPubKey(CMutableTransaction& tx, const std::string& strInput)
{
// Separate into VALUE:PUBKEY[:FLAGS]
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
if (vStrInputParts.size() < 2 || vStrInputParts.size() > 3)
throw std::runtime_error("TX output missing or too many separators");
// Extract and validate VALUE
CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
// Extract and validate PUBKEY
CPubKey pubkey(ParseHex(vStrInputParts[1]));
if (!pubkey.IsFullyValid())
throw std::runtime_error("invalid TX output pubkey");
CScript scriptPubKey = GetScriptForRawPubKey(pubkey);
CBitcoinAddress addr(scriptPubKey);
// Extract and validate FLAGS
bool bScriptHash = false;
if (vStrInputParts.size() == 3) {
std::string flags = vStrInputParts[2];
bScriptHash = (flags.find("S") != std::string::npos);
}
if (bScriptHash) {
// Get the address for the redeem script, then call
// GetScriptForDestination() to construct a P2SH scriptPubKey.
CBitcoinAddress redeemScriptAddr(scriptPubKey);
scriptPubKey = GetScriptForDestination(redeemScriptAddr.Get());
}
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
tx.vout.push_back(txout);
}
static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& strInput)
{
// Separate into VALUE:REQUIRED:NUMKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
// Check that there are enough parameters
if (vStrInputParts.size()<3)
throw std::runtime_error("Not enough multisig parameters");
// Extract and validate VALUE
CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
// Extract REQUIRED
uint32_t required = stoul(vStrInputParts[1]);
// Extract NUMKEYS
uint32_t numkeys = stoul(vStrInputParts[2]);
// Validate there are the correct number of pubkeys
if (vStrInputParts.size() < numkeys + 3)
throw std::runtime_error("incorrect number of multisig pubkeys");
if (required < 1 || required > 20 || numkeys < 1 || numkeys > 20 || numkeys < required)
throw std::runtime_error("multisig parameter mismatch. Required " \
+ std::to_string(required) + " of " + std::to_string(numkeys) + "signatures.");
// extract and validate PUBKEYs
std::vector<CPubKey> pubkeys;
for(int pos = 1; pos <= int(numkeys); pos++) {
CPubKey pubkey(ParseHex(vStrInputParts[pos + 2]));
if (!pubkey.IsFullyValid())
throw std::runtime_error("invalid TX output pubkey");
pubkeys.push_back(pubkey);
}
// Extract FLAGS
bool bScriptHash = false;
if (vStrInputParts.size() == numkeys + 4) {
std::string flags = vStrInputParts.back();
bScriptHash = (flags.find("S") != std::string::npos);
}
else if (vStrInputParts.size() > numkeys + 4) {
// Validate that there were no more parameters passed
throw std::runtime_error("Too many parameters");
}
CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
if (bScriptHash) {
// Get the address for the redeem script, then call
// GetScriptForDestination() to construct a P2SH scriptPubKey.
CBitcoinAddress addr(scriptPubKey);
scriptPubKey = GetScriptForDestination(addr.Get());
}
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
tx.vout.push_back(txout);
}
static void MutateTxAddOutData(CMutableTransaction& tx, const std::string& strInput)
{
CAmount value = 0;
// separate [VALUE:]DATA in string
size_t pos = strInput.find(':');
if (pos==0)
throw std::runtime_error("TX output value not specified");
if (pos != std::string::npos) {
// Extract and validate VALUE
value = ExtractAndValidateValue(strInput.substr(0, pos));
}
// extract and validate DATA
std::string strData = strInput.substr(pos + 1, std::string::npos);
if (!IsHex(strData))
throw std::runtime_error("invalid TX output data");
std::vector<unsigned char> data = ParseHex(strData);
CTxOut txout(value, CScript() << OP_RETURN << data);
tx.vout.push_back(txout);
}
static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& strInput)
2015-04-03 00:51:08 +02:00
{
// separate VALUE:SCRIPT[:FLAGS]
std::vector<std::string> vStrInputParts;
boost::split(vStrInputParts, strInput, boost::is_any_of(":"));
if (vStrInputParts.size() < 2)
throw std::runtime_error("TX output missing separator");
2015-04-03 00:51:08 +02:00
// Extract and validate VALUE
CAmount value = ExtractAndValidateValue(vStrInputParts[0]);
2015-04-03 00:51:08 +02:00
// extract and validate script
std::string strScript = vStrInputParts[1];
CScript scriptPubKey = ParseScript(strScript);
// Extract FLAGS
bool bScriptHash = false;
if (vStrInputParts.size() == 3) {
std::string flags = vStrInputParts.back();
bScriptHash = (flags.find("S") != std::string::npos);
}
if (bScriptHash) {
CBitcoinAddress addr(scriptPubKey);
scriptPubKey = GetScriptForDestination(addr.Get());
}
2015-04-03 00:51:08 +02:00
// construct TxOut, append to transaction output list
CTxOut txout(value, scriptPubKey);
tx.vout.push_back(txout);
}
static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
2015-04-03 00:51:08 +02:00
{
// parse requested deletion index
int inIdx = atoi(strInIdx);
if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
std::string strErr = "Invalid TX input index '" + strInIdx + "'";
throw std::runtime_error(strErr.c_str());
2015-04-03 00:51:08 +02:00
}
// delete input from transaction
tx.vin.erase(tx.vin.begin() + inIdx);
}
static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
2015-04-03 00:51:08 +02:00
{
// parse requested deletion index
int outIdx = atoi(strOutIdx);
if (outIdx < 0 || outIdx >= (int)tx.vout.size()) {
std::string strErr = "Invalid TX output index '" + strOutIdx + "'";
throw std::runtime_error(strErr.c_str());
2015-04-03 00:51:08 +02:00
}
// delete output from transaction
tx.vout.erase(tx.vout.begin() + outIdx);
}
static const unsigned int N_SIGHASH_OPTS = 6;
static const struct {
const char *flagStr;
int flags;
} sighashOptions[N_SIGHASH_OPTS] = {
{"ALL", SIGHASH_ALL},
{"NONE", SIGHASH_NONE},
{"SINGLE", SIGHASH_SINGLE},
{"ALL|ANYONECANPAY", SIGHASH_ALL|SIGHASH_ANYONECANPAY},
{"NONE|ANYONECANPAY", SIGHASH_NONE|SIGHASH_ANYONECANPAY},
{"SINGLE|ANYONECANPAY", SIGHASH_SINGLE|SIGHASH_ANYONECANPAY},
};
static bool findSighashFlags(int& flags, const std::string& flagStr)
2015-04-03 00:51:08 +02:00
{
flags = 0;
for (unsigned int i = 0; i < N_SIGHASH_OPTS; i++) {
if (flagStr == sighashOptions[i].flagStr) {
flags = sighashOptions[i].flags;
return true;
}
}
return false;
}
static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
2015-04-03 00:51:08 +02:00
{
int nHashType = SIGHASH_ALL;
if (flagStr.size() > 0)
if (!findSighashFlags(nHashType, flagStr))
throw std::runtime_error("unknown sighash flag/sign option");
2015-04-03 00:51:08 +02:00
std::vector<CTransaction> txVariants;
2015-04-03 00:51:08 +02:00
txVariants.push_back(tx);
// mergedTx will end up with all the signatures; it
// starts as a clone of the raw tx:
CMutableTransaction mergedTx(txVariants[0]);
bool fComplete = true;
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
if (!registers.count("privatekeys"))
throw std::runtime_error("privatekeys register variable must be set.");
2015-04-03 00:51:08 +02:00
CBasicKeyStore tempKeystore;
UniValue keysObj = registers["privatekeys"];
for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
2015-04-03 00:51:08 +02:00
if (!keysObj[kidx].isStr())
throw std::runtime_error("privatekey not a std::string");
2015-04-03 00:51:08 +02:00
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(keysObj[kidx].getValStr());
if (!fGood)
throw std::runtime_error("privatekey not valid");
2015-04-03 00:51:08 +02:00
CKey key = vchSecret.GetKey();
tempKeystore.AddKey(key);
}
// Add previous txouts given in the RPC call:
if (!registers.count("prevtxs"))
throw std::runtime_error("prevtxs register variable must be set.");
2015-04-03 00:51:08 +02:00
UniValue prevtxsObj = registers["prevtxs"];
{
for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {
2015-04-03 00:51:08 +02:00
UniValue prevOut = prevtxsObj[previdx];
if (!prevOut.isObject())
throw std::runtime_error("expected prevtxs internal object");
2015-04-03 00:51:08 +02:00
std::map<std::string, UniValue::VType> types = {
{"txid", UniValue::VSTR},
{"vout", UniValue::VNUM},
{"scriptPubKey", UniValue::VSTR},
};
2015-04-03 00:51:08 +02:00
if (!prevOut.checkObject(types))
throw std::runtime_error("prevtxs internal object typecheck fail");
2015-04-03 00:51:08 +02:00
uint256 txid = ParseHashUV(prevOut["txid"], "txid");
int nOut = atoi(prevOut["vout"].getValStr());
if (nOut < 0)
throw std::runtime_error("vout must be positive");
2015-04-03 00:51:08 +02:00
Merge #10195: Switch chainstate db and cache to per-txout model 589827975 scripted-diff: various renames for per-utxo consistency (Pieter Wuille) a5e02bc7f Increase travis unit test timeout (Pieter Wuille) 73de2c1ff Rename CCoinsCacheEntry::coins to coin (Pieter Wuille) 119e552f7 Merge CCoinsViewCache's GetOutputFor and AccessCoin (Pieter Wuille) 580b02309 [MOVEONLY] Move old CCoins class to txdb.cpp (Pieter Wuille) 8b25d2c0c Upgrade from per-tx database to per-txout (Pieter Wuille) b2af357f3 Reduce reserved memory space for flushing (Pieter Wuille) 41aa5b79a Pack Coin more tightly (Pieter Wuille) 97072d668 Remove unused CCoins methods (Pieter Wuille) ce23efaa5 Extend coins_tests (Pieter Wuille) 508307968 Switch CCoinsView and chainstate db from per-txid to per-txout (Pieter Wuille) 4ec0d9e79 Refactor GetUTXOStats in preparation for per-COutPoint iteration (Pieter Wuille) 13870b56f Replace CCoins-based CTxMemPool::pruneSpent with isSpent (Pieter Wuille) 05293f3cb Remove ModifyCoins/ModifyNewCoins (Pieter Wuille) 961e48397 Switch tests from ModifyCoins to AddCoin/SpendCoin (Pieter Wuille) 8b3868c1b Switch CScriptCheck to use Coin instead of CCoins (Pieter Wuille) c87b957a3 Only pass things committed to by tx's witness hash to CScriptCheck (Matt Corallo) f68cdfe92 Switch from per-tx to per-txout CCoinsViewCache methods in some places (Pieter Wuille) 000391132 Introduce new per-txout CCoinsViewCache functions (Pieter Wuille) bd83111a0 Optimization: Coin&& to ApplyTxInUndo (Pieter Wuille) cb2c7fdac Replace CTxInUndo with Coin (Pieter Wuille) 422634e2f Introduce Coin, a single unspent output (Pieter Wuille) 7d991b55d Store/allow tx metadata in all undo records (Pieter Wuille) c3aa0c119 Report on-disk size in gettxoutsetinfo (Pieter Wuille) d34242430 Remove/ignore tx version in utxo and undo (Pieter Wuille) 7e0032290 Add specialization of SipHash for 256 + 32 bit data (Pieter Wuille) e484652fc Introduce CHashVerifier to hash read data (Pieter Wuille) f54580e7e error() in disconnect for disk corruption, not inconsistency (Pieter Wuille) e66dbde6d Add SizeEstimate to CDBBatch (Pieter Wuille) Tree-SHA512: ce1fb1e40c77d38915cd02189fab7a8b125c7f44d425c85579d872c3bede3a437760997907c99d7b3017ced1c2de54b2ac7223d99d83a6658fe5ef61edef1de3
2017-06-02 00:47:58 +02:00
COutPoint out(txid, nOut);
std::vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey"));
2015-04-03 00:51:08 +02:00
CScript scriptPubKey(pkData.begin(), pkData.end());
{
Merge #10195: Switch chainstate db and cache to per-txout model 589827975 scripted-diff: various renames for per-utxo consistency (Pieter Wuille) a5e02bc7f Increase travis unit test timeout (Pieter Wuille) 73de2c1ff Rename CCoinsCacheEntry::coins to coin (Pieter Wuille) 119e552f7 Merge CCoinsViewCache's GetOutputFor and AccessCoin (Pieter Wuille) 580b02309 [MOVEONLY] Move old CCoins class to txdb.cpp (Pieter Wuille) 8b25d2c0c Upgrade from per-tx database to per-txout (Pieter Wuille) b2af357f3 Reduce reserved memory space for flushing (Pieter Wuille) 41aa5b79a Pack Coin more tightly (Pieter Wuille) 97072d668 Remove unused CCoins methods (Pieter Wuille) ce23efaa5 Extend coins_tests (Pieter Wuille) 508307968 Switch CCoinsView and chainstate db from per-txid to per-txout (Pieter Wuille) 4ec0d9e79 Refactor GetUTXOStats in preparation for per-COutPoint iteration (Pieter Wuille) 13870b56f Replace CCoins-based CTxMemPool::pruneSpent with isSpent (Pieter Wuille) 05293f3cb Remove ModifyCoins/ModifyNewCoins (Pieter Wuille) 961e48397 Switch tests from ModifyCoins to AddCoin/SpendCoin (Pieter Wuille) 8b3868c1b Switch CScriptCheck to use Coin instead of CCoins (Pieter Wuille) c87b957a3 Only pass things committed to by tx's witness hash to CScriptCheck (Matt Corallo) f68cdfe92 Switch from per-tx to per-txout CCoinsViewCache methods in some places (Pieter Wuille) 000391132 Introduce new per-txout CCoinsViewCache functions (Pieter Wuille) bd83111a0 Optimization: Coin&& to ApplyTxInUndo (Pieter Wuille) cb2c7fdac Replace CTxInUndo with Coin (Pieter Wuille) 422634e2f Introduce Coin, a single unspent output (Pieter Wuille) 7d991b55d Store/allow tx metadata in all undo records (Pieter Wuille) c3aa0c119 Report on-disk size in gettxoutsetinfo (Pieter Wuille) d34242430 Remove/ignore tx version in utxo and undo (Pieter Wuille) 7e0032290 Add specialization of SipHash for 256 + 32 bit data (Pieter Wuille) e484652fc Introduce CHashVerifier to hash read data (Pieter Wuille) f54580e7e error() in disconnect for disk corruption, not inconsistency (Pieter Wuille) e66dbde6d Add SizeEstimate to CDBBatch (Pieter Wuille) Tree-SHA512: ce1fb1e40c77d38915cd02189fab7a8b125c7f44d425c85579d872c3bede3a437760997907c99d7b3017ced1c2de54b2ac7223d99d83a6658fe5ef61edef1de3
2017-06-02 00:47:58 +02:00
const Coin& coin = view.AccessCoin(out);
if (!coin.IsSpent() && coin.out.scriptPubKey != scriptPubKey) {
std::string err("Previous output scriptPubKey mismatch:\n");
Merge #10195: Switch chainstate db and cache to per-txout model 589827975 scripted-diff: various renames for per-utxo consistency (Pieter Wuille) a5e02bc7f Increase travis unit test timeout (Pieter Wuille) 73de2c1ff Rename CCoinsCacheEntry::coins to coin (Pieter Wuille) 119e552f7 Merge CCoinsViewCache's GetOutputFor and AccessCoin (Pieter Wuille) 580b02309 [MOVEONLY] Move old CCoins class to txdb.cpp (Pieter Wuille) 8b25d2c0c Upgrade from per-tx database to per-txout (Pieter Wuille) b2af357f3 Reduce reserved memory space for flushing (Pieter Wuille) 41aa5b79a Pack Coin more tightly (Pieter Wuille) 97072d668 Remove unused CCoins methods (Pieter Wuille) ce23efaa5 Extend coins_tests (Pieter Wuille) 508307968 Switch CCoinsView and chainstate db from per-txid to per-txout (Pieter Wuille) 4ec0d9e79 Refactor GetUTXOStats in preparation for per-COutPoint iteration (Pieter Wuille) 13870b56f Replace CCoins-based CTxMemPool::pruneSpent with isSpent (Pieter Wuille) 05293f3cb Remove ModifyCoins/ModifyNewCoins (Pieter Wuille) 961e48397 Switch tests from ModifyCoins to AddCoin/SpendCoin (Pieter Wuille) 8b3868c1b Switch CScriptCheck to use Coin instead of CCoins (Pieter Wuille) c87b957a3 Only pass things committed to by tx's witness hash to CScriptCheck (Matt Corallo) f68cdfe92 Switch from per-tx to per-txout CCoinsViewCache methods in some places (Pieter Wuille) 000391132 Introduce new per-txout CCoinsViewCache functions (Pieter Wuille) bd83111a0 Optimization: Coin&& to ApplyTxInUndo (Pieter Wuille) cb2c7fdac Replace CTxInUndo with Coin (Pieter Wuille) 422634e2f Introduce Coin, a single unspent output (Pieter Wuille) 7d991b55d Store/allow tx metadata in all undo records (Pieter Wuille) c3aa0c119 Report on-disk size in gettxoutsetinfo (Pieter Wuille) d34242430 Remove/ignore tx version in utxo and undo (Pieter Wuille) 7e0032290 Add specialization of SipHash for 256 + 32 bit data (Pieter Wuille) e484652fc Introduce CHashVerifier to hash read data (Pieter Wuille) f54580e7e error() in disconnect for disk corruption, not inconsistency (Pieter Wuille) e66dbde6d Add SizeEstimate to CDBBatch (Pieter Wuille) Tree-SHA512: ce1fb1e40c77d38915cd02189fab7a8b125c7f44d425c85579d872c3bede3a437760997907c99d7b3017ced1c2de54b2ac7223d99d83a6658fe5ef61edef1de3
2017-06-02 00:47:58 +02:00
err = err + ScriptToAsmStr(coin.out.scriptPubKey) + "\nvs:\n"+
ScriptToAsmStr(scriptPubKey);
throw std::runtime_error(err);
2015-04-03 00:51:08 +02:00
}
Merge #10195: Switch chainstate db and cache to per-txout model 589827975 scripted-diff: various renames for per-utxo consistency (Pieter Wuille) a5e02bc7f Increase travis unit test timeout (Pieter Wuille) 73de2c1ff Rename CCoinsCacheEntry::coins to coin (Pieter Wuille) 119e552f7 Merge CCoinsViewCache's GetOutputFor and AccessCoin (Pieter Wuille) 580b02309 [MOVEONLY] Move old CCoins class to txdb.cpp (Pieter Wuille) 8b25d2c0c Upgrade from per-tx database to per-txout (Pieter Wuille) b2af357f3 Reduce reserved memory space for flushing (Pieter Wuille) 41aa5b79a Pack Coin more tightly (Pieter Wuille) 97072d668 Remove unused CCoins methods (Pieter Wuille) ce23efaa5 Extend coins_tests (Pieter Wuille) 508307968 Switch CCoinsView and chainstate db from per-txid to per-txout (Pieter Wuille) 4ec0d9e79 Refactor GetUTXOStats in preparation for per-COutPoint iteration (Pieter Wuille) 13870b56f Replace CCoins-based CTxMemPool::pruneSpent with isSpent (Pieter Wuille) 05293f3cb Remove ModifyCoins/ModifyNewCoins (Pieter Wuille) 961e48397 Switch tests from ModifyCoins to AddCoin/SpendCoin (Pieter Wuille) 8b3868c1b Switch CScriptCheck to use Coin instead of CCoins (Pieter Wuille) c87b957a3 Only pass things committed to by tx's witness hash to CScriptCheck (Matt Corallo) f68cdfe92 Switch from per-tx to per-txout CCoinsViewCache methods in some places (Pieter Wuille) 000391132 Introduce new per-txout CCoinsViewCache functions (Pieter Wuille) bd83111a0 Optimization: Coin&& to ApplyTxInUndo (Pieter Wuille) cb2c7fdac Replace CTxInUndo with Coin (Pieter Wuille) 422634e2f Introduce Coin, a single unspent output (Pieter Wuille) 7d991b55d Store/allow tx metadata in all undo records (Pieter Wuille) c3aa0c119 Report on-disk size in gettxoutsetinfo (Pieter Wuille) d34242430 Remove/ignore tx version in utxo and undo (Pieter Wuille) 7e0032290 Add specialization of SipHash for 256 + 32 bit data (Pieter Wuille) e484652fc Introduce CHashVerifier to hash read data (Pieter Wuille) f54580e7e error() in disconnect for disk corruption, not inconsistency (Pieter Wuille) e66dbde6d Add SizeEstimate to CDBBatch (Pieter Wuille) Tree-SHA512: ce1fb1e40c77d38915cd02189fab7a8b125c7f44d425c85579d872c3bede3a437760997907c99d7b3017ced1c2de54b2ac7223d99d83a6658fe5ef61edef1de3
2017-06-02 00:47:58 +02:00
Coin newcoin;
newcoin.out.scriptPubKey = scriptPubKey;
newcoin.out.nValue = 0; // we don't know the actual output value
newcoin.nHeight = 1;
view.AddCoin(out, std::move(newcoin), true);
2015-04-03 00:51:08 +02:00
}
// if redeemScript given and private keys given,
// add redeemScript to the tempKeystore so it can be signed:
if (scriptPubKey.IsPayToScriptHash() &&
2015-04-03 00:51:08 +02:00
prevOut.exists("redeemScript")) {
UniValue v = prevOut["redeemScript"];
std::vector<unsigned char> rsData(ParseHexUV(v, "redeemScript"));
2015-04-03 00:51:08 +02:00
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
}
}
}
const CKeyStore& keystore = tempKeystore;
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
CTxIn& txin = mergedTx.vin[i];
Merge #10195: Switch chainstate db and cache to per-txout model 589827975 scripted-diff: various renames for per-utxo consistency (Pieter Wuille) a5e02bc7f Increase travis unit test timeout (Pieter Wuille) 73de2c1ff Rename CCoinsCacheEntry::coins to coin (Pieter Wuille) 119e552f7 Merge CCoinsViewCache's GetOutputFor and AccessCoin (Pieter Wuille) 580b02309 [MOVEONLY] Move old CCoins class to txdb.cpp (Pieter Wuille) 8b25d2c0c Upgrade from per-tx database to per-txout (Pieter Wuille) b2af357f3 Reduce reserved memory space for flushing (Pieter Wuille) 41aa5b79a Pack Coin more tightly (Pieter Wuille) 97072d668 Remove unused CCoins methods (Pieter Wuille) ce23efaa5 Extend coins_tests (Pieter Wuille) 508307968 Switch CCoinsView and chainstate db from per-txid to per-txout (Pieter Wuille) 4ec0d9e79 Refactor GetUTXOStats in preparation for per-COutPoint iteration (Pieter Wuille) 13870b56f Replace CCoins-based CTxMemPool::pruneSpent with isSpent (Pieter Wuille) 05293f3cb Remove ModifyCoins/ModifyNewCoins (Pieter Wuille) 961e48397 Switch tests from ModifyCoins to AddCoin/SpendCoin (Pieter Wuille) 8b3868c1b Switch CScriptCheck to use Coin instead of CCoins (Pieter Wuille) c87b957a3 Only pass things committed to by tx's witness hash to CScriptCheck (Matt Corallo) f68cdfe92 Switch from per-tx to per-txout CCoinsViewCache methods in some places (Pieter Wuille) 000391132 Introduce new per-txout CCoinsViewCache functions (Pieter Wuille) bd83111a0 Optimization: Coin&& to ApplyTxInUndo (Pieter Wuille) cb2c7fdac Replace CTxInUndo with Coin (Pieter Wuille) 422634e2f Introduce Coin, a single unspent output (Pieter Wuille) 7d991b55d Store/allow tx metadata in all undo records (Pieter Wuille) c3aa0c119 Report on-disk size in gettxoutsetinfo (Pieter Wuille) d34242430 Remove/ignore tx version in utxo and undo (Pieter Wuille) 7e0032290 Add specialization of SipHash for 256 + 32 bit data (Pieter Wuille) e484652fc Introduce CHashVerifier to hash read data (Pieter Wuille) f54580e7e error() in disconnect for disk corruption, not inconsistency (Pieter Wuille) e66dbde6d Add SizeEstimate to CDBBatch (Pieter Wuille) Tree-SHA512: ce1fb1e40c77d38915cd02189fab7a8b125c7f44d425c85579d872c3bede3a437760997907c99d7b3017ced1c2de54b2ac7223d99d83a6658fe5ef61edef1de3
2017-06-02 00:47:58 +02:00
const Coin& coin = view.AccessCoin(txin.prevout);
if (coin.IsSpent()) {
2015-04-03 00:51:08 +02:00
fComplete = false;
continue;
}
Merge #10195: Switch chainstate db and cache to per-txout model 589827975 scripted-diff: various renames for per-utxo consistency (Pieter Wuille) a5e02bc7f Increase travis unit test timeout (Pieter Wuille) 73de2c1ff Rename CCoinsCacheEntry::coins to coin (Pieter Wuille) 119e552f7 Merge CCoinsViewCache's GetOutputFor and AccessCoin (Pieter Wuille) 580b02309 [MOVEONLY] Move old CCoins class to txdb.cpp (Pieter Wuille) 8b25d2c0c Upgrade from per-tx database to per-txout (Pieter Wuille) b2af357f3 Reduce reserved memory space for flushing (Pieter Wuille) 41aa5b79a Pack Coin more tightly (Pieter Wuille) 97072d668 Remove unused CCoins methods (Pieter Wuille) ce23efaa5 Extend coins_tests (Pieter Wuille) 508307968 Switch CCoinsView and chainstate db from per-txid to per-txout (Pieter Wuille) 4ec0d9e79 Refactor GetUTXOStats in preparation for per-COutPoint iteration (Pieter Wuille) 13870b56f Replace CCoins-based CTxMemPool::pruneSpent with isSpent (Pieter Wuille) 05293f3cb Remove ModifyCoins/ModifyNewCoins (Pieter Wuille) 961e48397 Switch tests from ModifyCoins to AddCoin/SpendCoin (Pieter Wuille) 8b3868c1b Switch CScriptCheck to use Coin instead of CCoins (Pieter Wuille) c87b957a3 Only pass things committed to by tx's witness hash to CScriptCheck (Matt Corallo) f68cdfe92 Switch from per-tx to per-txout CCoinsViewCache methods in some places (Pieter Wuille) 000391132 Introduce new per-txout CCoinsViewCache functions (Pieter Wuille) bd83111a0 Optimization: Coin&& to ApplyTxInUndo (Pieter Wuille) cb2c7fdac Replace CTxInUndo with Coin (Pieter Wuille) 422634e2f Introduce Coin, a single unspent output (Pieter Wuille) 7d991b55d Store/allow tx metadata in all undo records (Pieter Wuille) c3aa0c119 Report on-disk size in gettxoutsetinfo (Pieter Wuille) d34242430 Remove/ignore tx version in utxo and undo (Pieter Wuille) 7e0032290 Add specialization of SipHash for 256 + 32 bit data (Pieter Wuille) e484652fc Introduce CHashVerifier to hash read data (Pieter Wuille) f54580e7e error() in disconnect for disk corruption, not inconsistency (Pieter Wuille) e66dbde6d Add SizeEstimate to CDBBatch (Pieter Wuille) Tree-SHA512: ce1fb1e40c77d38915cd02189fab7a8b125c7f44d425c85579d872c3bede3a437760997907c99d7b3017ced1c2de54b2ac7223d99d83a6658fe5ef61edef1de3
2017-06-02 00:47:58 +02:00
const CScript& prevPubKey = coin.out.scriptPubKey;
2015-04-03 00:51:08 +02:00
txin.scriptSig.clear();
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
// ... and merge in other signatures:
BOOST_FOREACH(const CTransaction& txv, txVariants) {
txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
}
if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i)))
fComplete = false;
}
if (fComplete) {
// do nothing... for now
// perhaps store this for later optional JSON output
}
tx = mergedTx;
}
class Secp256k1Init
{
ECCVerifyHandle globalVerifyHandle;
public:
Secp256k1Init() {
ECC_Start();
}
~Secp256k1Init() {
ECC_Stop();
}
};
static void MutateTx(CMutableTransaction& tx, const std::string& command,
const std::string& commandVal)
2015-04-03 00:51:08 +02:00
{
std::unique_ptr<Secp256k1Init> ecc;
2015-04-03 00:51:08 +02:00
if (command == "nversion")
MutateTxVersion(tx, commandVal);
else if (command == "locktime")
MutateTxLocktime(tx, commandVal);
else if (command == "delin")
MutateTxDelInput(tx, commandVal);
else if (command == "in")
MutateTxAddInput(tx, commandVal);
else if (command == "delout")
MutateTxDelOutput(tx, commandVal);
else if (command == "outaddr")
MutateTxAddOutAddr(tx, commandVal);
else if (command == "outpubkey") {
if (!ecc) { ecc.reset(new Secp256k1Init()); }
MutateTxAddOutPubKey(tx, commandVal);
} else if (command == "outmultisig") {
if (!ecc) { ecc.reset(new Secp256k1Init()); }
MutateTxAddOutMultiSig(tx, commandVal);
} else if (command == "outscript")
2015-04-03 00:51:08 +02:00
MutateTxAddOutScript(tx, commandVal);
else if (command == "outdata")
MutateTxAddOutData(tx, commandVal);
2015-04-03 00:51:08 +02:00
else if (command == "sign") {
if (!ecc) { ecc.reset(new Secp256k1Init()); }
2015-04-03 00:51:08 +02:00
MutateTxSign(tx, commandVal);
}
2015-04-03 00:51:08 +02:00
else if (command == "load")
RegisterLoad(commandVal);
else if (command == "set")
RegisterSet(commandVal);
else
throw std::runtime_error("unknown command");
2015-04-03 00:51:08 +02:00
}
static void OutputTxJSON(const CTransaction& tx)
{
UniValue entry(UniValue::VOBJ);
TxToUniv(tx, uint256(), entry);
2015-04-03 00:51:08 +02:00
std::string jsonOutput = entry.write(4);
2015-04-03 00:51:08 +02:00
fprintf(stdout, "%s\n", jsonOutput.c_str());
}
static void OutputTxHash(const CTransaction& tx)
{
std::string strHexHash = tx.GetHash().GetHex(); // the hex-encoded transaction hash (aka the transaction id)
2015-04-03 00:51:08 +02:00
fprintf(stdout, "%s\n", strHexHash.c_str());
}
static void OutputTxHex(const CTransaction& tx)
{
std::string strHex = EncodeHexTx(tx);
2015-04-03 00:51:08 +02:00
fprintf(stdout, "%s\n", strHex.c_str());
}
static void OutputTx(const CTransaction& tx)
{
if (gArgs.GetBoolArg("-json", false))
2015-04-03 00:51:08 +02:00
OutputTxJSON(tx);
else if (gArgs.GetBoolArg("-txid", false))
2015-04-03 00:51:08 +02:00
OutputTxHash(tx);
else
OutputTxHex(tx);
}
static std::string readStdin()
2015-04-03 00:51:08 +02:00
{
char buf[4096];
std::string ret;
2015-04-03 00:51:08 +02:00
while (!feof(stdin)) {
size_t bread = fread(buf, 1, sizeof(buf), stdin);
ret.append(buf, bread);
if (bread < sizeof(buf))
break;
}
if (ferror(stdin))
throw std::runtime_error("error reading stdin");
2015-04-03 00:51:08 +02:00
boost::algorithm::trim_right(ret);
return ret;
}
static int CommandLineRawTx(int argc, char* argv[])
{
std::string strPrint;
2015-04-03 00:51:08 +02:00
int nRet = 0;
try {
// Skip switches; Permit common stdin convention "-"
while (argc > 1 && IsSwitchChar(argv[1][0]) &&
(argv[1][1] != 0)) {
argc--;
argv++;
}
CMutableTransaction tx;
2015-04-03 00:51:08 +02:00
int startArg;
if (!fCreateBlank) {
// require at least one param
if (argc < 2)
throw std::runtime_error("too few parameters");
2015-04-03 00:51:08 +02:00
2015-04-05 23:56:58 +02:00
// param: hex-encoded dash transaction
std::string strHexTx(argv[1]);
2015-04-03 00:51:08 +02:00
if (strHexTx == "-") // "-" implies standard input
strHexTx = readStdin();
if (!DecodeHexTx(tx, strHexTx))
throw std::runtime_error("invalid transaction encoding");
2015-04-03 00:51:08 +02:00
startArg = 2;
} else
startArg = 1;
for (int i = startArg; i < argc; i++) {
std::string arg = argv[i];
std::string key, value;
2015-04-03 00:51:08 +02:00
size_t eqpos = arg.find('=');
if (eqpos == std::string::npos)
2015-04-03 00:51:08 +02:00
key = arg;
else {
key = arg.substr(0, eqpos);
value = arg.substr(eqpos + 1);
}
MutateTx(tx, key, value);
}
OutputTx(tx);
}
catch (const boost::thread_interrupted&) {
2015-04-03 00:51:08 +02:00
throw;
}
catch (const std::exception& e) {
strPrint = std::string("error: ") + e.what();
2015-04-03 00:51:08 +02:00
nRet = EXIT_FAILURE;
}
catch (...) {
PrintExceptionContinue(std::current_exception(), "CommandLineRawTx()");
2015-04-03 00:51:08 +02:00
throw;
}
if (strPrint != "") {
fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
}
return nRet;
}
int main(int argc, char* argv[])
{
RegisterPrettyTerminateHander();
RegisterPrettySignalHandlers();
2015-04-03 00:51:08 +02:00
SetupEnvironment();
try {
int ret = AppInitRawTx(argc, argv);
if (ret != CONTINUE_EXECUTION)
return ret;
2015-04-03 00:51:08 +02:00
}
catch (const std::exception& e) {
PrintExceptionContinue(std::current_exception(), "AppInitRawTx()");
2015-04-03 00:51:08 +02:00
return EXIT_FAILURE;
}
int ret = EXIT_FAILURE;
try {
ret = CommandLineRawTx(argc, argv);
} catch (...) {
PrintExceptionContinue(std::current_exception(), "CommandLineRawTx()");
2015-04-03 00:51:08 +02:00
}
return ret;
}