]>
Commit | Line | Data |
---|---|---|
1 | // Copyright (c) 2010 Satoshi Nakamoto | |
2 | // Copyright (c) 2009-2014 The Bitcoin Core developers | |
3 | // Distributed under the MIT software license, see the accompanying | |
4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
5 | ||
6 | #include "base58.h" | |
7 | #include "clientversion.h" | |
8 | #include "init.h" | |
9 | #include "main.h" | |
10 | #include "net.h" | |
11 | #include "netbase.h" | |
12 | #include "rpcserver.h" | |
13 | #include "timedata.h" | |
14 | #include "util.h" | |
15 | #ifdef ENABLE_WALLET | |
16 | #include "wallet/wallet.h" | |
17 | #include "wallet/walletdb.h" | |
18 | #endif | |
19 | ||
20 | #include <stdint.h> | |
21 | ||
22 | #include <boost/assign/list_of.hpp> | |
23 | ||
24 | #include <univalue.h> | |
25 | ||
26 | #include "zcash/Address.hpp" | |
27 | ||
28 | using namespace std; | |
29 | ||
30 | /** | |
31 | * @note Do not add or change anything in the information returned by this | |
32 | * method. `getinfo` exists for backwards-compatibility only. It combines | |
33 | * information from wildly different sources in the program, which is a mess, | |
34 | * and is thus planned to be deprecated eventually. | |
35 | * | |
36 | * Based on the source of the information, new information should be added to: | |
37 | * - `getblockchaininfo`, | |
38 | * - `getnetworkinfo` or | |
39 | * - `getwalletinfo` | |
40 | * | |
41 | * Or alternatively, create a specific query method for the information. | |
42 | **/ | |
43 | ||
44 | int32_t Jumblr_depositaddradd(char *depositaddr); | |
45 | int32_t Jumblr_secretaddradd(char *secretaddr); | |
46 | uint64_t komodo_interestsum(); | |
47 | int32_t komodo_longestchain(); | |
48 | int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp); | |
49 | uint32_t komodo_chainactive_timestamp(); | |
50 | int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp); | |
51 | extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE; | |
52 | extern char ASSETCHAINS_SYMBOL[]; | |
53 | int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp); | |
54 | #define KOMODO_VERSION "0.1.1" | |
55 | uint32_t komodo_chainactive_timestamp(); | |
56 | ||
57 | UniValue getinfo(const UniValue& params, bool fHelp) | |
58 | { | |
59 | uint256 notarized_hash,notarized_desttxid; int32_t notarized_height,longestchain,kmdnotarized_height,txid_height; | |
60 | if (fHelp || params.size() != 0) | |
61 | throw runtime_error( | |
62 | "getinfo\n" | |
63 | "Returns an object containing various state info.\n" | |
64 | "\nResult:\n" | |
65 | "{\n" | |
66 | " \"version\": xxxxx, (numeric) the server version\n" | |
67 | " \"protocolversion\": xxxxx, (numeric) the protocol version\n" | |
68 | " \"walletversion\": xxxxx, (numeric) the wallet version\n" | |
69 | " \"balance\": xxxxxxx, (numeric) the total Zcash balance of the wallet\n" | |
70 | " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" | |
71 | " \"timeoffset\": xxxxx, (numeric) the time offset\n" | |
72 | " \"connections\": xxxxx, (numeric) the number of connections\n" | |
73 | " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" | |
74 | " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" | |
75 | " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" | |
76 | " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" | |
77 | " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" | |
78 | " \"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" | |
79 | " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n" | |
80 | " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n" | |
81 | " \"errors\": \"...\" (string) any error messages\n" | |
82 | "}\n" | |
83 | "\nExamples:\n" | |
84 | + HelpExampleCli("getinfo", "") | |
85 | + HelpExampleRpc("getinfo", "") | |
86 | ); | |
87 | ||
88 | #ifdef ENABLE_WALLET | |
89 | LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); | |
90 | #else | |
91 | LOCK(cs_main); | |
92 | #endif | |
93 | ||
94 | proxyType proxy; | |
95 | GetProxy(NET_IPV4, proxy); | |
96 | notarized_height = komodo_notarized_height(¬arized_hash,¬arized_desttxid); | |
97 | ||
98 | UniValue obj(UniValue::VOBJ); | |
99 | obj.push_back(Pair("version", CLIENT_VERSION)); | |
100 | obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); | |
101 | obj.push_back(Pair("KMDversion", KOMODO_VERSION)); | |
102 | obj.push_back(Pair("notarized", notarized_height)); | |
103 | obj.push_back(Pair("notarizedhash", notarized_hash.ToString())); | |
104 | obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString())); | |
105 | txid_height = notarizedtxid_height(ASSETCHAINS_SYMBOL[0] != 0 ? (char *)"KMD" : (char *)"BTC",(char *)notarized_desttxid.ToString().c_str(),&kmdnotarized_height); | |
106 | if ( txid_height > 0 ) | |
107 | obj.push_back(Pair("notarizedtxid_height", txid_height)); | |
108 | else obj.push_back(Pair("notarizedtxid_height", "mempool")); | |
109 | if ( ASSETCHAINS_SYMBOL[0] != 0 ) | |
110 | obj.push_back(Pair("KMDnotarized_height", kmdnotarized_height)); | |
111 | obj.push_back(Pair("notarized_confirms", txid_height < kmdnotarized_height ? (kmdnotarized_height - txid_height + 1) : 0)); | |
112 | #ifdef ENABLE_WALLET | |
113 | if (pwalletMain) { | |
114 | obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); | |
115 | obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); | |
116 | if ( ASSETCHAINS_SYMBOL[0] == 0 ) | |
117 | obj.push_back(Pair("interest", ValueFromAmount(komodo_interestsum()))); | |
118 | } | |
119 | #endif | |
120 | obj.push_back(Pair("blocks", (int)chainActive.Height())); | |
121 | if ( (longestchain= komodo_longestchain()) != 0 && chainActive.Height() > longestchain ) | |
122 | longestchain = chainActive.Height(); | |
123 | obj.push_back(Pair("longestchain", longestchain)); | |
124 | obj.push_back(Pair("timeoffset", GetTimeOffset())); | |
125 | if ( chainActive.Tip() != 0 ) | |
126 | obj.push_back(Pair("tiptime", (int)chainActive.Tip()->nTime)); | |
127 | obj.push_back(Pair("connections", (int)vNodes.size())); | |
128 | obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); | |
129 | obj.push_back(Pair("difficulty", (double)GetDifficulty())); | |
130 | obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); | |
131 | #ifdef ENABLE_WALLET | |
132 | if (pwalletMain) { | |
133 | obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); | |
134 | obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); | |
135 | } | |
136 | if (pwalletMain && pwalletMain->IsCrypted()) | |
137 | obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); | |
138 | obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); | |
139 | #endif | |
140 | obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); | |
141 | obj.push_back(Pair("errors", GetWarnings("statusbar"))); | |
142 | { | |
143 | char pubkeystr[65]; int32_t notaryid; | |
144 | if ( (notaryid= komodo_whoami(pubkeystr,(int32_t)chainActive.Tip()->nHeight,komodo_chainactive_timestamp())) >= 0 ) | |
145 | { | |
146 | obj.push_back(Pair("notaryid", notaryid)); | |
147 | obj.push_back(Pair("pubkey", pubkeystr)); | |
148 | if ( KOMODO_LASTMINED != 0 ) | |
149 | obj.push_back(Pair("lastmined", KOMODO_LASTMINED)); | |
150 | } | |
151 | } | |
152 | return obj; | |
153 | } | |
154 | ||
155 | #ifdef ENABLE_WALLET | |
156 | class DescribeAddressVisitor : public boost::static_visitor<UniValue> | |
157 | { | |
158 | public: | |
159 | UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); } | |
160 | ||
161 | UniValue operator()(const CKeyID &keyID) const { | |
162 | UniValue obj(UniValue::VOBJ); | |
163 | CPubKey vchPubKey; | |
164 | obj.push_back(Pair("isscript", false)); | |
165 | if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) { | |
166 | obj.push_back(Pair("pubkey", HexStr(vchPubKey))); | |
167 | obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); | |
168 | } | |
169 | return obj; | |
170 | } | |
171 | ||
172 | UniValue operator()(const CScriptID &scriptID) const { | |
173 | UniValue obj(UniValue::VOBJ); | |
174 | CScript subscript; | |
175 | obj.push_back(Pair("isscript", true)); | |
176 | if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) { | |
177 | std::vector<CTxDestination> addresses; | |
178 | txnouttype whichType; | |
179 | int nRequired; | |
180 | ExtractDestinations(subscript, whichType, addresses, nRequired); | |
181 | obj.push_back(Pair("script", GetTxnOutputType(whichType))); | |
182 | obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); | |
183 | UniValue a(UniValue::VARR); | |
184 | BOOST_FOREACH(const CTxDestination& addr, addresses) | |
185 | a.push_back(CBitcoinAddress(addr).ToString()); | |
186 | obj.push_back(Pair("addresses", a)); | |
187 | if (whichType == TX_MULTISIG) | |
188 | obj.push_back(Pair("sigsrequired", nRequired)); | |
189 | } | |
190 | return obj; | |
191 | } | |
192 | }; | |
193 | #endif | |
194 | ||
195 | UniValue jumblr_deposit(const UniValue& params, bool fHelp) | |
196 | { | |
197 | int32_t retval; UniValue result(UniValue::VOBJ); | |
198 | if (fHelp || params.size() != 1) | |
199 | throw runtime_error("jumblr_deposit \"depositaddress\"\n"); | |
200 | CBitcoinAddress address(params[0].get_str()); | |
201 | bool isValid = address.IsValid(); | |
202 | if ( isValid != 0 ) | |
203 | { | |
204 | string addr = params[0].get_str(); | |
205 | if ( (retval= Jumblr_depositaddradd((char *)addr.c_str())) >= 0 ) | |
206 | { | |
207 | result.push_back(Pair("result", retval)); | |
208 | JUMBLR_PAUSE = 0; | |
209 | } | |
210 | else result.push_back(Pair("error", retval)); | |
211 | } else result.push_back(Pair("error", "invalid address")); | |
212 | return(result); | |
213 | } | |
214 | ||
215 | UniValue jumblr_secret(const UniValue& params, bool fHelp) | |
216 | { | |
217 | int32_t retval; UniValue result(UniValue::VOBJ); | |
218 | if (fHelp || params.size() != 1) | |
219 | throw runtime_error("jumblr_secret \"secretaddress\"\n"); | |
220 | CBitcoinAddress address(params[0].get_str()); | |
221 | bool isValid = address.IsValid(); | |
222 | if ( isValid != 0 ) | |
223 | { | |
224 | string addr = params[0].get_str(); | |
225 | retval = Jumblr_secretaddradd((char *)addr.c_str()); | |
226 | result.push_back(Pair("result", "success")); | |
227 | result.push_back(Pair("num", retval)); | |
228 | JUMBLR_PAUSE = 0; | |
229 | } else result.push_back(Pair("error", "invalid address")); | |
230 | return(result); | |
231 | } | |
232 | ||
233 | UniValue jumblr_pause(const UniValue& params, bool fHelp) | |
234 | { | |
235 | int32_t retval; UniValue result(UniValue::VOBJ); | |
236 | if (fHelp ) | |
237 | throw runtime_error("jumblr_pause\n"); | |
238 | JUMBLR_PAUSE = 1; | |
239 | result.push_back(Pair("result", "paused")); | |
240 | return(result); | |
241 | } | |
242 | ||
243 | UniValue jumblr_resume(const UniValue& params, bool fHelp) | |
244 | { | |
245 | int32_t retval; UniValue result(UniValue::VOBJ); | |
246 | if (fHelp ) | |
247 | throw runtime_error("jumblr_resume\n"); | |
248 | JUMBLR_PAUSE = 0; | |
249 | result.push_back(Pair("result", "resumed")); | |
250 | return(result); | |
251 | } | |
252 | ||
253 | UniValue validateaddress(const UniValue& params, bool fHelp) | |
254 | { | |
255 | if (fHelp || params.size() != 1) | |
256 | throw runtime_error( | |
257 | "validateaddress \"zcashaddress\"\n" | |
258 | "\nReturn information about the given Zcash address.\n" | |
259 | "\nArguments:\n" | |
260 | "1. \"zcashaddress\" (string, required) The Zcash address to validate\n" | |
261 | "\nResult:\n" | |
262 | "{\n" | |
263 | " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" | |
264 | " \"address\" : \"zcashaddress\", (string) The Zcash address validated\n" | |
265 | " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" | |
266 | " \"ismine\" : true|false, (boolean) If the address is yours or not\n" | |
267 | " \"isscript\" : true|false, (boolean) If the key is a script\n" | |
268 | " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n" | |
269 | " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" | |
270 | " \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n" | |
271 | "}\n" | |
272 | "\nExamples:\n" | |
273 | + HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") | |
274 | + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") | |
275 | ); | |
276 | ||
277 | #ifdef ENABLE_WALLET | |
278 | LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); | |
279 | #else | |
280 | LOCK(cs_main); | |
281 | #endif | |
282 | ||
283 | CBitcoinAddress address(params[0].get_str()); | |
284 | bool isValid = address.IsValid(); | |
285 | ||
286 | UniValue ret(UniValue::VOBJ); | |
287 | ret.push_back(Pair("isvalid", isValid)); | |
288 | if (isValid) | |
289 | { | |
290 | CTxDestination dest = address.Get(); | |
291 | string currentAddress = address.ToString(); | |
292 | ret.push_back(Pair("address", currentAddress)); | |
293 | ||
294 | CScript scriptPubKey = GetScriptForDestination(dest); | |
295 | ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); | |
296 | ||
297 | #ifdef ENABLE_WALLET | |
298 | isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; | |
299 | ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); | |
300 | ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false)); | |
301 | UniValue detail = boost::apply_visitor(DescribeAddressVisitor(), dest); | |
302 | ret.pushKVs(detail); | |
303 | if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) | |
304 | ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); | |
305 | #endif | |
306 | } | |
307 | return ret; | |
308 | } | |
309 | ||
310 | ||
311 | UniValue z_validateaddress(const UniValue& params, bool fHelp) | |
312 | { | |
313 | if (fHelp || params.size() != 1) | |
314 | throw runtime_error( | |
315 | "z_validateaddress \"zaddr\"\n" | |
316 | "\nReturn information about the given z address.\n" | |
317 | "\nArguments:\n" | |
318 | "1. \"zaddr\" (string, required) The z address to validate\n" | |
319 | "\nResult:\n" | |
320 | "{\n" | |
321 | " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" | |
322 | " \"address\" : \"zaddr\", (string) The z address validated\n" | |
323 | " \"ismine\" : true|false, (boolean) If the address is yours or not\n" | |
324 | " \"payingkey\" : \"hex\", (string) The hex value of the paying key, a_pk\n" | |
325 | " \"transmissionkey\" : \"hex\", (string) The hex value of the transmission key, pk_enc\n" | |
326 | ||
327 | "}\n" | |
328 | "\nExamples:\n" | |
329 | + HelpExampleCli("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") | |
330 | + HelpExampleRpc("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") | |
331 | ); | |
332 | ||
333 | ||
334 | #ifdef ENABLE_WALLET | |
335 | LOCK2(cs_main, pwalletMain->cs_wallet); | |
336 | #else | |
337 | LOCK(cs_main); | |
338 | #endif | |
339 | ||
340 | bool isValid = false; | |
341 | bool isMine = false; | |
342 | std::string payingKey, transmissionKey; | |
343 | ||
344 | string strAddress = params[0].get_str(); | |
345 | try { | |
346 | CZCPaymentAddress address(strAddress); | |
347 | libzcash::PaymentAddress addr = address.Get(); | |
348 | ||
349 | #ifdef ENABLE_WALLET | |
350 | isMine = pwalletMain->HaveSpendingKey(addr); | |
351 | #endif | |
352 | payingKey = addr.a_pk.GetHex(); | |
353 | transmissionKey = addr.pk_enc.GetHex(); | |
354 | isValid = true; | |
355 | } catch (std::runtime_error e) { | |
356 | // address is invalid, nop here as isValid is false. | |
357 | } | |
358 | ||
359 | UniValue ret(UniValue::VOBJ); | |
360 | ret.push_back(Pair("isvalid", isValid)); | |
361 | if (isValid) | |
362 | { | |
363 | ret.push_back(Pair("address", strAddress)); | |
364 | ret.push_back(Pair("payingkey", payingKey)); | |
365 | ret.push_back(Pair("transmissionkey", transmissionKey)); | |
366 | #ifdef ENABLE_WALLET | |
367 | ret.push_back(Pair("ismine", isMine)); | |
368 | #endif | |
369 | } | |
370 | return ret; | |
371 | } | |
372 | ||
373 | ||
374 | /** | |
375 | * Used by addmultisigaddress / createmultisig: | |
376 | */ | |
377 | CScript _createmultisig_redeemScript(const UniValue& params) | |
378 | { | |
379 | int nRequired = params[0].get_int(); | |
380 | const UniValue& keys = params[1].get_array(); | |
381 | ||
382 | // Gather public keys | |
383 | if (nRequired < 1) | |
384 | throw runtime_error("a multisignature address must require at least one key to redeem"); | |
385 | if ((int)keys.size() < nRequired) | |
386 | throw runtime_error( | |
387 | strprintf("not enough keys supplied " | |
388 | "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired)); | |
389 | if (keys.size() > 16) | |
390 | throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); | |
391 | std::vector<CPubKey> pubkeys; | |
392 | pubkeys.resize(keys.size()); | |
393 | for (unsigned int i = 0; i < keys.size(); i++) | |
394 | { | |
395 | const std::string& ks = keys[i].get_str(); | |
396 | #ifdef ENABLE_WALLET | |
397 | // Case 1: Bitcoin address and we have full public key: | |
398 | CBitcoinAddress address(ks); | |
399 | if (pwalletMain && address.IsValid()) | |
400 | { | |
401 | CKeyID keyID; | |
402 | if (!address.GetKeyID(keyID)) | |
403 | throw runtime_error( | |
404 | strprintf("%s does not refer to a key",ks)); | |
405 | CPubKey vchPubKey; | |
406 | if (!pwalletMain->GetPubKey(keyID, vchPubKey)) | |
407 | throw runtime_error( | |
408 | strprintf("no full public key for address %s",ks)); | |
409 | if (!vchPubKey.IsFullyValid()) | |
410 | throw runtime_error(" Invalid public key: "+ks); | |
411 | pubkeys[i] = vchPubKey; | |
412 | } | |
413 | ||
414 | // Case 2: hex public key | |
415 | else | |
416 | #endif | |
417 | if (IsHex(ks)) | |
418 | { | |
419 | CPubKey vchPubKey(ParseHex(ks)); | |
420 | if (!vchPubKey.IsFullyValid()) | |
421 | throw runtime_error(" Invalid public key: "+ks); | |
422 | pubkeys[i] = vchPubKey; | |
423 | } | |
424 | else | |
425 | { | |
426 | throw runtime_error(" Invalid public key: "+ks); | |
427 | } | |
428 | } | |
429 | CScript result = GetScriptForMultisig(nRequired, pubkeys); | |
430 | ||
431 | if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) | |
432 | throw runtime_error( | |
433 | strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)); | |
434 | ||
435 | return result; | |
436 | } | |
437 | ||
438 | UniValue createmultisig(const UniValue& params, bool fHelp) | |
439 | { | |
440 | if (fHelp || params.size() < 2 || params.size() > 2) | |
441 | { | |
442 | string msg = "createmultisig nrequired [\"key\",...]\n" | |
443 | "\nCreates a multi-signature address with n signature of m keys required.\n" | |
444 | "It returns a json object with the address and redeemScript.\n" | |
445 | ||
446 | "\nArguments:\n" | |
447 | "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" | |
448 | "2. \"keys\" (string, required) A json array of keys which are Zcash addresses or hex-encoded public keys\n" | |
449 | " [\n" | |
450 | " \"key\" (string) Zcash address or hex-encoded public key\n" | |
451 | " ,...\n" | |
452 | " ]\n" | |
453 | ||
454 | "\nResult:\n" | |
455 | "{\n" | |
456 | " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n" | |
457 | " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n" | |
458 | "}\n" | |
459 | ||
460 | "\nExamples:\n" | |
461 | "\nCreate a multisig address from 2 addresses\n" | |
462 | + HelpExampleCli("createmultisig", "2 \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") + | |
463 | "\nAs a json rpc call\n" | |
464 | + HelpExampleRpc("createmultisig", "2, \"[\\\"t16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"t171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") | |
465 | ; | |
466 | throw runtime_error(msg); | |
467 | } | |
468 | ||
469 | // Construct using pay-to-script-hash: | |
470 | CScript inner = _createmultisig_redeemScript(params); | |
471 | CScriptID innerID(inner); | |
472 | CBitcoinAddress address(innerID); | |
473 | ||
474 | UniValue result(UniValue::VOBJ); | |
475 | result.push_back(Pair("address", address.ToString())); | |
476 | result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); | |
477 | ||
478 | return result; | |
479 | } | |
480 | ||
481 | UniValue verifymessage(const UniValue& params, bool fHelp) | |
482 | { | |
483 | if (fHelp || params.size() != 3) | |
484 | throw runtime_error( | |
485 | "verifymessage \"zcashaddress\" \"signature\" \"message\"\n" | |
486 | "\nVerify a signed message\n" | |
487 | "\nArguments:\n" | |
488 | "1. \"zcashaddress\" (string, required) The Zcash address to use for the signature.\n" | |
489 | "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" | |
490 | "3. \"message\" (string, required) The message that was signed.\n" | |
491 | "\nResult:\n" | |
492 | "true|false (boolean) If the signature is verified or not.\n" | |
493 | "\nExamples:\n" | |
494 | "\nUnlock the wallet for 30 seconds\n" | |
495 | + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + | |
496 | "\nCreate the signature\n" | |
497 | + HelpExampleCli("signmessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"my message\"") + | |
498 | "\nVerify the signature\n" | |
499 | + HelpExampleCli("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\" \"signature\" \"my message\"") + | |
500 | "\nAs json rpc\n" | |
501 | + HelpExampleRpc("verifymessage", "\"t14oHp2v54vfmdgQ3v3SNuQga8JKHTNi2a1\", \"signature\", \"my message\"") | |
502 | ); | |
503 | ||
504 | LOCK(cs_main); | |
505 | ||
506 | string strAddress = params[0].get_str(); | |
507 | string strSign = params[1].get_str(); | |
508 | string strMessage = params[2].get_str(); | |
509 | ||
510 | CBitcoinAddress addr(strAddress); | |
511 | if (!addr.IsValid()) | |
512 | throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); | |
513 | ||
514 | CKeyID keyID; | |
515 | if (!addr.GetKeyID(keyID)) | |
516 | throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); | |
517 | ||
518 | bool fInvalid = false; | |
519 | vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); | |
520 | ||
521 | if (fInvalid) | |
522 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); | |
523 | ||
524 | CHashWriter ss(SER_GETHASH, 0); | |
525 | ss << strMessageMagic; | |
526 | ss << strMessage; | |
527 | ||
528 | CPubKey pubkey; | |
529 | if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) | |
530 | return false; | |
531 | ||
532 | return (pubkey.GetID() == keyID); | |
533 | } | |
534 | ||
535 | UniValue setmocktime(const UniValue& params, bool fHelp) | |
536 | { | |
537 | if (fHelp || params.size() != 1) | |
538 | throw runtime_error( | |
539 | "setmocktime timestamp\n" | |
540 | "\nSet the local time to given timestamp (-regtest only)\n" | |
541 | "\nArguments:\n" | |
542 | "1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n" | |
543 | " Pass 0 to go back to using the system time." | |
544 | ); | |
545 | ||
546 | if (!Params().MineBlocksOnDemand()) | |
547 | throw runtime_error("setmocktime for regression testing (-regtest mode) only"); | |
548 | ||
549 | // cs_vNodes is locked and node send/receive times are updated | |
550 | // atomically with the time change to prevent peers from being | |
551 | // disconnected because we think we haven't communicated with them | |
552 | // in a long time. | |
553 | LOCK2(cs_main, cs_vNodes); | |
554 | ||
555 | RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); | |
556 | SetMockTime(params[0].get_int64()); | |
557 | ||
558 | uint64_t t = GetTime(); | |
559 | BOOST_FOREACH(CNode* pnode, vNodes) { | |
560 | pnode->nLastSend = pnode->nLastRecv = t; | |
561 | } | |
562 | ||
563 | return NullUniValue; | |
564 | } |