]>
Commit | Line | Data |
---|---|---|
652e1569 | 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 |
652e1569 WL |
4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | ||
6 | #include "base58.h" | |
71697f97 | 7 | #include "clientversion.h" |
652e1569 WL |
8 | #include "init.h" |
9 | #include "main.h" | |
10 | #include "net.h" | |
11 | #include "netbase.h" | |
c037531d | 12 | #include "rpcserver.h" |
14f888ca | 13 | #include "timedata.h" |
652e1569 WL |
14 | #include "util.h" |
15 | #ifdef ENABLE_WALLET | |
50c72f23 JS |
16 | #include "wallet/wallet.h" |
17 | #include "wallet/walletdb.h" | |
652e1569 WL |
18 | #endif |
19 | ||
20 | #include <stdint.h> | |
21 | ||
22 | #include <boost/assign/list_of.hpp> | |
23 | #include "json/json_spirit_utils.h" | |
24 | #include "json/json_spirit_value.h" | |
25 | ||
652e1569 | 26 | using namespace json_spirit; |
40a158e1 | 27 | using namespace std; |
652e1569 | 28 | |
f9de17ec WL |
29 | /** |
30 | * @note Do not add or change anything in the information returned by this | |
72fb3d29 | 31 | * method. `getinfo` exists for backwards-compatibility only. It combines |
f9de17ec WL |
32 | * information from wildly different sources in the program, which is a mess, |
33 | * and is thus planned to be deprecated eventually. | |
34 | * | |
35 | * Based on the source of the information, new information should be added to: | |
36 | * - `getblockchaininfo`, | |
37 | * - `getnetworkinfo` or | |
38 | * - `getwalletinfo` | |
39 | * | |
40 | * Or alternatively, create a specific query method for the information. | |
41 | **/ | |
da16b12e | 42 | uint64_t komodo_interestsum(); |
c75c18fc | 43 | int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp); |
09e3cf94 | 44 | |
16bc9aaf WL |
45 | Value getinfo(const Array& params, bool fHelp) |
46 | { | |
c75c18fc | 47 | uint256 notarized_hash,notarized_desttxid; |
48 | int32_t notarized_height; | |
16bc9aaf WL |
49 | if (fHelp || params.size() != 0) |
50 | throw runtime_error( | |
51 | "getinfo\n" | |
52 | "Returns an object containing various state info.\n" | |
53 | "\nResult:\n" | |
54 | "{\n" | |
55 | " \"version\": xxxxx, (numeric) the server version\n" | |
56 | " \"protocolversion\": xxxxx, (numeric) the protocol version\n" | |
57 | " \"walletversion\": xxxxx, (numeric) the wallet version\n" | |
58 | " \"balance\": xxxxxxx, (numeric) the total bitcoin balance of the wallet\n" | |
59 | " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" | |
60 | " \"timeoffset\": xxxxx, (numeric) the time offset\n" | |
61 | " \"connections\": xxxxx, (numeric) the number of connections\n" | |
62 | " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" | |
63 | " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" | |
64 | " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" | |
65 | " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" | |
66 | " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" | |
16bc9aaf | 67 | " \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n" |
1294cdc4 GM |
68 | " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc/kb\n" |
69 | " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n" | |
16bc9aaf WL |
70 | " \"errors\": \"...\" (string) any error messages\n" |
71 | "}\n" | |
72 | "\nExamples:\n" | |
73 | + HelpExampleCli("getinfo", "") | |
74 | + HelpExampleRpc("getinfo", "") | |
75 | ); | |
76 | ||
4401b2d7 EL |
77 | #ifdef ENABLE_WALLET |
78 | LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); | |
79 | #else | |
80 | LOCK(cs_main); | |
81 | #endif | |
82 | ||
16bc9aaf WL |
83 | proxyType proxy; |
84 | GetProxy(NET_IPV4, proxy); | |
c75c18fc | 85 | notarized_height = komodo_notarized_height(¬arized_hash,¬arized_desttxid); |
16bc9aaf WL |
86 | |
87 | Object obj; | |
faadbe17 PK |
88 | obj.push_back(Pair("version", CLIENT_VERSION)); |
89 | obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); | |
c75c18fc | 90 | obj.push_back(Pair("notarized", notarized_height)); |
91 | obj.push_back(Pair("notarizedhash", notarized_hash.ToString())); | |
92 | obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString())); | |
16bc9aaf WL |
93 | #ifdef ENABLE_WALLET |
94 | if (pwalletMain) { | |
95 | obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); | |
96 | obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); | |
da16b12e | 97 | obj.push_back(Pair("interest", ValueFromAmount(komodo_interestsum()))); |
16bc9aaf WL |
98 | } |
99 | #endif | |
100 | obj.push_back(Pair("blocks", (int)chainActive.Height())); | |
d56e30ca | 101 | obj.push_back(Pair("timeoffset", GetTimeOffset())); |
98d166cf | 102 | if ( chainActive.Tip() != 0 ) |
49c9db6a | 103 | obj.push_back(Pair("tiptime", (int)chainActive.Tip()->nTime)); |
16bc9aaf | 104 | obj.push_back(Pair("connections", (int)vNodes.size())); |
67a79493 | 105 | obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); |
16bc9aaf | 106 | obj.push_back(Pair("difficulty", (double)GetDifficulty())); |
cc972107 | 107 | obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); |
16bc9aaf WL |
108 | #ifdef ENABLE_WALLET |
109 | if (pwalletMain) { | |
d56e30ca | 110 | obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); |
16bc9aaf WL |
111 | obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); |
112 | } | |
16bc9aaf | 113 | if (pwalletMain && pwalletMain->IsCrypted()) |
d56e30ca | 114 | obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); |
c6cb21d1 | 115 | obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); |
16bc9aaf | 116 | #endif |
13fc83c7 | 117 | obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); |
16bc9aaf WL |
118 | obj.push_back(Pair("errors", GetWarnings("statusbar"))); |
119 | return obj; | |
120 | } | |
121 | ||
452955f5 WL |
122 | #ifdef ENABLE_WALLET |
123 | class DescribeAddressVisitor : public boost::static_visitor<Object> | |
124 | { | |
c8988460 PW |
125 | private: |
126 | isminetype mine; | |
127 | ||
452955f5 | 128 | public: |
c8988460 PW |
129 | DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {} |
130 | ||
452955f5 WL |
131 | Object operator()(const CNoDestination &dest) const { return Object(); } |
132 | ||
133 | Object operator()(const CKeyID &keyID) const { | |
134 | Object obj; | |
135 | CPubKey vchPubKey; | |
452955f5 | 136 | obj.push_back(Pair("isscript", false)); |
a3e192a3 | 137 | if (mine == ISMINE_SPENDABLE) { |
c8988460 PW |
138 | pwalletMain->GetPubKey(keyID, vchPubKey); |
139 | obj.push_back(Pair("pubkey", HexStr(vchPubKey))); | |
140 | obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); | |
141 | } | |
452955f5 WL |
142 | return obj; |
143 | } | |
144 | ||
145 | Object operator()(const CScriptID &scriptID) const { | |
146 | Object obj; | |
147 | obj.push_back(Pair("isscript", true)); | |
a3e192a3 | 148 | if (mine != ISMINE_NO) { |
c8988460 PW |
149 | CScript subscript; |
150 | pwalletMain->GetCScript(scriptID, subscript); | |
151 | std::vector<CTxDestination> addresses; | |
152 | txnouttype whichType; | |
153 | int nRequired; | |
154 | ExtractDestinations(subscript, whichType, addresses, nRequired); | |
155 | obj.push_back(Pair("script", GetTxnOutputType(whichType))); | |
156 | obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); | |
157 | Array a; | |
158 | BOOST_FOREACH(const CTxDestination& addr, addresses) | |
159 | a.push_back(CBitcoinAddress(addr).ToString()); | |
160 | obj.push_back(Pair("addresses", a)); | |
161 | if (whichType == TX_MULTISIG) | |
162 | obj.push_back(Pair("sigsrequired", nRequired)); | |
163 | } | |
452955f5 WL |
164 | return obj; |
165 | } | |
166 | }; | |
167 | #endif | |
168 | ||
169 | Value validateaddress(const Array& params, bool fHelp) | |
170 | { | |
171 | if (fHelp || params.size() != 1) | |
172 | throw runtime_error( | |
173 | "validateaddress \"bitcoinaddress\"\n" | |
174 | "\nReturn information about the given bitcoin address.\n" | |
175 | "\nArguments:\n" | |
176 | "1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n" | |
177 | "\nResult:\n" | |
178 | "{\n" | |
179 | " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" | |
180 | " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n" | |
426a74ed | 181 | " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" |
452955f5 WL |
182 | " \"ismine\" : true|false, (boolean) If the address is yours or not\n" |
183 | " \"isscript\" : true|false, (boolean) If the key is a script\n" | |
184 | " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n" | |
185 | " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" | |
7b782f5b | 186 | " \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n" |
452955f5 WL |
187 | "}\n" |
188 | "\nExamples:\n" | |
189 | + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") | |
190 | + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") | |
191 | ); | |
192 | ||
4401b2d7 EL |
193 | #ifdef ENABLE_WALLET |
194 | LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); | |
195 | #else | |
196 | LOCK(cs_main); | |
197 | #endif | |
198 | ||
452955f5 WL |
199 | CBitcoinAddress address(params[0].get_str()); |
200 | bool isValid = address.IsValid(); | |
201 | ||
202 | Object ret; | |
203 | ret.push_back(Pair("isvalid", isValid)); | |
204 | if (isValid) | |
205 | { | |
206 | CTxDestination dest = address.Get(); | |
207 | string currentAddress = address.ToString(); | |
208 | ret.push_back(Pair("address", currentAddress)); | |
426a74ed PT |
209 | |
210 | CScript scriptPubKey = GetScriptForDestination(dest); | |
211 | ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); | |
212 | ||
452955f5 | 213 | #ifdef ENABLE_WALLET |
a3e192a3 J |
214 | isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; |
215 | ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); | |
216 | if (mine != ISMINE_NO) { | |
217 | ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false)); | |
c8988460 | 218 | Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest); |
452955f5 WL |
219 | ret.insert(ret.end(), detail.begin(), detail.end()); |
220 | } | |
221 | if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) | |
222 | ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); | |
223 | #endif | |
224 | } | |
225 | return ret; | |
226 | } | |
227 | ||
72fb3d29 MF |
228 | /** |
229 | * Used by addmultisigaddress / createmultisig: | |
230 | */ | |
787ee0c9 | 231 | CScript _createmultisig_redeemScript(const Array& params) |
723a03d2 WL |
232 | { |
233 | int nRequired = params[0].get_int(); | |
234 | const Array& keys = params[1].get_array(); | |
235 | ||
236 | // Gather public keys | |
237 | if (nRequired < 1) | |
238 | throw runtime_error("a multisignature address must require at least one key to redeem"); | |
239 | if ((int)keys.size() < nRequired) | |
240 | throw runtime_error( | |
241 | strprintf("not enough keys supplied " | |
783b182c | 242 | "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired)); |
e5d9d77d | 243 | if (keys.size() > 16) |
244 | throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); | |
723a03d2 WL |
245 | std::vector<CPubKey> pubkeys; |
246 | pubkeys.resize(keys.size()); | |
247 | for (unsigned int i = 0; i < keys.size(); i++) | |
248 | { | |
249 | const std::string& ks = keys[i].get_str(); | |
250 | #ifdef ENABLE_WALLET | |
251 | // Case 1: Bitcoin address and we have full public key: | |
252 | CBitcoinAddress address(ks); | |
253 | if (pwalletMain && address.IsValid()) | |
254 | { | |
255 | CKeyID keyID; | |
256 | if (!address.GetKeyID(keyID)) | |
257 | throw runtime_error( | |
7d9d134b | 258 | strprintf("%s does not refer to a key",ks)); |
723a03d2 WL |
259 | CPubKey vchPubKey; |
260 | if (!pwalletMain->GetPubKey(keyID, vchPubKey)) | |
261 | throw runtime_error( | |
7d9d134b | 262 | strprintf("no full public key for address %s",ks)); |
723a03d2 WL |
263 | if (!vchPubKey.IsFullyValid()) |
264 | throw runtime_error(" Invalid public key: "+ks); | |
265 | pubkeys[i] = vchPubKey; | |
266 | } | |
267 | ||
268 | // Case 2: hex public key | |
269 | else | |
270 | #endif | |
271 | if (IsHex(ks)) | |
272 | { | |
273 | CPubKey vchPubKey(ParseHex(ks)); | |
274 | if (!vchPubKey.IsFullyValid()) | |
275 | throw runtime_error(" Invalid public key: "+ks); | |
276 | pubkeys[i] = vchPubKey; | |
277 | } | |
278 | else | |
279 | { | |
280 | throw runtime_error(" Invalid public key: "+ks); | |
281 | } | |
282 | } | |
0be990ba | 283 | CScript result = GetScriptForMultisig(nRequired, pubkeys); |
787ee0c9 PT |
284 | |
285 | if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) | |
286 | throw runtime_error( | |
287 | strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)); | |
288 | ||
723a03d2 WL |
289 | return result; |
290 | } | |
291 | ||
292 | Value createmultisig(const Array& params, bool fHelp) | |
293 | { | |
294 | if (fHelp || params.size() < 2 || params.size() > 2) | |
295 | { | |
296 | string msg = "createmultisig nrequired [\"key\",...]\n" | |
297 | "\nCreates a multi-signature address with n signature of m keys required.\n" | |
298 | "It returns a json object with the address and redeemScript.\n" | |
299 | ||
300 | "\nArguments:\n" | |
301 | "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" | |
302 | "2. \"keys\" (string, required) A json array of keys which are bitcoin addresses or hex-encoded public keys\n" | |
303 | " [\n" | |
304 | " \"key\" (string) bitcoin address or hex-encoded public key\n" | |
305 | " ,...\n" | |
306 | " ]\n" | |
307 | ||
308 | "\nResult:\n" | |
309 | "{\n" | |
310 | " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n" | |
311 | " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n" | |
312 | "}\n" | |
313 | ||
314 | "\nExamples:\n" | |
315 | "\nCreate a multisig address from 2 addresses\n" | |
316 | + HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") + | |
317 | "\nAs a json rpc call\n" | |
e3e3728f | 318 | + HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") |
723a03d2 WL |
319 | ; |
320 | throw runtime_error(msg); | |
321 | } | |
322 | ||
323 | // Construct using pay-to-script-hash: | |
787ee0c9 | 324 | CScript inner = _createmultisig_redeemScript(params); |
066e2a14 | 325 | CScriptID innerID(inner); |
723a03d2 WL |
326 | CBitcoinAddress address(innerID); |
327 | ||
328 | Object result; | |
329 | result.push_back(Pair("address", address.ToString())); | |
330 | result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); | |
331 | ||
332 | return result; | |
333 | } | |
334 | ||
c3a7f516 WL |
335 | Value verifymessage(const Array& params, bool fHelp) |
336 | { | |
337 | if (fHelp || params.size() != 3) | |
338 | throw runtime_error( | |
339 | "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n" | |
340 | "\nVerify a signed message\n" | |
341 | "\nArguments:\n" | |
342 | "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n" | |
343 | "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" | |
344 | "3. \"message\" (string, required) The message that was signed.\n" | |
345 | "\nResult:\n" | |
346 | "true|false (boolean) If the signature is verified or not.\n" | |
347 | "\nExamples:\n" | |
348 | "\nUnlock the wallet for 30 seconds\n" | |
349 | + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + | |
350 | "\nCreate the signature\n" | |
351 | + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") + | |
352 | "\nVerify the signature\n" | |
353 | + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") + | |
354 | "\nAs json rpc\n" | |
355 | + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"") | |
356 | ); | |
357 | ||
4401b2d7 EL |
358 | LOCK(cs_main); |
359 | ||
c3a7f516 WL |
360 | string strAddress = params[0].get_str(); |
361 | string strSign = params[1].get_str(); | |
362 | string strMessage = params[2].get_str(); | |
363 | ||
364 | CBitcoinAddress addr(strAddress); | |
365 | if (!addr.IsValid()) | |
366 | throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); | |
367 | ||
368 | CKeyID keyID; | |
369 | if (!addr.GetKeyID(keyID)) | |
370 | throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); | |
371 | ||
372 | bool fInvalid = false; | |
373 | vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); | |
374 | ||
375 | if (fInvalid) | |
376 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); | |
377 | ||
378 | CHashWriter ss(SER_GETHASH, 0); | |
379 | ss << strMessageMagic; | |
380 | ss << strMessage; | |
381 | ||
382 | CPubKey pubkey; | |
383 | if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) | |
384 | return false; | |
385 | ||
386 | return (pubkey.GetID() == keyID); | |
387 | } | |
a8b2ce55 GA |
388 | |
389 | Value setmocktime(const Array& params, bool fHelp) | |
390 | { | |
391 | if (fHelp || params.size() != 1) | |
392 | throw runtime_error( | |
393 | "setmocktime timestamp\n" | |
394 | "\nSet the local time to given timestamp (-regtest only)\n" | |
395 | "\nArguments:\n" | |
396 | "1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n" | |
397 | " Pass 0 to go back to using the system time." | |
398 | ); | |
399 | ||
400 | if (!Params().MineBlocksOnDemand()) | |
401 | throw runtime_error("setmocktime for regression testing (-regtest mode) only"); | |
402 | ||
4401b2d7 EL |
403 | LOCK(cs_main); |
404 | ||
a8b2ce55 GA |
405 | RPCTypeCheck(params, boost::assign::list_of(int_type)); |
406 | SetMockTime(params[0].get_int64()); | |
407 | ||
408 | return Value::null; | |
409 | } |