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