]> Git Repo - VerusCoin.git/blame - src/rpcrawtransaction.cpp
Merge pull request #2740 from constantined/constantined
[VerusCoin.git] / src / rpcrawtransaction.cpp
CommitLineData
a2709fad 1// Copyright (c) 2010 Satoshi Nakamoto
db0e8ccd 2// Copyright (c) 2009-2013 The Bitcoin developers
a2709fad
GA
3// Distributed under the MIT/X11 software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <boost/assign/list_of.hpp>
7
8#include "base58.h"
9#include "bitcoinrpc.h"
10#include "db.h"
11#include "init.h"
771ffb5e 12#include "net.h"
a2709fad
GA
13#include "wallet.h"
14
15using namespace std;
16using namespace boost;
17using namespace boost::assign;
18using namespace json_spirit;
19
be066fad 20void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
a2709fad
GA
21{
22 txnouttype type;
23 vector<CTxDestination> addresses;
24 int nRequired;
25
26 out.push_back(Pair("asm", scriptPubKey.ToString()));
be066fad
PT
27 if (fIncludeHex)
28 out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
a2709fad
GA
29
30 if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired))
31 {
32 out.push_back(Pair("type", GetTxnOutputType(TX_NONSTANDARD)));
33 return;
34 }
35
36 out.push_back(Pair("reqSigs", nRequired));
37 out.push_back(Pair("type", GetTxnOutputType(type)));
38
39 Array a;
40 BOOST_FOREACH(const CTxDestination& addr, addresses)
41 a.push_back(CBitcoinAddress(addr).ToString());
42 out.push_back(Pair("addresses", a));
43}
44
bdab0cf5 45void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
a2709fad
GA
46{
47 entry.push_back(Pair("txid", tx.GetHash().GetHex()));
48 entry.push_back(Pair("version", tx.nVersion));
49 entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime));
50 Array vin;
51 BOOST_FOREACH(const CTxIn& txin, tx.vin)
52 {
53 Object in;
54 if (tx.IsCoinBase())
55 in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
56 else
57 {
58 in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
59 in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n));
60 Object o;
61 o.push_back(Pair("asm", txin.scriptSig.ToString()));
62 o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
63 in.push_back(Pair("scriptSig", o));
64 }
65 in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence));
66 vin.push_back(in);
67 }
68 entry.push_back(Pair("vin", vin));
69 Array vout;
dab9fa7f 70 for (unsigned int i = 0; i < tx.vout.size(); i++)
a2709fad
GA
71 {
72 const CTxOut& txout = tx.vout[i];
73 Object out;
74 out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
dab9fa7f 75 out.push_back(Pair("n", (boost::int64_t)i));
a2709fad 76 Object o;
be066fad 77 ScriptPubKeyToJSON(txout.scriptPubKey, o, false);
a2709fad
GA
78 out.push_back(Pair("scriptPubKey", o));
79 vout.push_back(out);
80 }
81 entry.push_back(Pair("vout", vout));
82
83 if (hashBlock != 0)
84 {
85 entry.push_back(Pair("blockhash", hashBlock.GetHex()));
86 map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
87 if (mi != mapBlockIndex.end() && (*mi).second)
88 {
89 CBlockIndex* pindex = (*mi).second;
4c6d41b8 90 if (chainActive.Contains(pindex))
a2709fad 91 {
4c6d41b8 92 entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight));
a2709fad 93 entry.push_back(Pair("time", (boost::int64_t)pindex->nTime));
bdbfd232 94 entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime));
a2709fad
GA
95 }
96 else
97 entry.push_back(Pair("confirmations", 0));
98 }
99 }
100}
101
102Value getrawtransaction(const Array& params, bool fHelp)
103{
104 if (fHelp || params.size() < 1 || params.size() > 2)
105 throw runtime_error(
106 "getrawtransaction <txid> [verbose=0]\n"
107 "If verbose=0, returns a string that is\n"
108 "serialized, hex-encoded data for <txid>.\n"
109 "If verbose is non-zero, returns an Object\n"
110 "with information about <txid>.");
111
2d43f88e 112 uint256 hash = ParseHashV(params[0], "parameter 1");
a2709fad
GA
113
114 bool fVerbose = false;
115 if (params.size() > 1)
116 fVerbose = (params[1].get_int() != 0);
117
118 CTransaction tx;
119 uint256 hashBlock = 0;
450cbb09 120 if (!GetTransaction(hash, tx, hashBlock, true))
738835d7 121 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
a2709fad
GA
122
123 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
124 ssTx << tx;
125 string strHex = HexStr(ssTx.begin(), ssTx.end());
126
127 if (!fVerbose)
128 return strHex;
129
130 Object result;
131 result.push_back(Pair("hex", strHex));
132 TxToJSON(tx, hashBlock, result);
133 return result;
134}
135
136Value listunspent(const Array& params, bool fHelp)
137{
92735bca 138 if (fHelp || params.size() > 3)
a2709fad 139 throw runtime_error(
b1093efa 140 "listunspent [minconf=1] [maxconf=9999999] [\"address\",...]\n"
a2709fad
GA
141 "Returns array of unspent transaction outputs\n"
142 "with between minconf and maxconf (inclusive) confirmations.\n"
92735bca 143 "Optionally filtered to only include txouts paid to specified addresses.\n"
a2709fad
GA
144 "Results are an array of Objects, each of which has:\n"
145 "{txid, vout, scriptPubKey, amount, confirmations}");
146
92735bca 147 RPCTypeCheck(params, list_of(int_type)(int_type)(array_type));
a2709fad
GA
148
149 int nMinDepth = 1;
150 if (params.size() > 0)
151 nMinDepth = params[0].get_int();
152
92735bca 153 int nMaxDepth = 9999999;
a2709fad
GA
154 if (params.size() > 1)
155 nMaxDepth = params[1].get_int();
156
92735bca
GM
157 set<CBitcoinAddress> setAddress;
158 if (params.size() > 2)
159 {
160 Array inputs = params[2].get_array();
161 BOOST_FOREACH(Value& input, inputs)
162 {
163 CBitcoinAddress address(input.get_str());
164 if (!address.IsValid())
738835d7 165 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
92735bca 166 if (setAddress.count(address))
738835d7 167 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str());
92735bca
GM
168 setAddress.insert(address);
169 }
170 }
171
a2709fad
GA
172 Array results;
173 vector<COutput> vecOutputs;
b0730874 174 assert(pwalletMain != NULL);
a2709fad
GA
175 pwalletMain->AvailableCoins(vecOutputs, false);
176 BOOST_FOREACH(const COutput& out, vecOutputs)
177 {
178 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
179 continue;
180
2d43f88e 181 if (setAddress.size())
b1093efa
GM
182 {
183 CTxDestination address;
2d43f88e 184 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
b1093efa
GM
185 continue;
186
187 if (!setAddress.count(address))
188 continue;
189 }
92735bca 190
a2709fad
GA
191 int64 nValue = out.tx->vout[out.i].nValue;
192 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
193 Object entry;
194 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
195 entry.push_back(Pair("vout", out.i));
550479b0 196 CTxDestination address;
197 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
198 {
199 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
200 if (pwalletMain->mapAddressBook.count(address))
61885513 201 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
550479b0 202 }
a2709fad 203 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
03346a61
GA
204 if (pk.IsPayToScriptHash())
205 {
206 CTxDestination address;
207 if (ExtractDestination(pk, address))
208 {
209 const CScriptID& hash = boost::get<const CScriptID&>(address);
210 CScript redeemScript;
211 if (pwalletMain->GetCScript(hash, redeemScript))
212 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
213 }
214 }
a2709fad
GA
215 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
216 entry.push_back(Pair("confirmations",out.nDepth));
217 results.push_back(entry);
218 }
219
220 return results;
221}
222
223Value createrawtransaction(const Array& params, bool fHelp)
224{
225 if (fHelp || params.size() != 2)
226 throw runtime_error(
227 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
228 "Create a transaction spending given inputs\n"
229 "(array of objects containing transaction id and output number),\n"
230 "sending to given address(es).\n"
231 "Returns hex-encoded raw transaction.\n"
232 "Note that the transaction's inputs are not signed, and\n"
233 "it is not stored in the wallet or transmitted to the network.");
234
235 RPCTypeCheck(params, list_of(array_type)(obj_type));
236
237 Array inputs = params[0].get_array();
238 Object sendTo = params[1].get_obj();
239
240 CTransaction rawTx;
241
2d43f88e 242 BOOST_FOREACH(const Value& input, inputs)
a2709fad
GA
243 {
244 const Object& o = input.get_obj();
245
2d43f88e 246 uint256 txid = ParseHashO(o, "txid");
a2709fad
GA
247
248 const Value& vout_v = find_value(o, "vout");
249 if (vout_v.type() != int_type)
738835d7 250 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
a2709fad
GA
251 int nOutput = vout_v.get_int();
252 if (nOutput < 0)
738835d7 253 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
a2709fad 254
2d43f88e 255 CTxIn in(COutPoint(txid, nOutput));
a2709fad
GA
256 rawTx.vin.push_back(in);
257 }
258
259 set<CBitcoinAddress> setAddress;
260 BOOST_FOREACH(const Pair& s, sendTo)
261 {
262 CBitcoinAddress address(s.name_);
263 if (!address.IsValid())
738835d7 264 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
a2709fad
GA
265
266 if (setAddress.count(address))
738835d7 267 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
a2709fad
GA
268 setAddress.insert(address);
269
270 CScript scriptPubKey;
271 scriptPubKey.SetDestination(address.Get());
272 int64 nAmount = AmountFromValue(s.value_);
273
274 CTxOut out(nAmount, scriptPubKey);
275 rawTx.vout.push_back(out);
276 }
277
278 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
279 ss << rawTx;
280 return HexStr(ss.begin(), ss.end());
281}
282
283Value decoderawtransaction(const Array& params, bool fHelp)
284{
285 if (fHelp || params.size() != 1)
286 throw runtime_error(
287 "decoderawtransaction <hex string>\n"
288 "Return a JSON object representing the serialized, hex-encoded transaction.");
289
2d43f88e 290 vector<unsigned char> txData(ParseHexV(params[0], "argument"));
a2709fad
GA
291 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
292 CTransaction tx;
293 try {
294 ssData >> tx;
295 }
296 catch (std::exception &e) {
738835d7 297 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
a2709fad
GA
298 }
299
300 Object result;
301 TxToJSON(tx, 0, result);
302
303 return result;
304}
305
be066fad
PT
306Value decodescript(const Array& params, bool fHelp)
307{
308 if (fHelp || params.size() != 1)
309 throw runtime_error(
310 "decodescript <hex string>\n"
311 "Decode a hex-encoded script.");
312
313 RPCTypeCheck(params, list_of(str_type));
314
315 Object r;
316 CScript script;
317 if (params[0].get_str().size() > 0){
318 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
319 script = CScript(scriptData.begin(), scriptData.end());
320 } else {
321 // Empty scripts are valid
322 }
323 ScriptPubKeyToJSON(script, r, false);
324
325 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
326 return r;
327}
328
a2709fad
GA
329Value signrawtransaction(const Array& params, bool fHelp)
330{
3c3666d6 331 if (fHelp || params.size() < 1 || params.size() > 4)
a2709fad 332 throw runtime_error(
03346a61 333 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
a2709fad 334 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
cc6dfd1f 335 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
729b1806 336 "this transaction depends on but may not yet be in the block chain.\n"
cc6dfd1f 337 "Third optional argument (may be null) is an array of base58-encoded private\n"
a2709fad 338 "keys that, if given, will be the only keys used to sign the transaction.\n"
cc6dfd1f 339 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
3c3666d6 340 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
a2709fad
GA
341 "Returns json object with keys:\n"
342 " hex : raw transaction with signature(s) (hex-encoded string)\n"
343 " complete : 1 if transaction has a complete set of signature (0 if not)"
344 + HelpRequiringPassphrase());
345
cc6dfd1f 346 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
a2709fad 347
2d43f88e 348 vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
a2709fad
GA
349 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
350 vector<CTransaction> txVariants;
351 while (!ssData.empty())
352 {
353 try {
354 CTransaction tx;
355 ssData >> tx;
356 txVariants.push_back(tx);
357 }
358 catch (std::exception &e) {
738835d7 359 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
a2709fad
GA
360 }
361 }
362
363 if (txVariants.empty())
738835d7 364 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
a2709fad
GA
365
366 // mergedTx will end up with all the signatures; it
367 // starts as a clone of the rawtx:
368 CTransaction mergedTx(txVariants[0]);
369 bool fComplete = true;
370
371 // Fetch previous transactions (inputs):
450cbb09
PW
372 CCoinsView viewDummy;
373 CCoinsViewCache view(viewDummy);
a2709fad 374 {
450cbb09 375 LOCK(mempool.cs);
ae8bfd12
PW
376 CCoinsViewCache &viewChain = *pcoinsTip;
377 CCoinsViewMemPool viewMempool(viewChain, mempool);
450cbb09
PW
378 view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
379
380 BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
a2709fad 381 const uint256& prevHash = txin.prevout.hash;
450cbb09
PW
382 CCoins coins;
383 view.GetCoins(prevHash, coins); // this is certainly allowed to fail
a2709fad 384 }
450cbb09 385
ae8bfd12 386 view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
a2709fad
GA
387 }
388
03346a61
GA
389 bool fGivenKeys = false;
390 CBasicKeyStore tempKeystore;
391 if (params.size() > 2 && params[2].type() != null_type)
392 {
393 fGivenKeys = true;
394 Array keys = params[2].get_array();
395 BOOST_FOREACH(Value k, keys)
396 {
397 CBitcoinSecret vchSecret;
398 bool fGood = vchSecret.SetString(k.get_str());
399 if (!fGood)
400 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
dfa23b94 401 CKey key = vchSecret.GetKey();
03346a61
GA
402 tempKeystore.AddKey(key);
403 }
404 }
405 else
406 EnsureWalletIsUnlocked();
407
a2709fad 408 // Add previous txouts given in the RPC call:
cc6dfd1f 409 if (params.size() > 1 && params[1].type() != null_type)
a2709fad
GA
410 {
411 Array prevTxs = params[1].get_array();
412 BOOST_FOREACH(Value& p, prevTxs)
413 {
414 if (p.type() != obj_type)
738835d7 415 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
a2709fad
GA
416
417 Object prevOut = p.get_obj();
418
21c6d3ae 419 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
a2709fad 420
2d43f88e 421 uint256 txid = ParseHashO(prevOut, "txid");
a2709fad
GA
422
423 int nOut = find_value(prevOut, "vout").get_int();
424 if (nOut < 0)
738835d7 425 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
a2709fad 426
2d43f88e 427 vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
a2709fad
GA
428 CScript scriptPubKey(pkData.begin(), pkData.end());
429
450cbb09
PW
430 CCoins coins;
431 if (view.GetCoins(txid, coins)) {
432 if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
a2709fad 433 string err("Previous output scriptPubKey mismatch:\n");
450cbb09 434 err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
a2709fad 435 scriptPubKey.ToString();
738835d7 436 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
a2709fad 437 }
450cbb09 438 // what todo if txid is known, but the actual output isn't?
a2709fad 439 }
03346a61
GA
440 if ((unsigned int)nOut >= coins.vout.size())
441 coins.vout.resize(nOut+1);
450cbb09
PW
442 coins.vout[nOut].scriptPubKey = scriptPubKey;
443 coins.vout[nOut].nValue = 0; // we don't know the actual output value
444 view.SetCoins(txid, coins);
a2709fad 445
03346a61
GA
446 // if redeemScript given and not using the local wallet (private keys
447 // given), add redeemScript to the tempKeystore so it can be signed:
21c6d3ae 448 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
03346a61 449 {
21c6d3ae
GM
450 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
451 Value v = find_value(prevOut, "redeemScript");
452 if (!(v == Value::null))
453 {
454 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
455 CScript redeemScript(rsData.begin(), rsData.end());
456 tempKeystore.AddCScript(redeemScript);
457 }
03346a61 458 }
a2709fad
GA
459 }
460 }
cc6dfd1f 461
b0730874 462 const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain);
a2709fad 463
3c3666d6 464 int nHashType = SIGHASH_ALL;
cc6dfd1f 465 if (params.size() > 3 && params[3].type() != null_type)
3c3666d6
GA
466 {
467 static map<string, int> mapSigHashValues =
468 boost::assign::map_list_of
469 (string("ALL"), int(SIGHASH_ALL))
470 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
471 (string("NONE"), int(SIGHASH_NONE))
472 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
473 (string("SINGLE"), int(SIGHASH_SINGLE))
474 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
475 ;
476 string strHashType = params[3].get_str();
477 if (mapSigHashValues.count(strHashType))
478 nHashType = mapSigHashValues[strHashType];
479 else
738835d7 480 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
3c3666d6
GA
481 }
482
d5e7b611
GA
483 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
484
a2709fad 485 // Sign what we can:
dab9fa7f 486 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
a2709fad
GA
487 {
488 CTxIn& txin = mergedTx.vin[i];
450cbb09
PW
489 CCoins coins;
490 if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
a2709fad
GA
491 {
492 fComplete = false;
493 continue;
494 }
450cbb09 495 const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
a2709fad
GA
496
497 txin.scriptSig.clear();
d5e7b611
GA
498 // Only sign SIGHASH_SINGLE if there's a corresponding output:
499 if (!fHashSingle || (i < mergedTx.vout.size()))
500 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
a2709fad
GA
501
502 // ... and merge in other signatures:
503 BOOST_FOREACH(const CTransaction& txv, txVariants)
504 {
505 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
506 }
99d0d0f3 507 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0))
a2709fad
GA
508 fComplete = false;
509 }
510
511 Object result;
512 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
513 ssTx << mergedTx;
514 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
515 result.push_back(Pair("complete", fComplete));
516
517 return result;
518}
519
520Value sendrawtransaction(const Array& params, bool fHelp)
521{
9d14e689 522 if (fHelp || params.size() < 1 || params.size() > 2)
a2709fad 523 throw runtime_error(
9d14e689 524 "sendrawtransaction <hex string> [allowhighfees=false]\n"
a2709fad
GA
525 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
526
a2709fad 527 // parse hex string from parameter
2d43f88e 528 vector<unsigned char> txData(ParseHexV(params[0], "parameter"));
a2709fad
GA
529 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
530 CTransaction tx;
531
9d14e689
GM
532 bool fOverrideFees = false;
533 if (params.size() > 1)
534 fOverrideFees = params[1].get_bool();
535
a2709fad
GA
536 // deserialize binary data stream
537 try {
538 ssData >> tx;
539 }
540 catch (std::exception &e) {
738835d7 541 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
a2709fad 542 }
771ffb5e 543 uint256 hashTx = tx.GetHash();
a2709fad 544
450cbb09 545 bool fHave = false;
ae8bfd12 546 CCoinsViewCache &view = *pcoinsTip;
450cbb09 547 CCoins existingCoins;
771ffb5e 548 {
ae8bfd12 549 fHave = view.GetCoins(hashTx, existingCoins);
450cbb09
PW
550 if (!fHave) {
551 // push to local node
ef3988ca 552 CValidationState state;
9d14e689 553 if (!mempool.accept(state, tx, false, NULL, !fOverrideFees))
ef3988ca 554 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
450cbb09
PW
555 }
556 }
557 if (fHave) {
558 if (existingCoins.nHeight < 1000000000)
559 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
771ffb5e
GA
560 // Not in block, but already in the memory pool; will drop
561 // through to re-relay it.
450cbb09 562 } else {
64dd46fd 563 SyncWithWallets(hashTx, tx, NULL, true);
771ffb5e 564 }
269d9c64 565 RelayTransaction(tx, hashTx);
a2709fad 566
771ffb5e 567 return hashTx.GetHex();
a2709fad 568}
This page took 0.162167 seconds and 4 git commands to generate.