]>
Commit | Line | Data |
---|---|---|
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 | ||
15 | using namespace std; | |
16 | using namespace boost; | |
17 | using namespace boost::assign; | |
18 | using namespace json_spirit; | |
19 | ||
be066fad | 20 | void 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 | 45 | void 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 | ||
102 | Value 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 | ||
136 | Value 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 | ||
223 | Value 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 | ||
283 | Value 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 |
306 | Value 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 |
329 | Value 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 | ||
520 | Value 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 | } |