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