]> Git Repo - VerusCoin.git/blame - src/rpcrawtransaction.cpp
Merge pull request #2888 from litecoin-project/getnetworkhashps
[VerusCoin.git] / src / rpcrawtransaction.cpp
CommitLineData
a2709fad
GA
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-2012 The Bitcoin developers
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;
90 if (pindex->IsInMainChain())
91 {
92 entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight));
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;
174 pwalletMain->AvailableCoins(vecOutputs, false);
175 BOOST_FOREACH(const COutput& out, vecOutputs)
176 {
177 if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
178 continue;
179
2d43f88e 180 if (setAddress.size())
b1093efa
GM
181 {
182 CTxDestination address;
2d43f88e 183 if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
b1093efa
GM
184 continue;
185
186 if (!setAddress.count(address))
187 continue;
188 }
92735bca 189
a2709fad
GA
190 int64 nValue = out.tx->vout[out.i].nValue;
191 const CScript& pk = out.tx->vout[out.i].scriptPubKey;
192 Object entry;
193 entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
194 entry.push_back(Pair("vout", out.i));
550479b0 195 CTxDestination address;
196 if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address))
197 {
198 entry.push_back(Pair("address", CBitcoinAddress(address).ToString()));
199 if (pwalletMain->mapAddressBook.count(address))
61885513 200 entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name));
550479b0 201 }
a2709fad 202 entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end())));
03346a61
GA
203 if (pk.IsPayToScriptHash())
204 {
205 CTxDestination address;
206 if (ExtractDestination(pk, address))
207 {
208 const CScriptID& hash = boost::get<const CScriptID&>(address);
209 CScript redeemScript;
210 if (pwalletMain->GetCScript(hash, redeemScript))
211 entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
212 }
213 }
a2709fad
GA
214 entry.push_back(Pair("amount",ValueFromAmount(nValue)));
215 entry.push_back(Pair("confirmations",out.nDepth));
216 results.push_back(entry);
217 }
218
219 return results;
220}
221
222Value createrawtransaction(const Array& params, bool fHelp)
223{
224 if (fHelp || params.size() != 2)
225 throw runtime_error(
226 "createrawtransaction [{\"txid\":txid,\"vout\":n},...] {address:amount,...}\n"
227 "Create a transaction spending given inputs\n"
228 "(array of objects containing transaction id and output number),\n"
229 "sending to given address(es).\n"
230 "Returns hex-encoded raw transaction.\n"
231 "Note that the transaction's inputs are not signed, and\n"
232 "it is not stored in the wallet or transmitted to the network.");
233
234 RPCTypeCheck(params, list_of(array_type)(obj_type));
235
236 Array inputs = params[0].get_array();
237 Object sendTo = params[1].get_obj();
238
239 CTransaction rawTx;
240
2d43f88e 241 BOOST_FOREACH(const Value& input, inputs)
a2709fad
GA
242 {
243 const Object& o = input.get_obj();
244
2d43f88e 245 uint256 txid = ParseHashO(o, "txid");
a2709fad
GA
246
247 const Value& vout_v = find_value(o, "vout");
248 if (vout_v.type() != int_type)
738835d7 249 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
a2709fad
GA
250 int nOutput = vout_v.get_int();
251 if (nOutput < 0)
738835d7 252 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
a2709fad 253
2d43f88e 254 CTxIn in(COutPoint(txid, nOutput));
a2709fad
GA
255 rawTx.vin.push_back(in);
256 }
257
258 set<CBitcoinAddress> setAddress;
259 BOOST_FOREACH(const Pair& s, sendTo)
260 {
261 CBitcoinAddress address(s.name_);
262 if (!address.IsValid())
738835d7 263 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
a2709fad
GA
264
265 if (setAddress.count(address))
738835d7 266 throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
a2709fad
GA
267 setAddress.insert(address);
268
269 CScript scriptPubKey;
270 scriptPubKey.SetDestination(address.Get());
271 int64 nAmount = AmountFromValue(s.value_);
272
273 CTxOut out(nAmount, scriptPubKey);
274 rawTx.vout.push_back(out);
275 }
276
277 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
278 ss << rawTx;
279 return HexStr(ss.begin(), ss.end());
280}
281
282Value decoderawtransaction(const Array& params, bool fHelp)
283{
284 if (fHelp || params.size() != 1)
285 throw runtime_error(
286 "decoderawtransaction <hex string>\n"
287 "Return a JSON object representing the serialized, hex-encoded transaction.");
288
2d43f88e 289 vector<unsigned char> txData(ParseHexV(params[0], "argument"));
a2709fad
GA
290 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
291 CTransaction tx;
292 try {
293 ssData >> tx;
294 }
295 catch (std::exception &e) {
738835d7 296 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
a2709fad
GA
297 }
298
299 Object result;
300 TxToJSON(tx, 0, result);
301
302 return result;
303}
304
be066fad
PT
305Value decodescript(const Array& params, bool fHelp)
306{
307 if (fHelp || params.size() != 1)
308 throw runtime_error(
309 "decodescript <hex string>\n"
310 "Decode a hex-encoded script.");
311
312 RPCTypeCheck(params, list_of(str_type));
313
314 Object r;
315 CScript script;
316 if (params[0].get_str().size() > 0){
317 vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
318 script = CScript(scriptData.begin(), scriptData.end());
319 } else {
320 // Empty scripts are valid
321 }
322 ScriptPubKeyToJSON(script, r, false);
323
324 r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString()));
325 return r;
326}
327
a2709fad
GA
328Value signrawtransaction(const Array& params, bool fHelp)
329{
3c3666d6 330 if (fHelp || params.size() < 1 || params.size() > 4)
a2709fad 331 throw runtime_error(
03346a61 332 "signrawtransaction <hex string> [{\"txid\":txid,\"vout\":n,\"scriptPubKey\":hex,\"redeemScript\":hex},...] [<privatekey1>,...] [sighashtype=\"ALL\"]\n"
a2709fad 333 "Sign inputs for raw transaction (serialized, hex-encoded).\n"
cc6dfd1f 334 "Second optional argument (may be null) is an array of previous transaction outputs that\n"
729b1806 335 "this transaction depends on but may not yet be in the block chain.\n"
cc6dfd1f 336 "Third optional argument (may be null) is an array of base58-encoded private\n"
a2709fad 337 "keys that, if given, will be the only keys used to sign the transaction.\n"
cc6dfd1f 338 "Fourth optional argument is a string that is one of six values; ALL, NONE, SINGLE or\n"
3c3666d6 339 "ALL|ANYONECANPAY, NONE|ANYONECANPAY, SINGLE|ANYONECANPAY.\n"
a2709fad
GA
340 "Returns json object with keys:\n"
341 " hex : raw transaction with signature(s) (hex-encoded string)\n"
342 " complete : 1 if transaction has a complete set of signature (0 if not)"
343 + HelpRequiringPassphrase());
344
cc6dfd1f 345 RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true);
a2709fad 346
2d43f88e 347 vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
a2709fad
GA
348 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
349 vector<CTransaction> txVariants;
350 while (!ssData.empty())
351 {
352 try {
353 CTransaction tx;
354 ssData >> tx;
355 txVariants.push_back(tx);
356 }
357 catch (std::exception &e) {
738835d7 358 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
a2709fad
GA
359 }
360 }
361
362 if (txVariants.empty())
738835d7 363 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction");
a2709fad
GA
364
365 // mergedTx will end up with all the signatures; it
366 // starts as a clone of the rawtx:
367 CTransaction mergedTx(txVariants[0]);
368 bool fComplete = true;
369
370 // Fetch previous transactions (inputs):
450cbb09
PW
371 CCoinsView viewDummy;
372 CCoinsViewCache view(viewDummy);
a2709fad 373 {
450cbb09 374 LOCK(mempool.cs);
ae8bfd12
PW
375 CCoinsViewCache &viewChain = *pcoinsTip;
376 CCoinsViewMemPool viewMempool(viewChain, mempool);
450cbb09
PW
377 view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view
378
379 BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) {
a2709fad 380 const uint256& prevHash = txin.prevout.hash;
450cbb09
PW
381 CCoins coins;
382 view.GetCoins(prevHash, coins); // this is certainly allowed to fail
a2709fad 383 }
450cbb09 384
ae8bfd12 385 view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long
a2709fad
GA
386 }
387
03346a61
GA
388 bool fGivenKeys = false;
389 CBasicKeyStore tempKeystore;
390 if (params.size() > 2 && params[2].type() != null_type)
391 {
392 fGivenKeys = true;
393 Array keys = params[2].get_array();
394 BOOST_FOREACH(Value k, keys)
395 {
396 CBitcoinSecret vchSecret;
397 bool fGood = vchSecret.SetString(k.get_str());
398 if (!fGood)
399 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
dfa23b94 400 CKey key = vchSecret.GetKey();
03346a61
GA
401 tempKeystore.AddKey(key);
402 }
403 }
404 else
405 EnsureWalletIsUnlocked();
406
a2709fad 407 // Add previous txouts given in the RPC call:
cc6dfd1f 408 if (params.size() > 1 && params[1].type() != null_type)
a2709fad
GA
409 {
410 Array prevTxs = params[1].get_array();
411 BOOST_FOREACH(Value& p, prevTxs)
412 {
413 if (p.type() != obj_type)
738835d7 414 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
a2709fad
GA
415
416 Object prevOut = p.get_obj();
417
21c6d3ae 418 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
a2709fad 419
2d43f88e 420 uint256 txid = ParseHashO(prevOut, "txid");
a2709fad
GA
421
422 int nOut = find_value(prevOut, "vout").get_int();
423 if (nOut < 0)
738835d7 424 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive");
a2709fad 425
2d43f88e 426 vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey"));
a2709fad
GA
427 CScript scriptPubKey(pkData.begin(), pkData.end());
428
450cbb09
PW
429 CCoins coins;
430 if (view.GetCoins(txid, coins)) {
431 if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) {
a2709fad 432 string err("Previous output scriptPubKey mismatch:\n");
450cbb09 433 err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+
a2709fad 434 scriptPubKey.ToString();
738835d7 435 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err);
a2709fad 436 }
450cbb09 437 // what todo if txid is known, but the actual output isn't?
a2709fad 438 }
03346a61
GA
439 if ((unsigned int)nOut >= coins.vout.size())
440 coins.vout.resize(nOut+1);
450cbb09
PW
441 coins.vout[nOut].scriptPubKey = scriptPubKey;
442 coins.vout[nOut].nValue = 0; // we don't know the actual output value
443 view.SetCoins(txid, coins);
a2709fad 444
03346a61
GA
445 // if redeemScript given and not using the local wallet (private keys
446 // given), add redeemScript to the tempKeystore so it can be signed:
21c6d3ae 447 if (fGivenKeys && scriptPubKey.IsPayToScriptHash())
03346a61 448 {
21c6d3ae
GM
449 RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
450 Value v = find_value(prevOut, "redeemScript");
451 if (!(v == Value::null))
452 {
453 vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
454 CScript redeemScript(rsData.begin(), rsData.end());
455 tempKeystore.AddCScript(redeemScript);
456 }
03346a61 457 }
a2709fad
GA
458 }
459 }
cc6dfd1f 460
a2709fad
GA
461 const CKeyStore& keystore = (fGivenKeys ? tempKeystore : *pwalletMain);
462
3c3666d6 463 int nHashType = SIGHASH_ALL;
cc6dfd1f 464 if (params.size() > 3 && params[3].type() != null_type)
3c3666d6
GA
465 {
466 static map<string, int> mapSigHashValues =
467 boost::assign::map_list_of
468 (string("ALL"), int(SIGHASH_ALL))
469 (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))
470 (string("NONE"), int(SIGHASH_NONE))
471 (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY))
472 (string("SINGLE"), int(SIGHASH_SINGLE))
473 (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY))
474 ;
475 string strHashType = params[3].get_str();
476 if (mapSigHashValues.count(strHashType))
477 nHashType = mapSigHashValues[strHashType];
478 else
738835d7 479 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param");
3c3666d6
GA
480 }
481
d5e7b611
GA
482 bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
483
a2709fad 484 // Sign what we can:
dab9fa7f 485 for (unsigned int i = 0; i < mergedTx.vin.size(); i++)
a2709fad
GA
486 {
487 CTxIn& txin = mergedTx.vin[i];
450cbb09
PW
488 CCoins coins;
489 if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n))
a2709fad
GA
490 {
491 fComplete = false;
492 continue;
493 }
450cbb09 494 const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey;
a2709fad
GA
495
496 txin.scriptSig.clear();
d5e7b611
GA
497 // Only sign SIGHASH_SINGLE if there's a corresponding output:
498 if (!fHashSingle || (i < mergedTx.vout.size()))
499 SignSignature(keystore, prevPubKey, mergedTx, i, nHashType);
a2709fad
GA
500
501 // ... and merge in other signatures:
502 BOOST_FOREACH(const CTransaction& txv, txVariants)
503 {
504 txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig);
505 }
99d0d0f3 506 if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0))
a2709fad
GA
507 fComplete = false;
508 }
509
510 Object result;
511 CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
512 ssTx << mergedTx;
513 result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end())));
514 result.push_back(Pair("complete", fComplete));
515
516 return result;
517}
518
519Value sendrawtransaction(const Array& params, bool fHelp)
520{
9d14e689 521 if (fHelp || params.size() < 1 || params.size() > 2)
a2709fad 522 throw runtime_error(
9d14e689 523 "sendrawtransaction <hex string> [allowhighfees=false]\n"
a2709fad
GA
524 "Submits raw transaction (serialized, hex-encoded) to local node and network.");
525
a2709fad 526 // parse hex string from parameter
2d43f88e 527 vector<unsigned char> txData(ParseHexV(params[0], "parameter"));
a2709fad
GA
528 CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
529 CTransaction tx;
530
9d14e689
GM
531 bool fOverrideFees = false;
532 if (params.size() > 1)
533 fOverrideFees = params[1].get_bool();
534
a2709fad
GA
535 // deserialize binary data stream
536 try {
537 ssData >> tx;
538 }
539 catch (std::exception &e) {
738835d7 540 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
a2709fad 541 }
771ffb5e 542 uint256 hashTx = tx.GetHash();
a2709fad 543
450cbb09 544 bool fHave = false;
ae8bfd12 545 CCoinsViewCache &view = *pcoinsTip;
450cbb09 546 CCoins existingCoins;
771ffb5e 547 {
ae8bfd12 548 fHave = view.GetCoins(hashTx, existingCoins);
450cbb09
PW
549 if (!fHave) {
550 // push to local node
ef3988ca 551 CValidationState state;
9d14e689 552 if (!mempool.accept(state, tx, false, NULL, !fOverrideFees))
ef3988ca 553 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX rejected"); // TODO: report validation state
450cbb09
PW
554 }
555 }
556 if (fHave) {
557 if (existingCoins.nHeight < 1000000000)
558 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "transaction already in block chain");
771ffb5e
GA
559 // Not in block, but already in the memory pool; will drop
560 // through to re-relay it.
450cbb09 561 } else {
64dd46fd 562 SyncWithWallets(hashTx, tx, NULL, true);
771ffb5e 563 }
269d9c64 564 RelayTransaction(tx, hashTx);
a2709fad 565
771ffb5e 566 return hashTx.GetHex();
a2709fad 567}
This page took 0.152099 seconds and 4 git commands to generate.