]>
Commit | Line | Data |
---|---|---|
a2709fad | 1 | // Copyright (c) 2010 Satoshi Nakamoto |
57702541 | 2 | // Copyright (c) 2009-2014 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 | ||
a2709fad | 6 | #include "base58.h" |
c037531d | 7 | #include "core.h" |
a2709fad | 8 | #include "init.h" |
c037531d PK |
9 | #include "keystore.h" |
10 | #include "main.h" | |
771ffb5e | 11 | #include "net.h" |
c037531d | 12 | #include "rpcserver.h" |
51ed9ec9 | 13 | #include "uint256.h" |
48ba56cd | 14 | #ifdef ENABLE_WALLET |
a2709fad | 15 | #include "wallet.h" |
48ba56cd | 16 | #endif |
a2709fad | 17 | |
51ed9ec9 BD |
18 | #include <stdint.h> |
19 | ||
20 | #include <boost/assign/list_of.hpp> | |
21 | #include "json/json_spirit_utils.h" | |
22 | #include "json/json_spirit_value.h" | |
23 | ||
a2709fad GA |
24 | using namespace std; |
25 | using namespace boost; | |
26 | using namespace boost::assign; | |
27 | using namespace json_spirit; | |
28 | ||
be066fad | 29 | void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex) |
a2709fad GA |
30 | { |
31 | txnouttype type; | |
32 | vector<CTxDestination> addresses; | |
33 | int nRequired; | |
34 | ||
35 | out.push_back(Pair("asm", scriptPubKey.ToString())); | |
be066fad PT |
36 | if (fIncludeHex) |
37 | out.push_back(Pair("hex", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); | |
a2709fad GA |
38 | |
39 | if (!ExtractDestinations(scriptPubKey, type, addresses, nRequired)) | |
40 | { | |
22de68df | 41 | out.push_back(Pair("type", GetTxnOutputType(type))); |
a2709fad GA |
42 | return; |
43 | } | |
44 | ||
45 | out.push_back(Pair("reqSigs", nRequired)); | |
46 | out.push_back(Pair("type", GetTxnOutputType(type))); | |
47 | ||
48 | Array a; | |
49 | BOOST_FOREACH(const CTxDestination& addr, addresses) | |
50 | a.push_back(CBitcoinAddress(addr).ToString()); | |
51 | out.push_back(Pair("addresses", a)); | |
52 | } | |
53 | ||
bdab0cf5 | 54 | void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) |
a2709fad GA |
55 | { |
56 | entry.push_back(Pair("txid", tx.GetHash().GetHex())); | |
57 | entry.push_back(Pair("version", tx.nVersion)); | |
58 | entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); | |
59 | Array vin; | |
60 | BOOST_FOREACH(const CTxIn& txin, tx.vin) | |
61 | { | |
62 | Object in; | |
63 | if (tx.IsCoinBase()) | |
64 | in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); | |
65 | else | |
66 | { | |
67 | in.push_back(Pair("txid", txin.prevout.hash.GetHex())); | |
68 | in.push_back(Pair("vout", (boost::int64_t)txin.prevout.n)); | |
69 | Object o; | |
70 | o.push_back(Pair("asm", txin.scriptSig.ToString())); | |
71 | o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); | |
72 | in.push_back(Pair("scriptSig", o)); | |
73 | } | |
74 | in.push_back(Pair("sequence", (boost::int64_t)txin.nSequence)); | |
75 | vin.push_back(in); | |
76 | } | |
77 | entry.push_back(Pair("vin", vin)); | |
78 | Array vout; | |
dab9fa7f | 79 | for (unsigned int i = 0; i < tx.vout.size(); i++) |
a2709fad GA |
80 | { |
81 | const CTxOut& txout = tx.vout[i]; | |
82 | Object out; | |
83 | out.push_back(Pair("value", ValueFromAmount(txout.nValue))); | |
dab9fa7f | 84 | out.push_back(Pair("n", (boost::int64_t)i)); |
a2709fad | 85 | Object o; |
a702a0b6 | 86 | ScriptPubKeyToJSON(txout.scriptPubKey, o, true); |
a2709fad GA |
87 | out.push_back(Pair("scriptPubKey", o)); |
88 | vout.push_back(out); | |
89 | } | |
90 | entry.push_back(Pair("vout", vout)); | |
91 | ||
92 | if (hashBlock != 0) | |
93 | { | |
94 | entry.push_back(Pair("blockhash", hashBlock.GetHex())); | |
95 | map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock); | |
96 | if (mi != mapBlockIndex.end() && (*mi).second) | |
97 | { | |
98 | CBlockIndex* pindex = (*mi).second; | |
4c6d41b8 | 99 | if (chainActive.Contains(pindex)) |
a2709fad | 100 | { |
4c6d41b8 | 101 | entry.push_back(Pair("confirmations", 1 + chainActive.Height() - pindex->nHeight)); |
a2709fad | 102 | entry.push_back(Pair("time", (boost::int64_t)pindex->nTime)); |
bdbfd232 | 103 | entry.push_back(Pair("blocktime", (boost::int64_t)pindex->nTime)); |
a2709fad GA |
104 | } |
105 | else | |
106 | entry.push_back(Pair("confirmations", 0)); | |
107 | } | |
108 | } | |
109 | } | |
110 | ||
111 | Value getrawtransaction(const Array& params, bool fHelp) | |
112 | { | |
113 | if (fHelp || params.size() < 1 || params.size() > 2) | |
114 | throw runtime_error( | |
a6099ef3 | 115 | "getrawtransaction \"txid\" ( verbose )\n" |
116 | "\nReturn the raw transaction data.\n" | |
117 | "\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n" | |
118 | "If verbose is non-zero, returns an Object with information about 'txid'.\n" | |
119 | ||
120 | "\nArguments:\n" | |
121 | "1. \"txid\" (string, required) The transaction id\n" | |
122 | "2. verbose (numeric, optional, default=0) If 0, return a string, other return a json object\n" | |
123 | ||
124 | "\nResult (if verbose is not set or set to 0):\n" | |
125 | "\"data\" (string) The serialized, hex-encoded data for 'txid'\n" | |
126 | ||
127 | "\nResult (if verbose > 0):\n" | |
128 | "{\n" | |
129 | " \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n" | |
130 | " \"txid\" : \"id\", (string) The transaction id (same as provided)\n" | |
131 | " \"version\" : n, (numeric) The version\n" | |
132 | " \"locktime\" : ttt, (numeric) The lock time\n" | |
133 | " \"vin\" : [ (array of json objects)\n" | |
134 | " {\n" | |
135 | " \"txid\": \"id\", (string) The transaction id\n" | |
136 | " \"vout\": n, (numeric) \n" | |
137 | " \"scriptSig\": { (json object) The script\n" | |
138 | " \"asm\": \"asm\", (string) asm\n" | |
139 | " \"hex\": \"hex\" (string) hex\n" | |
140 | " },\n" | |
141 | " \"sequence\": n (numeric) The script sequence number\n" | |
142 | " }\n" | |
143 | " ,...\n" | |
144 | " ],\n" | |
145 | " \"vout\" : [ (array of json objects)\n" | |
146 | " {\n" | |
147 | " \"value\" : x.xxx, (numeric) The value in btc\n" | |
148 | " \"n\" : n, (numeric) index\n" | |
149 | " \"scriptPubKey\" : { (json object)\n" | |
150 | " \"asm\" : \"asm\", (string) the asm\n" | |
151 | " \"hex\" : \"hex\", (string) the hex\n" | |
152 | " \"reqSigs\" : n, (numeric) The required sigs\n" | |
153 | " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" | |
154 | " \"addresses\" : [ (json array of string)\n" | |
155 | " \"bitcoinaddress\" (string) bitcoin address\n" | |
156 | " ,...\n" | |
157 | " ]\n" | |
158 | " }\n" | |
159 | " }\n" | |
160 | " ,...\n" | |
161 | " ],\n" | |
162 | " \"blockhash\" : \"hash\", (string) the block hash\n" | |
163 | " \"confirmations\" : n, (numeric) The confirmations\n" | |
164 | " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)\n" | |
165 | " \"blocktime\" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" | |
166 | "}\n" | |
167 | ||
168 | "\nExamples:\n" | |
169 | + HelpExampleCli("getrawtransaction", "\"mytxid\"") | |
170 | + HelpExampleCli("getrawtransaction", "\"mytxid\" 1") | |
171 | + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") | |
172 | ); | |
a2709fad | 173 | |
2d43f88e | 174 | uint256 hash = ParseHashV(params[0], "parameter 1"); |
a2709fad GA |
175 | |
176 | bool fVerbose = false; | |
177 | if (params.size() > 1) | |
178 | fVerbose = (params[1].get_int() != 0); | |
179 | ||
180 | CTransaction tx; | |
181 | uint256 hashBlock = 0; | |
450cbb09 | 182 | if (!GetTransaction(hash, tx, hashBlock, true)) |
738835d7 | 183 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); |
a2709fad GA |
184 | |
185 | CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | |
186 | ssTx << tx; | |
187 | string strHex = HexStr(ssTx.begin(), ssTx.end()); | |
188 | ||
189 | if (!fVerbose) | |
190 | return strHex; | |
191 | ||
192 | Object result; | |
193 | result.push_back(Pair("hex", strHex)); | |
194 | TxToJSON(tx, hashBlock, result); | |
195 | return result; | |
196 | } | |
197 | ||
48ba56cd | 198 | #ifdef ENABLE_WALLET |
a2709fad GA |
199 | Value listunspent(const Array& params, bool fHelp) |
200 | { | |
92735bca | 201 | if (fHelp || params.size() > 3) |
a2709fad | 202 | throw runtime_error( |
a6099ef3 | 203 | "listunspent ( minconf maxconf [\"address\",...] )\n" |
204 | "\nReturns array of unspent transaction outputs\n" | |
a2709fad | 205 | "with between minconf and maxconf (inclusive) confirmations.\n" |
a6099ef3 | 206 | "Optionally filter to only include txouts paid to specified addresses.\n" |
a2709fad | 207 | "Results are an array of Objects, each of which has:\n" |
a6099ef3 | 208 | "{txid, vout, scriptPubKey, amount, confirmations}\n" |
209 | "\nArguments:\n" | |
210 | "1. minconf (numeric, optional, default=1) The minimum confirmationsi to filter\n" | |
211 | "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" | |
212 | "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n" | |
213 | " [\n" | |
214 | " \"address\" (string) bitcoin address\n" | |
215 | " ,...\n" | |
216 | " ]\n" | |
217 | "\nResult\n" | |
218 | "[ (array of json object)\n" | |
219 | " {\n" | |
220 | " \"txid\" : \"txid\", (string) the transaction id \n" | |
221 | " \"vout\" : n, (numeric) the vout value\n" | |
222 | " \"address\" : \"address\", (string) the bitcoin address\n" | |
223 | " \"account\" : \"account\", (string) The associated account, or \"\" for the default account\n" | |
224 | " \"scriptPubKey\" : \"key\", (string) the script key\n" | |
225 | " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n" | |
226 | " \"confirmations\" : n (numeric) The number of confirmations\n" | |
227 | " }\n" | |
228 | " ,...\n" | |
229 | "]\n" | |
230 | ||
231 | "\nExamples\n" | |
232 | + HelpExampleCli("listunspent", "") | |
233 | + HelpExampleCli("listunspent", "6 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") | |
234 | + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") | |
235 | ); | |
a2709fad | 236 | |
92735bca | 237 | RPCTypeCheck(params, list_of(int_type)(int_type)(array_type)); |
a2709fad GA |
238 | |
239 | int nMinDepth = 1; | |
240 | if (params.size() > 0) | |
241 | nMinDepth = params[0].get_int(); | |
242 | ||
92735bca | 243 | int nMaxDepth = 9999999; |
a2709fad GA |
244 | if (params.size() > 1) |
245 | nMaxDepth = params[1].get_int(); | |
246 | ||
92735bca GM |
247 | set<CBitcoinAddress> setAddress; |
248 | if (params.size() > 2) | |
249 | { | |
250 | Array inputs = params[2].get_array(); | |
251 | BOOST_FOREACH(Value& input, inputs) | |
252 | { | |
253 | CBitcoinAddress address(input.get_str()); | |
254 | if (!address.IsValid()) | |
738835d7 | 255 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str()); |
92735bca | 256 | if (setAddress.count(address)) |
738835d7 | 257 | throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+input.get_str()); |
92735bca GM |
258 | setAddress.insert(address); |
259 | } | |
260 | } | |
261 | ||
a2709fad GA |
262 | Array results; |
263 | vector<COutput> vecOutputs; | |
b0730874 | 264 | assert(pwalletMain != NULL); |
a2709fad GA |
265 | pwalletMain->AvailableCoins(vecOutputs, false); |
266 | BOOST_FOREACH(const COutput& out, vecOutputs) | |
267 | { | |
268 | if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) | |
269 | continue; | |
270 | ||
2d43f88e | 271 | if (setAddress.size()) |
b1093efa GM |
272 | { |
273 | CTxDestination address; | |
2d43f88e | 274 | if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) |
b1093efa GM |
275 | continue; |
276 | ||
277 | if (!setAddress.count(address)) | |
278 | continue; | |
279 | } | |
92735bca | 280 | |
51ed9ec9 | 281 | int64_t nValue = out.tx->vout[out.i].nValue; |
a2709fad GA |
282 | const CScript& pk = out.tx->vout[out.i].scriptPubKey; |
283 | Object entry; | |
284 | entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); | |
285 | entry.push_back(Pair("vout", out.i)); | |
550479b0 | 286 | CTxDestination address; |
287 | if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) | |
288 | { | |
289 | entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); | |
290 | if (pwalletMain->mapAddressBook.count(address)) | |
61885513 | 291 | entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); |
550479b0 | 292 | } |
a2709fad | 293 | entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); |
03346a61 GA |
294 | if (pk.IsPayToScriptHash()) |
295 | { | |
296 | CTxDestination address; | |
297 | if (ExtractDestination(pk, address)) | |
298 | { | |
299 | const CScriptID& hash = boost::get<const CScriptID&>(address); | |
300 | CScript redeemScript; | |
301 | if (pwalletMain->GetCScript(hash, redeemScript)) | |
302 | entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); | |
303 | } | |
304 | } | |
a2709fad GA |
305 | entry.push_back(Pair("amount",ValueFromAmount(nValue))); |
306 | entry.push_back(Pair("confirmations",out.nDepth)); | |
307 | results.push_back(entry); | |
308 | } | |
309 | ||
310 | return results; | |
311 | } | |
48ba56cd | 312 | #endif |
a2709fad GA |
313 | |
314 | Value createrawtransaction(const Array& params, bool fHelp) | |
315 | { | |
316 | if (fHelp || params.size() != 2) | |
317 | throw runtime_error( | |
a6099ef3 | 318 | "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...}\n" |
319 | "\nCreate a transaction spending the given inputs and sending to the given addresses.\n" | |
a2709fad GA |
320 | "Returns hex-encoded raw transaction.\n" |
321 | "Note that the transaction's inputs are not signed, and\n" | |
a6099ef3 | 322 | "it is not stored in the wallet or transmitted to the network.\n" |
323 | ||
324 | "\nArguments:\n" | |
325 | "1. \"transactions\" (string, required) A json array of json objects\n" | |
326 | " [\n" | |
327 | " {\n" | |
328 | " \"txid\":\"id\", (string, required) The transaction id\n" | |
329 | " \"vout\":n (numeric, required) The output number\n" | |
330 | " }\n" | |
331 | " ,...\n" | |
332 | " ]\n" | |
333 | "2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n" | |
334 | " {\n" | |
335 | " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the btc amount\n" | |
336 | " ,...\n" | |
337 | " }\n" | |
338 | ||
339 | "\nResult:\n" | |
340 | "\"transaction\" (string) hex string of the transaction\n" | |
341 | ||
342 | "\nExamples\n" | |
343 | + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") | |
344 | + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"") | |
345 | ); | |
a2709fad GA |
346 | |
347 | RPCTypeCheck(params, list_of(array_type)(obj_type)); | |
348 | ||
349 | Array inputs = params[0].get_array(); | |
350 | Object sendTo = params[1].get_obj(); | |
351 | ||
352 | CTransaction rawTx; | |
353 | ||
2d43f88e | 354 | BOOST_FOREACH(const Value& input, inputs) |
a2709fad GA |
355 | { |
356 | const Object& o = input.get_obj(); | |
357 | ||
2d43f88e | 358 | uint256 txid = ParseHashO(o, "txid"); |
a2709fad GA |
359 | |
360 | const Value& vout_v = find_value(o, "vout"); | |
361 | if (vout_v.type() != int_type) | |
738835d7 | 362 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); |
a2709fad GA |
363 | int nOutput = vout_v.get_int(); |
364 | if (nOutput < 0) | |
738835d7 | 365 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); |
a2709fad | 366 | |
2d43f88e | 367 | CTxIn in(COutPoint(txid, nOutput)); |
a2709fad GA |
368 | rawTx.vin.push_back(in); |
369 | } | |
370 | ||
371 | set<CBitcoinAddress> setAddress; | |
372 | BOOST_FOREACH(const Pair& s, sendTo) | |
373 | { | |
374 | CBitcoinAddress address(s.name_); | |
375 | if (!address.IsValid()) | |
738835d7 | 376 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_); |
a2709fad GA |
377 | |
378 | if (setAddress.count(address)) | |
738835d7 | 379 | throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_); |
a2709fad GA |
380 | setAddress.insert(address); |
381 | ||
382 | CScript scriptPubKey; | |
383 | scriptPubKey.SetDestination(address.Get()); | |
51ed9ec9 | 384 | int64_t nAmount = AmountFromValue(s.value_); |
a2709fad GA |
385 | |
386 | CTxOut out(nAmount, scriptPubKey); | |
387 | rawTx.vout.push_back(out); | |
388 | } | |
389 | ||
390 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
391 | ss << rawTx; | |
392 | return HexStr(ss.begin(), ss.end()); | |
393 | } | |
394 | ||
395 | Value decoderawtransaction(const Array& params, bool fHelp) | |
396 | { | |
397 | if (fHelp || params.size() != 1) | |
398 | throw runtime_error( | |
a6099ef3 | 399 | "decoderawtransaction \"hexstring\"\n" |
400 | "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" | |
401 | ||
402 | "\nArguments:\n" | |
e0c06d2c | 403 | "1. \"hex\" (string, required) The transaction hex string\n" |
a6099ef3 | 404 | |
405 | "\nResult:\n" | |
406 | "{\n" | |
e0c06d2c | 407 | " \"txid\" : \"id\", (string) The transaction id\n" |
a6099ef3 | 408 | " \"version\" : n, (numeric) The version\n" |
409 | " \"locktime\" : ttt, (numeric) The lock time\n" | |
410 | " \"vin\" : [ (array of json objects)\n" | |
411 | " {\n" | |
412 | " \"txid\": \"id\", (string) The transaction id\n" | |
413 | " \"vout\": n, (numeric) The output number\n" | |
414 | " \"scriptSig\": { (json object) The script\n" | |
415 | " \"asm\": \"asm\", (string) asm\n" | |
416 | " \"hex\": \"hex\" (string) hex\n" | |
417 | " },\n" | |
418 | " \"sequence\": n (numeric) The script sequence number\n" | |
419 | " }\n" | |
420 | " ,...\n" | |
421 | " ],\n" | |
422 | " \"vout\" : [ (array of json objects)\n" | |
423 | " {\n" | |
424 | " \"value\" : x.xxx, (numeric) The value in btc\n" | |
425 | " \"n\" : n, (numeric) index\n" | |
426 | " \"scriptPubKey\" : { (json object)\n" | |
427 | " \"asm\" : \"asm\", (string) the asm\n" | |
428 | " \"hex\" : \"hex\", (string) the hex\n" | |
429 | " \"reqSigs\" : n, (numeric) The required sigs\n" | |
430 | " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" | |
431 | " \"addresses\" : [ (json array of string)\n" | |
432 | " \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) bitcoin address\n" | |
433 | " ,...\n" | |
434 | " ]\n" | |
435 | " }\n" | |
436 | " }\n" | |
437 | " ,...\n" | |
438 | " ],\n" | |
a6099ef3 | 439 | "}\n" |
440 | ||
441 | "\nExamples:\n" | |
442 | + HelpExampleCli("decoderawtransaction", "\"hexstring\"") | |
443 | + HelpExampleRpc("decoderawtransaction", "\"hexstring\"") | |
444 | ); | |
a2709fad | 445 | |
2d43f88e | 446 | vector<unsigned char> txData(ParseHexV(params[0], "argument")); |
a2709fad GA |
447 | CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); |
448 | CTransaction tx; | |
449 | try { | |
450 | ssData >> tx; | |
451 | } | |
452 | catch (std::exception &e) { | |
738835d7 | 453 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); |
a2709fad GA |
454 | } |
455 | ||
456 | Object result; | |
457 | TxToJSON(tx, 0, result); | |
458 | ||
459 | return result; | |
460 | } | |
461 | ||
be066fad PT |
462 | Value decodescript(const Array& params, bool fHelp) |
463 | { | |
464 | if (fHelp || params.size() != 1) | |
465 | throw runtime_error( | |
a6099ef3 | 466 | "decodescript \"hex\"\n" |
467 | "\nDecode a hex-encoded script.\n" | |
468 | "\nArguments:\n" | |
469 | "1. \"hex\" (string) the hex encoded script\n" | |
470 | "\nResult:\n" | |
471 | "{\n" | |
472 | " \"asm\":\"asm\", (string) Script public key\n" | |
473 | " \"hex\":\"hex\", (string) hex encoded public key\n" | |
474 | " \"type\":\"type\", (string) The output type\n" | |
475 | " \"reqSigs\": n, (numeric) The required signatures\n" | |
476 | " \"addresses\": [ (json array of string)\n" | |
477 | " \"address\" (string) bitcoin address\n" | |
478 | " ,...\n" | |
479 | " ],\n" | |
480 | " \"p2sh\",\"address\" (string) script address\n" | |
481 | "}\n" | |
482 | "\nExamples:\n" | |
483 | + HelpExampleCli("decodescript", "\"hexstring\"") | |
484 | + HelpExampleRpc("decodescript", "\"hexstring\"") | |
485 | ); | |
be066fad PT |
486 | |
487 | RPCTypeCheck(params, list_of(str_type)); | |
488 | ||
489 | Object r; | |
490 | CScript script; | |
491 | if (params[0].get_str().size() > 0){ | |
492 | vector<unsigned char> scriptData(ParseHexV(params[0], "argument")); | |
493 | script = CScript(scriptData.begin(), scriptData.end()); | |
494 | } else { | |
495 | // Empty scripts are valid | |
496 | } | |
497 | ScriptPubKeyToJSON(script, r, false); | |
498 | ||
499 | r.push_back(Pair("p2sh", CBitcoinAddress(script.GetID()).ToString())); | |
500 | return r; | |
501 | } | |
502 | ||
a2709fad GA |
503 | Value signrawtransaction(const Array& params, bool fHelp) |
504 | { | |
3c3666d6 | 505 | if (fHelp || params.size() < 1 || params.size() > 4) |
a2709fad | 506 | throw runtime_error( |
a6099ef3 | 507 | "signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n" |
508 | "\nSign inputs for raw transaction (serialized, hex-encoded).\n" | |
509 | "The second optional argument (may be null) is an array of previous transaction outputs that\n" | |
729b1806 | 510 | "this transaction depends on but may not yet be in the block chain.\n" |
a6099ef3 | 511 | "The third optional argument (may be null) is an array of base58-encoded private\n" |
a2709fad | 512 | "keys that, if given, will be the only keys used to sign the transaction.\n" |
48ba56cd | 513 | #ifdef ENABLE_WALLET |
a6099ef3 | 514 | + HelpRequiringPassphrase() + "\n" |
48ba56cd | 515 | #endif |
a6099ef3 | 516 | |
517 | "\nArguments:\n" | |
518 | "1. \"hexstring\" (string, required) The transaction hex string\n" | |
519 | "2. \"prevtxs\" (string, optional) An json array of previous dependent transaction outputs\n" | |
041f71bb | 520 | " [ (json array of json objects, or 'null' if none provided)\n" |
a6099ef3 | 521 | " {\n" |
522 | " \"txid\":\"id\", (string, required) The transaction id\n" | |
523 | " \"vout\":n, (numeric, required) The output number\n" | |
524 | " \"scriptPubKey\": \"hex\", (string, required) script key\n" | |
525 | " \"redeemScript\": \"hex\" (string, required) redeem script\n" | |
526 | " }\n" | |
527 | " ,...\n" | |
528 | " ]\n" | |
529 | "3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n" | |
041f71bb | 530 | " [ (json array of strings, or 'null' if none provided)\n" |
a6099ef3 | 531 | " \"privatekey\" (string) private key in base58-encoding\n" |
532 | " ,...\n" | |
533 | " ]\n" | |
ab643811 | 534 | "4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n" |
a6099ef3 | 535 | " \"ALL\"\n" |
536 | " \"NONE\"\n" | |
537 | " \"SINGLE\"\n" | |
538 | " \"ALL|ANYONECANPAY\"\n" | |
539 | " \"NONE|ANYONECANPAY\"\n" | |
540 | " \"SINGLE|ANYONECANPAY\"\n" | |
541 | ||
542 | "\nResult:\n" | |
543 | "{\n" | |
544 | " \"hex\": \"value\", (string) The raw transaction with signature(s) (hex-encoded string)\n" | |
545 | " \"complete\": n (numeric) if transaction has a complete set of signature (0 if not)\n" | |
546 | "}\n" | |
547 | ||
548 | "\nExamples:\n" | |
549 | + HelpExampleCli("signrawtransaction", "\"myhex\"") | |
550 | + HelpExampleRpc("signrawtransaction", "\"myhex\"") | |
551 | ); | |
a2709fad | 552 | |
cc6dfd1f | 553 | RPCTypeCheck(params, list_of(str_type)(array_type)(array_type)(str_type), true); |
a2709fad | 554 | |
2d43f88e | 555 | vector<unsigned char> txData(ParseHexV(params[0], "argument 1")); |
a2709fad GA |
556 | CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); |
557 | vector<CTransaction> txVariants; | |
558 | while (!ssData.empty()) | |
559 | { | |
560 | try { | |
561 | CTransaction tx; | |
562 | ssData >> tx; | |
563 | txVariants.push_back(tx); | |
564 | } | |
565 | catch (std::exception &e) { | |
738835d7 | 566 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); |
a2709fad GA |
567 | } |
568 | } | |
569 | ||
570 | if (txVariants.empty()) | |
738835d7 | 571 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction"); |
a2709fad GA |
572 | |
573 | // mergedTx will end up with all the signatures; it | |
574 | // starts as a clone of the rawtx: | |
575 | CTransaction mergedTx(txVariants[0]); | |
576 | bool fComplete = true; | |
577 | ||
578 | // Fetch previous transactions (inputs): | |
450cbb09 PW |
579 | CCoinsView viewDummy; |
580 | CCoinsViewCache view(viewDummy); | |
a2709fad | 581 | { |
450cbb09 | 582 | LOCK(mempool.cs); |
ae8bfd12 PW |
583 | CCoinsViewCache &viewChain = *pcoinsTip; |
584 | CCoinsViewMemPool viewMempool(viewChain, mempool); | |
450cbb09 PW |
585 | view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view |
586 | ||
587 | BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { | |
a2709fad | 588 | const uint256& prevHash = txin.prevout.hash; |
450cbb09 PW |
589 | CCoins coins; |
590 | view.GetCoins(prevHash, coins); // this is certainly allowed to fail | |
a2709fad | 591 | } |
450cbb09 | 592 | |
ae8bfd12 | 593 | view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long |
a2709fad GA |
594 | } |
595 | ||
03346a61 GA |
596 | bool fGivenKeys = false; |
597 | CBasicKeyStore tempKeystore; | |
598 | if (params.size() > 2 && params[2].type() != null_type) | |
599 | { | |
600 | fGivenKeys = true; | |
601 | Array keys = params[2].get_array(); | |
602 | BOOST_FOREACH(Value k, keys) | |
603 | { | |
604 | CBitcoinSecret vchSecret; | |
605 | bool fGood = vchSecret.SetString(k.get_str()); | |
606 | if (!fGood) | |
607 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); | |
dfa23b94 | 608 | CKey key = vchSecret.GetKey(); |
03346a61 GA |
609 | tempKeystore.AddKey(key); |
610 | } | |
611 | } | |
48ba56cd | 612 | #ifdef ENABLE_WALLET |
03346a61 GA |
613 | else |
614 | EnsureWalletIsUnlocked(); | |
48ba56cd | 615 | #endif |
03346a61 | 616 | |
a2709fad | 617 | // Add previous txouts given in the RPC call: |
cc6dfd1f | 618 | if (params.size() > 1 && params[1].type() != null_type) |
a2709fad GA |
619 | { |
620 | Array prevTxs = params[1].get_array(); | |
621 | BOOST_FOREACH(Value& p, prevTxs) | |
622 | { | |
623 | if (p.type() != obj_type) | |
738835d7 | 624 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); |
a2709fad GA |
625 | |
626 | Object prevOut = p.get_obj(); | |
627 | ||
21c6d3ae | 628 | RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)); |
a2709fad | 629 | |
2d43f88e | 630 | uint256 txid = ParseHashO(prevOut, "txid"); |
a2709fad GA |
631 | |
632 | int nOut = find_value(prevOut, "vout").get_int(); | |
633 | if (nOut < 0) | |
738835d7 | 634 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); |
a2709fad | 635 | |
2d43f88e | 636 | vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); |
a2709fad GA |
637 | CScript scriptPubKey(pkData.begin(), pkData.end()); |
638 | ||
450cbb09 PW |
639 | CCoins coins; |
640 | if (view.GetCoins(txid, coins)) { | |
641 | if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) { | |
a2709fad | 642 | string err("Previous output scriptPubKey mismatch:\n"); |
450cbb09 | 643 | err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ |
a2709fad | 644 | scriptPubKey.ToString(); |
738835d7 | 645 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); |
a2709fad | 646 | } |
450cbb09 | 647 | // what todo if txid is known, but the actual output isn't? |
a2709fad | 648 | } |
03346a61 GA |
649 | if ((unsigned int)nOut >= coins.vout.size()) |
650 | coins.vout.resize(nOut+1); | |
450cbb09 PW |
651 | coins.vout[nOut].scriptPubKey = scriptPubKey; |
652 | coins.vout[nOut].nValue = 0; // we don't know the actual output value | |
653 | view.SetCoins(txid, coins); | |
a2709fad | 654 | |
03346a61 GA |
655 | // if redeemScript given and not using the local wallet (private keys |
656 | // given), add redeemScript to the tempKeystore so it can be signed: | |
21c6d3ae | 657 | if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) |
03346a61 | 658 | { |
21c6d3ae GM |
659 | RPCTypeCheck(prevOut, map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type)); |
660 | Value v = find_value(prevOut, "redeemScript"); | |
661 | if (!(v == Value::null)) | |
662 | { | |
663 | vector<unsigned char> rsData(ParseHexV(v, "redeemScript")); | |
664 | CScript redeemScript(rsData.begin(), rsData.end()); | |
665 | tempKeystore.AddCScript(redeemScript); | |
666 | } | |
03346a61 | 667 | } |
a2709fad GA |
668 | } |
669 | } | |
cc6dfd1f | 670 | |
48ba56cd | 671 | #ifdef ENABLE_WALLET |
b0730874 | 672 | const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); |
48ba56cd WL |
673 | #else |
674 | const CKeyStore& keystore = tempKeystore; | |
675 | #endif | |
a2709fad | 676 | |
3c3666d6 | 677 | int nHashType = SIGHASH_ALL; |
cc6dfd1f | 678 | if (params.size() > 3 && params[3].type() != null_type) |
3c3666d6 GA |
679 | { |
680 | static map<string, int> mapSigHashValues = | |
681 | boost::assign::map_list_of | |
682 | (string("ALL"), int(SIGHASH_ALL)) | |
683 | (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) | |
684 | (string("NONE"), int(SIGHASH_NONE)) | |
685 | (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) | |
686 | (string("SINGLE"), int(SIGHASH_SINGLE)) | |
687 | (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) | |
688 | ; | |
689 | string strHashType = params[3].get_str(); | |
690 | if (mapSigHashValues.count(strHashType)) | |
691 | nHashType = mapSigHashValues[strHashType]; | |
692 | else | |
738835d7 | 693 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); |
3c3666d6 GA |
694 | } |
695 | ||
d5e7b611 GA |
696 | bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); |
697 | ||
a2709fad | 698 | // Sign what we can: |
dab9fa7f | 699 | for (unsigned int i = 0; i < mergedTx.vin.size(); i++) |
a2709fad GA |
700 | { |
701 | CTxIn& txin = mergedTx.vin[i]; | |
450cbb09 PW |
702 | CCoins coins; |
703 | if (!view.GetCoins(txin.prevout.hash, coins) || !coins.IsAvailable(txin.prevout.n)) | |
a2709fad GA |
704 | { |
705 | fComplete = false; | |
706 | continue; | |
707 | } | |
450cbb09 | 708 | const CScript& prevPubKey = coins.vout[txin.prevout.n].scriptPubKey; |
a2709fad GA |
709 | |
710 | txin.scriptSig.clear(); | |
d5e7b611 GA |
711 | // Only sign SIGHASH_SINGLE if there's a corresponding output: |
712 | if (!fHashSingle || (i < mergedTx.vout.size())) | |
713 | SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); | |
a2709fad GA |
714 | |
715 | // ... and merge in other signatures: | |
716 | BOOST_FOREACH(const CTransaction& txv, txVariants) | |
717 | { | |
718 | txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); | |
719 | } | |
68f7d1d7 | 720 | if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STANDARD_SCRIPT_VERIFY_FLAGS, 0)) |
a2709fad GA |
721 | fComplete = false; |
722 | } | |
723 | ||
724 | Object result; | |
725 | CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); | |
726 | ssTx << mergedTx; | |
727 | result.push_back(Pair("hex", HexStr(ssTx.begin(), ssTx.end()))); | |
728 | result.push_back(Pair("complete", fComplete)); | |
729 | ||
730 | return result; | |
731 | } | |
732 | ||
733 | Value sendrawtransaction(const Array& params, bool fHelp) | |
734 | { | |
9d14e689 | 735 | if (fHelp || params.size() < 1 || params.size() > 2) |
a2709fad | 736 | throw runtime_error( |
a6099ef3 | 737 | "sendrawtransaction \"hexstring\" ( allowhighfees )\n" |
738 | "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" | |
739 | "\nAlso see createrawtransaction and signrawtransaction calls.\n" | |
740 | "\nArguments:\n" | |
741 | "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" | |
742 | "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" | |
743 | "\nResult:\n" | |
744 | "\"hex\" (string) The transaction hash in hex\n" | |
745 | "\nExamples:\n" | |
746 | "\nCreate a transaction\n" | |
747 | + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + | |
748 | "Sign the transaction, and get back the hex\n" | |
749 | + HelpExampleCli("signrawtransaction", "\"myhex\"") + | |
750 | "\nSend the transaction (signed hex)\n" | |
751 | + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + | |
752 | "\nAs a json rpc call\n" | |
753 | + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") | |
754 | ); | |
755 | ||
a2709fad | 756 | |
a2709fad | 757 | // parse hex string from parameter |
2d43f88e | 758 | vector<unsigned char> txData(ParseHexV(params[0], "parameter")); |
a2709fad GA |
759 | CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); |
760 | CTransaction tx; | |
761 | ||
9d14e689 GM |
762 | bool fOverrideFees = false; |
763 | if (params.size() > 1) | |
764 | fOverrideFees = params[1].get_bool(); | |
765 | ||
a2709fad GA |
766 | // deserialize binary data stream |
767 | try { | |
768 | ssData >> tx; | |
769 | } | |
770 | catch (std::exception &e) { | |
738835d7 | 771 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); |
a2709fad | 772 | } |
771ffb5e | 773 | uint256 hashTx = tx.GetHash(); |
a2709fad | 774 | |
ae8bfd12 | 775 | CCoinsViewCache &view = *pcoinsTip; |
450cbb09 | 776 | CCoins existingCoins; |
1d46fe33 WL |
777 | bool fHaveMempool = mempool.exists(hashTx); |
778 | bool fHaveChain = view.GetCoins(hashTx, existingCoins) && existingCoins.nHeight < 1000000000; | |
779 | if (!fHaveMempool && !fHaveChain) { | |
780 | // push to local node and sync with wallets | |
781 | CValidationState state; | |
782 | if (AcceptToMemoryPool(mempool, state, tx, false, NULL, !fOverrideFees)) | |
783 | SyncWithWallets(hashTx, tx, NULL); | |
784 | else { | |
785 | if(state.IsInvalid()) | |
786 | throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); | |
787 | else | |
788 | throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason()); | |
450cbb09 | 789 | } |
1d46fe33 WL |
790 | } else if (fHaveChain) { |
791 | throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); | |
771ffb5e | 792 | } |
269d9c64 | 793 | RelayTransaction(tx, hashTx); |
a2709fad | 794 | |
771ffb5e | 795 | return hashTx.GetHex(); |
a2709fad | 796 | } |