aboutsummaryrefslogtreecommitdiff
path: root/src/bitcoin-tx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/bitcoin-tx.cpp')
-rw-r--r--src/bitcoin-tx.cpp135
1 files changed, 70 insertions, 65 deletions
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index bf42307df5..9ee3e8eee7 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -31,39 +31,45 @@ static bool fCreateBlank;
static std::map<std::string,UniValue> registers;
static const int CONTINUE_EXECUTION=-1;
+const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
+
static void SetupBitcoinTxArgs()
{
- gArgs.AddArg("-?", _("This help message"), false, OptionsCategory::OPTIONS);
- gArgs.AddArg("-create", _("Create new, empty TX."), false, OptionsCategory::OPTIONS);
- gArgs.AddArg("-json", _("Select JSON output"), false, OptionsCategory::OPTIONS);
- gArgs.AddArg("-txid", _("Output only the hex-encoded transaction id of the resultant transaction."), false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-?", "This help message", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-create", "Create new, empty TX.", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-json", "Select JSON output", false, OptionsCategory::OPTIONS);
+ gArgs.AddArg("-txid", "Output only the hex-encoded transaction id of the resultant transaction.", false, OptionsCategory::OPTIONS);
SetupChainParamsBaseOptions();
- gArgs.AddArg("delin=N", _("Delete input N from TX"), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("delout=N", _("Delete output N from TX"), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", _("Add input to TX"), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("locktime=N", _("Set TX lock time to N"), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("nversion=N", _("Set TX version to N"), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("outdata=[VALUE:]DATA", _("Add data-based output to TX"), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("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 \"W\" flag to produce a pay-to-witness-script-hash output") + ". " +
- _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", _("Add pay-to-pubkey output to TX") + ". " +
- _("Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output") + ". " +
- _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", _("Add raw script output to TX") + ". " +
- _("Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output") + ". " +
- _("Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash."), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("replaceable(=N)", _("Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)"), false, OptionsCategory::COMMANDS);
- gArgs.AddArg("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."), false, OptionsCategory::COMMANDS);
-
- gArgs.AddArg("load=NAME:FILENAME", _("Load JSON file FILENAME into register NAME"), false, OptionsCategory::REGISTER_COMMANDS);
- gArgs.AddArg("set=NAME:JSON-STRING", _("Set register NAME to given JSON-STRING"), false, OptionsCategory::REGISTER_COMMANDS);
+ gArgs.AddArg("delin=N", "Delete input N from TX", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("delout=N", "Delete output N from TX", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("locktime=N", "Set TX lock time to N", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("nversion=N", "Set TX version to N", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("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 \"W\" flag to produce a pay-to-witness-script-hash output. "
+ "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("outpubkey=VALUE:PUBKEY[:FLAGS]", "Add pay-to-pubkey output to TX. "
+ "Optionally add the \"W\" flag to produce a pay-to-witness-pubkey-hash output. "
+ "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. "
+ "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
+ "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("replaceable(=N)", "Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)", false, OptionsCategory::COMMANDS);
+ gArgs.AddArg("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.", false, OptionsCategory::COMMANDS);
+
+ gArgs.AddArg("load=NAME:FILENAME", "Load JSON file FILENAME into register NAME", false, OptionsCategory::REGISTER_COMMANDS);
+ gArgs.AddArg("set=NAME:JSON-STRING", "Set register NAME to given JSON-STRING", false, OptionsCategory::REGISTER_COMMANDS);
+
+ // Hidden
+ gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN);
+ gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN);
}
//
@@ -76,7 +82,11 @@ static int AppInitRawTx(int argc, char* argv[])
// Parameters
//
SetupBitcoinTxArgs();
- gArgs.ParseParameters(argc, argv);
+ std::string error;
+ if (!gArgs.ParseParameters(argc, argv, error)) {
+ fprintf(stderr, "Error parsing command line arguments: %s\n", error.c_str());
+ return EXIT_FAILURE;
+ }
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
@@ -90,11 +100,10 @@ static int AppInitRawTx(int argc, char* argv[])
if (argc < 2 || HelpRequested(gArgs)) {
// First part of help message is specific to this utility
- std::string strUsage = strprintf(_("%s bitcoin-tx utility version"), _(PACKAGE_NAME)) + " " + FormatFullVersion() + "\n\n" +
- _("Usage:") + "\n" +
- " bitcoin-tx [options] <hex-tx> [commands] " + _("Update hex-encoded bitcoin transaction") + "\n" +
- " bitcoin-tx [options] -create [commands] " + _("Create hex-encoded bitcoin transaction") + "\n" +
- "\n";
+ std::string strUsage = PACKAGE_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n\n" +
+ "Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction\n" +
+ "or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction\n" +
+ "\n";
strUsage += gArgs.GetHelpMessage();
fprintf(stdout, "%s", strUsage.c_str());
@@ -185,18 +194,18 @@ static CAmount ExtractAndValidateValue(const std::string& strValue)
static void MutateTxVersion(CMutableTransaction& tx, const std::string& cmdVal)
{
- int64_t newVersion = atoi64(cmdVal);
- if (newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
- throw std::runtime_error("Invalid TX version requested");
+ int64_t newVersion;
+ if (!ParseInt64(cmdVal, &newVersion) || newVersion < 1 || newVersion > CTransaction::MAX_STANDARD_VERSION)
+ throw std::runtime_error("Invalid TX version requested: '" + cmdVal + "'");
tx.nVersion = (int) newVersion;
}
static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
{
- int64_t newLocktime = atoi64(cmdVal);
- if (newLocktime < 0LL || newLocktime > 0xffffffffLL)
- throw std::runtime_error("Invalid TX locktime requested");
+ int64_t newLocktime;
+ if (!ParseInt64(cmdVal, &newLocktime) || newLocktime < 0LL || newLocktime > 0xffffffffLL)
+ throw std::runtime_error("Invalid TX locktime requested: '" + cmdVal + "'");
tx.nLockTime = (unsigned int) newLocktime;
}
@@ -204,8 +213,8 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
{
// parse requested index
- int inIdx = atoi(strInIdx);
- if (inIdx < 0 || inIdx >= (int)tx.vin.size()) {
+ int64_t inIdx;
+ if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
}
@@ -240,10 +249,10 @@ static void MutateTxAddInput(CMutableTransaction& tx, const std::string& strInpu
static const unsigned int maxVout = MAX_BLOCK_WEIGHT / (WITNESS_SCALE_FACTOR * minTxOutSz);
// extract and validate vout
- std::string strVout = vStrInputParts[1];
- int vout = atoi(strVout);
- if ((vout < 0) || (vout > (int)maxVout))
- throw std::runtime_error("invalid TX input vout");
+ const std::string& strVout = vStrInputParts[1];
+ int64_t vout;
+ if (!ParseInt64(strVout, &vout) || vout < 0 || vout > static_cast<int64_t>(maxVout))
+ throw std::runtime_error("invalid TX input vout '" + strVout + "'");
// extract the optional sequence number
uint32_t nSequenceIn=std::numeric_limits<unsigned int>::max();
@@ -376,7 +385,7 @@ static void MutateTxAddOutMultiSig(CMutableTransaction& tx, const std::string& s
CScript scriptPubKey = GetScriptForMultisig(required, pubkeys);
if (bSegWit) {
- for (CPubKey& pubkey : pubkeys) {
+ for (const CPubKey& pubkey : pubkeys) {
if (!pubkey.IsCompressed()) {
throw std::runtime_error("Uncompressed pubkeys are not useable for SegWit outputs");
}
@@ -473,10 +482,9 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const std::string& str
static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInIdx)
{
// 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());
+ int64_t inIdx;
+ if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
+ throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
}
// delete input from transaction
@@ -486,10 +494,9 @@ static void MutateTxDelInput(CMutableTransaction& tx, const std::string& strInId
static void MutateTxDelOutput(CMutableTransaction& tx, const std::string& strOutIdx)
{
// 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());
+ int64_t outIdx;
+ if (!ParseInt64(strOutIdx, &outIdx) || outIdx < 0 || outIdx >= static_cast<int64_t>(tx.vout.size())) {
+ throw std::runtime_error("Invalid TX output index '" + strOutIdx + "'");
}
// delete output from transaction
@@ -546,7 +553,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
// mergedTx will end up with all the signatures; it
// starts as a clone of the raw tx:
CMutableTransaction mergedTx{tx};
- const CTransaction txv{tx};
+ const CMutableTransaction txv{tx};
CCoinsView viewDummy;
CCoinsViewCache view(&viewDummy);
@@ -583,9 +590,9 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
if (!prevOut.checkObject(types))
throw std::runtime_error("prevtxs internal object typecheck fail");
- uint256 txid = ParseHashUV(prevOut["txid"], "txid");
+ uint256 txid = ParseHashStr(prevOut["txid"].get_str(), "txid");
- int nOut = atoi(prevOut["vout"].getValStr());
+ const int nOut = prevOut["vout"].get_int();
if (nOut < 0)
throw std::runtime_error("vout must be positive");
@@ -629,7 +636,7 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
- const CTxIn& txin = mergedTx.vin[i];
+ CTxIn& txin = mergedTx.vin[i];
const Coin& coin = view.AccessCoin(txin.prevout);
if (coin.IsSpent()) {
continue;
@@ -637,14 +644,12 @@ static void MutateTxSign(CMutableTransaction& tx, const std::string& flagStr)
const CScript& prevPubKey = coin.out.scriptPubKey;
const CAmount& amount = coin.out.nValue;
- SignatureData sigdata;
+ SignatureData sigdata = DataFromTransaction(mergedTx, i, coin.out);
// Only sign SIGHASH_SINGLE if there's a corresponding output:
if (!fHashSingle || (i < mergedTx.vout.size()))
ProduceSignature(keystore, MutableTransactionSignatureCreator(&mergedTx, i, amount, nHashType), prevPubKey, sigdata);
- // ... and merge in other signatures:
- sigdata = CombineSignatures(prevPubKey, MutableTransactionSignatureChecker(&mergedTx, i, amount), sigdata, DataFromTransaction(txv, i));
- UpdateTransaction(mergedTx, i, sigdata);
+ UpdateInput(txin, sigdata);
}
tx = mergedTx;