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