]>
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" |
8b78a819 | 14 | #include "txmempool.h" |
652e1569 WL |
15 | #include "util.h" |
16 | #ifdef ENABLE_WALLET | |
50c72f23 JS |
17 | #include "wallet/wallet.h" |
18 | #include "wallet/walletdb.h" | |
652e1569 WL |
19 | #endif |
20 | ||
21 | #include <stdint.h> | |
22 | ||
23 | #include <boost/assign/list_of.hpp> | |
a10a6e2a JS |
24 | |
25 | #include <univalue.h> | |
652e1569 | 26 | |
4e16a724 S |
27 | #include "zcash/Address.hpp" |
28 | ||
40a158e1 | 29 | using namespace std; |
652e1569 | 30 | |
f9de17ec WL |
31 | /** |
32 | * @note Do not add or change anything in the information returned by this | |
72fb3d29 | 33 | * method. `getinfo` exists for backwards-compatibility only. It combines |
f9de17ec WL |
34 | * information from wildly different sources in the program, which is a mess, |
35 | * and is thus planned to be deprecated eventually. | |
36 | * | |
37 | * Based on the source of the information, new information should be added to: | |
38 | * - `getblockchaininfo`, | |
39 | * - `getnetworkinfo` or | |
40 | * - `getwalletinfo` | |
41 | * | |
42 | * Or alternatively, create a specific query method for the information. | |
43 | **/ | |
945f015d | 44 | |
b487a8fe | 45 | int32_t Jumblr_depositaddradd(char *depositaddr); |
eeaaf554 | 46 | int32_t Jumblr_secretaddradd(char *secretaddr); |
da16b12e | 47 | uint64_t komodo_interestsum(); |
f595c2e0 | 48 | int32_t komodo_longestchain(); |
69d23911 | 49 | int32_t komodo_notarized_height(int32_t *prevhtp,uint256 *hashp,uint256 *txidp); |
e34a9d43 | 50 | uint32_t komodo_chainactive_timestamp(); |
8683bd8d | 51 | int32_t komodo_whoami(char *pubkeystr,int32_t height,uint32_t timestamp); |
94d3d09d | 52 | extern uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; |
6bb74a02 | 53 | extern int32_t KOMODO_LASTMINED,JUMBLR_PAUSE,KOMODO_LONGESTCHAIN; |
9edf27ec | 54 | extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; |
acbc7a94 | 55 | uint32_t komodo_segid32(char *coinaddr); |
26189509 | 56 | int64_t komodo_coinsupply(int64_t *zfundsp,int32_t height); |
0cb025c1 | 57 | int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heightp); |
eeaaf554 | 58 | #define KOMODO_VERSION "0.1.1" |
05c2ba63 | 59 | extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; |
dbc80050 | 60 | extern uint32_t ASSETCHAINS_CC; |
61 | extern uint32_t ASSETCHAINS_MAGIC; | |
62 | extern uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY; | |
09e3cf94 | 63 | |
d014114d | 64 | UniValue getinfo(const UniValue& params, bool fHelp) |
16bc9aaf | 65 | { |
69d23911 | 66 | uint256 notarized_hash,notarized_desttxid; int32_t prevMoMheight,notarized_height,longestchain,kmdnotarized_height,txid_height; |
16bc9aaf WL |
67 | if (fHelp || params.size() != 0) |
68 | throw runtime_error( | |
69 | "getinfo\n" | |
70 | "Returns an object containing various state info.\n" | |
71 | "\nResult:\n" | |
72 | "{\n" | |
73 | " \"version\": xxxxx, (numeric) the server version\n" | |
74 | " \"protocolversion\": xxxxx, (numeric) the protocol version\n" | |
75 | " \"walletversion\": xxxxx, (numeric) the wallet version\n" | |
a7322d77 | 76 | " \"balance\": xxxxxxx, (numeric) the total Komodo balance of the wallet\n" |
16bc9aaf WL |
77 | " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" |
78 | " \"timeoffset\": xxxxx, (numeric) the time offset\n" | |
79 | " \"connections\": xxxxx, (numeric) the number of connections\n" | |
80 | " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" | |
81 | " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" | |
82 | " \"testnet\": true|false, (boolean) if the server is using testnet or not\n" | |
83 | " \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n" | |
84 | " \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n" | |
16bc9aaf | 85 | " \"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" |
091b2116 RN |
86 | " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n" |
87 | " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n" | |
16bc9aaf WL |
88 | " \"errors\": \"...\" (string) any error messages\n" |
89 | "}\n" | |
90 | "\nExamples:\n" | |
91 | + HelpExampleCli("getinfo", "") | |
92 | + HelpExampleRpc("getinfo", "") | |
93 | ); | |
247428bd | 94 | //#ifdef ENABLE_WALLET |
95 | // LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); | |
96 | //#else | |
4add33cf | 97 | LOCK(cs_main); |
247428bd | 98 | //#endif |
4401b2d7 | 99 | |
16bc9aaf WL |
100 | proxyType proxy; |
101 | GetProxy(NET_IPV4, proxy); | |
69d23911 | 102 | notarized_height = komodo_notarized_height(&prevMoMheight,¬arized_hash,¬arized_desttxid); |
6f1de985 | 103 | //fprintf(stderr,"after notarized_height %u\n",(uint32_t)time(NULL)); |
16bc9aaf | 104 | |
38fc4b70 | 105 | UniValue obj(UniValue::VOBJ); |
faadbe17 PK |
106 | obj.push_back(Pair("version", CLIENT_VERSION)); |
107 | obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); | |
b000fa04 | 108 | obj.push_back(Pair("KMDversion", KOMODO_VERSION)); |
c75c18fc | 109 | obj.push_back(Pair("notarized", notarized_height)); |
69d23911 | 110 | obj.push_back(Pair("prevMoMheight", prevMoMheight)); |
c75c18fc | 111 | obj.push_back(Pair("notarizedhash", notarized_hash.ToString())); |
112 | obj.push_back(Pair("notarizedtxid", notarized_desttxid.ToString())); | |
6f1de985 | 113 | txid_height = notarizedtxid_height(ASSETCHAINS_SYMBOL[0] != 0 ? (char *)"KMD" : (char *)"BTC",(char *)notarized_desttxid.ToString().c_str(),&kmdnotarized_height); |
70d83934 | 114 | if ( txid_height > 0 ) |
115 | obj.push_back(Pair("notarizedtxid_height", txid_height)); | |
6f1de985 | 116 | else obj.push_back(Pair("notarizedtxid_height", "mempool")); |
57dd4ada | 117 | if ( ASSETCHAINS_SYMBOL[0] != 0 ) |
118 | obj.push_back(Pair("KMDnotarized_height", kmdnotarized_height)); | |
119 | obj.push_back(Pair("notarized_confirms", txid_height < kmdnotarized_height ? (kmdnotarized_height - txid_height + 1) : 0)); | |
6f1de985 | 120 | //fprintf(stderr,"after notarized_confirms %u\n",(uint32_t)time(NULL)); |
16bc9aaf WL |
121 | #ifdef ENABLE_WALLET |
122 | if (pwalletMain) { | |
123 | obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); | |
247428bd | 124 | obj.push_back(Pair("balance", ValueFromAmount(KOMODO_WALLETBALANCE))); //pwalletMain->GetBalance() |
9e1bde7e | 125 | if ( ASSETCHAINS_SYMBOL[0] == 0 ) |
247428bd | 126 | obj.push_back(Pair("interest", ValueFromAmount(KOMODO_INTERESTSUM))); //komodo_interestsum() |
16bc9aaf WL |
127 | } |
128 | #endif | |
6f1de985 | 129 | //fprintf(stderr,"after wallet %u\n",(uint32_t)time(NULL)); |
16bc9aaf | 130 | obj.push_back(Pair("blocks", (int)chainActive.Height())); |
daf214b1 | 131 | if ( (longestchain= KOMODO_LONGESTCHAIN) != 0 && chainActive.Height() > longestchain ) |
a19b28ce | 132 | longestchain = chainActive.Height(); |
6f1de985 | 133 | //fprintf(stderr,"after longestchain %u\n",(uint32_t)time(NULL)); |
a19b28ce | 134 | obj.push_back(Pair("longestchain", longestchain)); |
d56e30ca | 135 | obj.push_back(Pair("timeoffset", GetTimeOffset())); |
98d166cf | 136 | if ( chainActive.Tip() != 0 ) |
49c9db6a | 137 | obj.push_back(Pair("tiptime", (int)chainActive.Tip()->nTime)); |
16bc9aaf | 138 | obj.push_back(Pair("connections", (int)vNodes.size())); |
67a79493 | 139 | obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); |
16bc9aaf | 140 | obj.push_back(Pair("difficulty", (double)GetDifficulty())); |
cc972107 | 141 | obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); |
16bc9aaf WL |
142 | #ifdef ENABLE_WALLET |
143 | if (pwalletMain) { | |
d56e30ca | 144 | obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); |
16bc9aaf WL |
145 | obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); |
146 | } | |
16bc9aaf | 147 | if (pwalletMain && pwalletMain->IsCrypted()) |
d56e30ca | 148 | obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); |
c6cb21d1 | 149 | obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); |
16bc9aaf | 150 | #endif |
13fc83c7 | 151 | obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); |
16bc9aaf | 152 | obj.push_back(Pair("errors", GetWarnings("statusbar"))); |
58033467 | 153 | { |
154 | char pubkeystr[65]; int32_t notaryid; | |
e34a9d43 | 155 | if ( (notaryid= komodo_whoami(pubkeystr,(int32_t)chainActive.Tip()->nHeight,komodo_chainactive_timestamp())) >= 0 ) |
1e2a41f6 | 156 | { |
157 | obj.push_back(Pair("notaryid", notaryid)); | |
158 | obj.push_back(Pair("pubkey", pubkeystr)); | |
159 | if ( KOMODO_LASTMINED != 0 ) | |
160 | obj.push_back(Pair("lastmined", KOMODO_LASTMINED)); | |
161 | } | |
58033467 | 162 | } |
dbc80050 | 163 | if ( ASSETCHAINS_CC != 0 ) |
91e76e0c | 164 | obj.push_back(Pair("CCid", (int)ASSETCHAINS_CC)); |
9edf27ec | 165 | obj.push_back(Pair("name", ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)); |
dbc80050 | 166 | if ( ASSETCHAINS_SYMBOL[0] != 0 ) |
167 | { | |
9edf27ec | 168 | //obj.push_back(Pair("name", ASSETCHAINS_SYMBOL)); |
05c2ba63 | 169 | obj.push_back(Pair("p2pport", ASSETCHAINS_P2PPORT)); |
170 | obj.push_back(Pair("rpcport", ASSETCHAINS_RPCPORT)); | |
91e76e0c | 171 | obj.push_back(Pair("magic", (int)ASSETCHAINS_MAGIC)); |
dbc80050 | 172 | if ( ASSETCHAINS_SUPPLY != 0 ) |
173 | obj.push_back(Pair("premine", ASSETCHAINS_SUPPLY)); | |
174 | if ( ASSETCHAINS_REWARD != 0 ) | |
175 | obj.push_back(Pair("reward", ASSETCHAINS_REWARD)); | |
176 | if ( ASSETCHAINS_HALVING != 0 ) | |
177 | obj.push_back(Pair("halving", ASSETCHAINS_HALVING)); | |
178 | if ( ASSETCHAINS_DECAY != 0 ) | |
179 | obj.push_back(Pair("decay", ASSETCHAINS_DECAY)); | |
180 | if ( ASSETCHAINS_ENDSUBSIDY != 0 ) | |
181 | obj.push_back(Pair("endsubsidy", ASSETCHAINS_ENDSUBSIDY)); | |
182 | if ( ASSETCHAINS_COMMISSION != 0 ) | |
183 | obj.push_back(Pair("commission", ASSETCHAINS_COMMISSION)); | |
184 | if ( ASSETCHAINS_STAKED != 0 ) | |
185 | obj.push_back(Pair("staked", ASSETCHAINS_STAKED)); | |
186 | } | |
16bc9aaf WL |
187 | return obj; |
188 | } | |
189 | ||
452955f5 | 190 | #ifdef ENABLE_WALLET |
d014114d | 191 | class DescribeAddressVisitor : public boost::static_visitor<UniValue> |
452955f5 WL |
192 | { |
193 | public: | |
d014114d | 194 | UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); } |
452955f5 | 195 | |
851f58f9 | 196 | UniValue operator()(const CKeyID &keyID) const { |
38fc4b70 | 197 | UniValue obj(UniValue::VOBJ); |
452955f5 | 198 | CPubKey vchPubKey; |
452955f5 | 199 | obj.push_back(Pair("isscript", false)); |
56215c77 | 200 | if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) { |
c8988460 PW |
201 | obj.push_back(Pair("pubkey", HexStr(vchPubKey))); |
202 | obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); | |
203 | } | |
452955f5 WL |
204 | return obj; |
205 | } | |
206 | ||
851f58f9 | 207 | UniValue operator()(const CScriptID &scriptID) const { |
38fc4b70 | 208 | UniValue obj(UniValue::VOBJ); |
9c7167d1 | 209 | CScript subscript; |
452955f5 | 210 | obj.push_back(Pair("isscript", true)); |
56215c77 | 211 | if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) { |
c8988460 PW |
212 | std::vector<CTxDestination> addresses; |
213 | txnouttype whichType; | |
214 | int nRequired; | |
215 | ExtractDestinations(subscript, whichType, addresses, nRequired); | |
216 | obj.push_back(Pair("script", GetTxnOutputType(whichType))); | |
217 | obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end()))); | |
38fc4b70 | 218 | UniValue a(UniValue::VARR); |
c8988460 PW |
219 | BOOST_FOREACH(const CTxDestination& addr, addresses) |
220 | a.push_back(CBitcoinAddress(addr).ToString()); | |
221 | obj.push_back(Pair("addresses", a)); | |
222 | if (whichType == TX_MULTISIG) | |
223 | obj.push_back(Pair("sigsrequired", nRequired)); | |
224 | } | |
452955f5 WL |
225 | return obj; |
226 | } | |
227 | }; | |
228 | #endif | |
229 | ||
7e282415 | 230 | UniValue coinsupply(const UniValue& params, bool fHelp) |
231 | { | |
26189509 | 232 | int32_t height = 0; int64_t zfunds,supply = 0; UniValue result(UniValue::VOBJ); |
7e282415 | 233 | if (fHelp || params.size() > 1) |
234 | throw runtime_error("coinsupply <height>\n"); | |
235 | if ( params.size() == 0 ) | |
236 | height = chainActive.Height(); | |
237 | else height = atoi(params[0].get_str()); | |
26189509 | 238 | if ( (supply= komodo_coinsupply(&zfunds,height)) > 0 ) |
7e282415 | 239 | { |
240 | result.push_back(Pair("result", "success")); | |
241 | result.push_back(Pair("height", (int)height)); | |
242 | result.push_back(Pair("supply", ValueFromAmount(supply))); | |
26189509 | 243 | result.push_back(Pair("zfunds", ValueFromAmount(zfunds))); |
244 | result.push_back(Pair("total", ValueFromAmount(zfunds + supply))); | |
7e282415 | 245 | } else result.push_back(Pair("error", "couldnt calculate supply")); |
246 | return(result); | |
247 | } | |
248 | ||
eeaaf554 | 249 | UniValue jumblr_deposit(const UniValue& params, bool fHelp) |
250 | { | |
b487a8fe | 251 | int32_t retval; UniValue result(UniValue::VOBJ); |
eeaaf554 | 252 | if (fHelp || params.size() != 1) |
253 | throw runtime_error("jumblr_deposit \"depositaddress\"\n"); | |
254 | CBitcoinAddress address(params[0].get_str()); | |
255 | bool isValid = address.IsValid(); | |
256 | if ( isValid != 0 ) | |
257 | { | |
258 | string addr = params[0].get_str(); | |
b487a8fe | 259 | if ( (retval= Jumblr_depositaddradd((char *)addr.c_str())) >= 0 ) |
e21c70e9 | 260 | { |
190dbe6d | 261 | result.push_back(Pair("result", retval)); |
e21c70e9 | 262 | JUMBLR_PAUSE = 0; |
263 | } | |
b487a8fe | 264 | else result.push_back(Pair("error", retval)); |
eeaaf554 | 265 | } else result.push_back(Pair("error", "invalid address")); |
266 | return(result); | |
267 | } | |
268 | ||
269 | UniValue jumblr_secret(const UniValue& params, bool fHelp) | |
270 | { | |
271 | int32_t retval; UniValue result(UniValue::VOBJ); | |
272 | if (fHelp || params.size() != 1) | |
273 | throw runtime_error("jumblr_secret \"secretaddress\"\n"); | |
274 | CBitcoinAddress address(params[0].get_str()); | |
275 | bool isValid = address.IsValid(); | |
276 | if ( isValid != 0 ) | |
277 | { | |
278 | string addr = params[0].get_str(); | |
bc035879 | 279 | retval = Jumblr_secretaddradd((char *)addr.c_str()); |
eeaaf554 | 280 | result.push_back(Pair("result", "success")); |
281 | result.push_back(Pair("num", retval)); | |
e8fa58ec | 282 | JUMBLR_PAUSE = 0; |
eeaaf554 | 283 | } else result.push_back(Pair("error", "invalid address")); |
284 | return(result); | |
285 | } | |
286 | ||
eea03b7b | 287 | UniValue jumblr_pause(const UniValue& params, bool fHelp) |
288 | { | |
289 | int32_t retval; UniValue result(UniValue::VOBJ); | |
290 | if (fHelp ) | |
291 | throw runtime_error("jumblr_pause\n"); | |
292 | JUMBLR_PAUSE = 1; | |
293 | result.push_back(Pair("result", "paused")); | |
294 | return(result); | |
295 | } | |
296 | ||
297 | UniValue jumblr_resume(const UniValue& params, bool fHelp) | |
298 | { | |
299 | int32_t retval; UniValue result(UniValue::VOBJ); | |
300 | if (fHelp ) | |
301 | throw runtime_error("jumblr_resume\n"); | |
302 | JUMBLR_PAUSE = 0; | |
303 | result.push_back(Pair("result", "resumed")); | |
304 | return(result); | |
305 | } | |
306 | ||
d014114d | 307 | UniValue validateaddress(const UniValue& params, bool fHelp) |
452955f5 WL |
308 | { |
309 | if (fHelp || params.size() != 1) | |
310 | throw runtime_error( | |
a7322d77 | 311 | "validateaddress \"komodoaddress\"\n" |
312 | "\nReturn information about the given Komodo address.\n" | |
452955f5 | 313 | "\nArguments:\n" |
a7322d77 | 314 | "1. \"komodoaddress\" (string, required) The Komodo address to validate\n" |
452955f5 WL |
315 | "\nResult:\n" |
316 | "{\n" | |
317 | " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" | |
a7322d77 | 318 | " \"address\" : \"komodoaddress\", (string) The Komodo address validated\n" |
426a74ed | 319 | " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" |
452955f5 WL |
320 | " \"ismine\" : true|false, (boolean) If the address is yours or not\n" |
321 | " \"isscript\" : true|false, (boolean) If the key is a script\n" | |
322 | " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n" | |
323 | " \"iscompressed\" : true|false, (boolean) If the address is compressed\n" | |
7b782f5b | 324 | " \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n" |
452955f5 WL |
325 | "}\n" |
326 | "\nExamples:\n" | |
a7322d77 | 327 | + HelpExampleCli("validateaddress", "\"RTZMZHDFSTFQst8XmX2dR4DaH87cEUs3gC\"") |
328 | + HelpExampleRpc("validateaddress", "\"RTZMZHDFSTFQst8XmX2dR4DaH87cEUs3gC\"") | |
452955f5 WL |
329 | ); |
330 | ||
4401b2d7 EL |
331 | #ifdef ENABLE_WALLET |
332 | LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); | |
333 | #else | |
334 | LOCK(cs_main); | |
335 | #endif | |
336 | ||
452955f5 WL |
337 | CBitcoinAddress address(params[0].get_str()); |
338 | bool isValid = address.IsValid(); | |
339 | ||
38fc4b70 | 340 | UniValue ret(UniValue::VOBJ); |
452955f5 WL |
341 | ret.push_back(Pair("isvalid", isValid)); |
342 | if (isValid) | |
343 | { | |
344 | CTxDestination dest = address.Get(); | |
345 | string currentAddress = address.ToString(); | |
346 | ret.push_back(Pair("address", currentAddress)); | |
426a74ed PT |
347 | |
348 | CScript scriptPubKey = GetScriptForDestination(dest); | |
349 | ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); | |
7cf23c98 | 350 | ret.push_back(Pair("segid", (int32_t)komodo_segid32((char *)params[0].get_str().c_str()) & 0x3f)); |
452955f5 | 351 | #ifdef ENABLE_WALLET |
a3e192a3 J |
352 | isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; |
353 | ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); | |
9c7167d1 | 354 | ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false)); |
355 | UniValue detail = boost::apply_visitor(DescribeAddressVisitor(), dest); | |
356 | ret.pushKVs(detail); | |
452955f5 WL |
357 | if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) |
358 | ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); | |
359 | #endif | |
360 | } | |
361 | return ret; | |
362 | } | |
363 | ||
4e16a724 | 364 | |
0d37ae3a | 365 | UniValue z_validateaddress(const UniValue& params, bool fHelp) |
4e16a724 S |
366 | { |
367 | if (fHelp || params.size() != 1) | |
368 | throw runtime_error( | |
369 | "z_validateaddress \"zaddr\"\n" | |
370 | "\nReturn information about the given z address.\n" | |
371 | "\nArguments:\n" | |
372 | "1. \"zaddr\" (string, required) The z address to validate\n" | |
373 | "\nResult:\n" | |
374 | "{\n" | |
375 | " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" | |
376 | " \"address\" : \"zaddr\", (string) The z address validated\n" | |
377 | " \"ismine\" : true|false, (boolean) If the address is yours or not\n" | |
378 | " \"payingkey\" : \"hex\", (string) The hex value of the paying key, a_pk\n" | |
379 | " \"transmissionkey\" : \"hex\", (string) The hex value of the transmission key, pk_enc\n" | |
380 | ||
381 | "}\n" | |
382 | "\nExamples:\n" | |
337a99a2 JG |
383 | + HelpExampleCli("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") |
384 | + HelpExampleRpc("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") | |
4e16a724 S |
385 | ); |
386 | ||
387 | ||
388 | #ifdef ENABLE_WALLET | |
389 | LOCK2(cs_main, pwalletMain->cs_wallet); | |
390 | #else | |
391 | LOCK(cs_main); | |
392 | #endif | |
393 | ||
394 | bool isValid = false; | |
395 | bool isMine = false; | |
396 | std::string payingKey, transmissionKey; | |
397 | ||
398 | string strAddress = params[0].get_str(); | |
399 | try { | |
400 | CZCPaymentAddress address(strAddress); | |
401 | libzcash::PaymentAddress addr = address.Get(); | |
402 | ||
403 | #ifdef ENABLE_WALLET | |
404 | isMine = pwalletMain->HaveSpendingKey(addr); | |
405 | #endif | |
406 | payingKey = addr.a_pk.GetHex(); | |
407 | transmissionKey = addr.pk_enc.GetHex(); | |
408 | isValid = true; | |
409 | } catch (std::runtime_error e) { | |
410 | // address is invalid, nop here as isValid is false. | |
411 | } | |
412 | ||
0d37ae3a | 413 | UniValue ret(UniValue::VOBJ); |
4e16a724 S |
414 | ret.push_back(Pair("isvalid", isValid)); |
415 | if (isValid) | |
416 | { | |
417 | ret.push_back(Pair("address", strAddress)); | |
418 | ret.push_back(Pair("payingkey", payingKey)); | |
419 | ret.push_back(Pair("transmissionkey", transmissionKey)); | |
420 | #ifdef ENABLE_WALLET | |
421 | ret.push_back(Pair("ismine", isMine)); | |
422 | #endif | |
423 | } | |
424 | return ret; | |
425 | } | |
426 | ||
427 | ||
72fb3d29 MF |
428 | /** |
429 | * Used by addmultisigaddress / createmultisig: | |
430 | */ | |
d014114d | 431 | CScript _createmultisig_redeemScript(const UniValue& params) |
723a03d2 WL |
432 | { |
433 | int nRequired = params[0].get_int(); | |
d014114d | 434 | const UniValue& keys = params[1].get_array(); |
723a03d2 WL |
435 | |
436 | // Gather public keys | |
437 | if (nRequired < 1) | |
438 | throw runtime_error("a multisignature address must require at least one key to redeem"); | |
439 | if ((int)keys.size() < nRequired) | |
440 | throw runtime_error( | |
441 | strprintf("not enough keys supplied " | |
783b182c | 442 | "(got %u keys, but need at least %d to redeem)", keys.size(), nRequired)); |
e5d9d77d | 443 | if (keys.size() > 16) |
444 | throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number"); | |
723a03d2 WL |
445 | std::vector<CPubKey> pubkeys; |
446 | pubkeys.resize(keys.size()); | |
447 | for (unsigned int i = 0; i < keys.size(); i++) | |
448 | { | |
449 | const std::string& ks = keys[i].get_str(); | |
450 | #ifdef ENABLE_WALLET | |
451 | // Case 1: Bitcoin address and we have full public key: | |
452 | CBitcoinAddress address(ks); | |
453 | if (pwalletMain && address.IsValid()) | |
454 | { | |
455 | CKeyID keyID; | |
456 | if (!address.GetKeyID(keyID)) | |
457 | throw runtime_error( | |
7d9d134b | 458 | strprintf("%s does not refer to a key",ks)); |
723a03d2 WL |
459 | CPubKey vchPubKey; |
460 | if (!pwalletMain->GetPubKey(keyID, vchPubKey)) | |
461 | throw runtime_error( | |
7d9d134b | 462 | strprintf("no full public key for address %s",ks)); |
723a03d2 WL |
463 | if (!vchPubKey.IsFullyValid()) |
464 | throw runtime_error(" Invalid public key: "+ks); | |
465 | pubkeys[i] = vchPubKey; | |
466 | } | |
467 | ||
468 | // Case 2: hex public key | |
469 | else | |
470 | #endif | |
471 | if (IsHex(ks)) | |
472 | { | |
473 | CPubKey vchPubKey(ParseHex(ks)); | |
474 | if (!vchPubKey.IsFullyValid()) | |
475 | throw runtime_error(" Invalid public key: "+ks); | |
476 | pubkeys[i] = vchPubKey; | |
477 | } | |
478 | else | |
479 | { | |
480 | throw runtime_error(" Invalid public key: "+ks); | |
481 | } | |
482 | } | |
0be990ba | 483 | CScript result = GetScriptForMultisig(nRequired, pubkeys); |
787ee0c9 PT |
484 | |
485 | if (result.size() > MAX_SCRIPT_ELEMENT_SIZE) | |
486 | throw runtime_error( | |
487 | strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE)); | |
488 | ||
723a03d2 WL |
489 | return result; |
490 | } | |
491 | ||
d014114d | 492 | UniValue createmultisig(const UniValue& params, bool fHelp) |
723a03d2 WL |
493 | { |
494 | if (fHelp || params.size() < 2 || params.size() > 2) | |
495 | { | |
496 | string msg = "createmultisig nrequired [\"key\",...]\n" | |
497 | "\nCreates a multi-signature address with n signature of m keys required.\n" | |
498 | "It returns a json object with the address and redeemScript.\n" | |
499 | ||
500 | "\nArguments:\n" | |
501 | "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" | |
a7322d77 | 502 | "2. \"keys\" (string, required) A json array of keys which are Komodo addresses or hex-encoded public keys\n" |
723a03d2 | 503 | " [\n" |
a7322d77 | 504 | " \"key\" (string) Komodo address or hex-encoded public key\n" |
723a03d2 WL |
505 | " ,...\n" |
506 | " ]\n" | |
507 | ||
508 | "\nResult:\n" | |
509 | "{\n" | |
510 | " \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n" | |
511 | " \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n" | |
512 | "}\n" | |
513 | ||
514 | "\nExamples:\n" | |
515 | "\nCreate a multisig address from 2 addresses\n" | |
a7322d77 | 516 | + HelpExampleCli("createmultisig", "2 \"[\\\"RTZMZHDFSTFQst8XmX2dR4DaH87cEUs3gC\\\",\\\"RNKiEBduBru6Siv1cZRVhp4fkZNyPska6z\\\"]\"") + |
723a03d2 | 517 | "\nAs a json rpc call\n" |
a7322d77 | 518 | + HelpExampleRpc("createmultisig", "2, \"[\\\"RTZMZHDFSTFQst8XmX2dR4DaH87cEUs3gC\\\",\\\"RNKiEBduBru6Siv1cZRVhp4fkZNyPska6z\\\"]\"") |
723a03d2 WL |
519 | ; |
520 | throw runtime_error(msg); | |
521 | } | |
522 | ||
523 | // Construct using pay-to-script-hash: | |
787ee0c9 | 524 | CScript inner = _createmultisig_redeemScript(params); |
066e2a14 | 525 | CScriptID innerID(inner); |
723a03d2 WL |
526 | CBitcoinAddress address(innerID); |
527 | ||
b47f3aea | 528 | UniValue result(UniValue::VOBJ); |
723a03d2 WL |
529 | result.push_back(Pair("address", address.ToString())); |
530 | result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end()))); | |
531 | ||
532 | return result; | |
533 | } | |
534 | ||
d014114d | 535 | UniValue verifymessage(const UniValue& params, bool fHelp) |
c3a7f516 WL |
536 | { |
537 | if (fHelp || params.size() != 3) | |
538 | throw runtime_error( | |
a7322d77 | 539 | "verifymessage \"komodoaddress\" \"signature\" \"message\"\n" |
c3a7f516 WL |
540 | "\nVerify a signed message\n" |
541 | "\nArguments:\n" | |
a7322d77 | 542 | "1. \"komodoaddress\" (string, required) The Komodo address to use for the signature.\n" |
c3a7f516 WL |
543 | "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" |
544 | "3. \"message\" (string, required) The message that was signed.\n" | |
545 | "\nResult:\n" | |
546 | "true|false (boolean) If the signature is verified or not.\n" | |
547 | "\nExamples:\n" | |
548 | "\nUnlock the wallet for 30 seconds\n" | |
549 | + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + | |
550 | "\nCreate the signature\n" | |
a7322d77 | 551 | + HelpExampleCli("signmessage", "\"RNKiEBduBru6Siv1cZRVhp4fkZNyPska6z\" \"my message\"") + |
c3a7f516 | 552 | "\nVerify the signature\n" |
a7322d77 | 553 | + HelpExampleCli("verifymessage", "\"RNKiEBduBru6Siv1cZRVhp4fkZNyPska6z\" \"signature\" \"my message\"") + |
c3a7f516 | 554 | "\nAs json rpc\n" |
a7322d77 | 555 | + HelpExampleRpc("verifymessage", "\"RNKiEBduBru6Siv1cZRVhp4fkZNyPska6z\", \"signature\", \"my message\"") |
c3a7f516 WL |
556 | ); |
557 | ||
4401b2d7 EL |
558 | LOCK(cs_main); |
559 | ||
c3a7f516 WL |
560 | string strAddress = params[0].get_str(); |
561 | string strSign = params[1].get_str(); | |
562 | string strMessage = params[2].get_str(); | |
563 | ||
564 | CBitcoinAddress addr(strAddress); | |
565 | if (!addr.IsValid()) | |
566 | throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); | |
567 | ||
568 | CKeyID keyID; | |
569 | if (!addr.GetKeyID(keyID)) | |
570 | throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); | |
571 | ||
572 | bool fInvalid = false; | |
573 | vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid); | |
574 | ||
575 | if (fInvalid) | |
576 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); | |
577 | ||
578 | CHashWriter ss(SER_GETHASH, 0); | |
579 | ss << strMessageMagic; | |
580 | ss << strMessage; | |
581 | ||
582 | CPubKey pubkey; | |
583 | if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) | |
584 | return false; | |
585 | ||
586 | return (pubkey.GetID() == keyID); | |
587 | } | |
a8b2ce55 | 588 | |
d014114d | 589 | UniValue setmocktime(const UniValue& params, bool fHelp) |
a8b2ce55 GA |
590 | { |
591 | if (fHelp || params.size() != 1) | |
592 | throw runtime_error( | |
593 | "setmocktime timestamp\n" | |
594 | "\nSet the local time to given timestamp (-regtest only)\n" | |
595 | "\nArguments:\n" | |
596 | "1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n" | |
597 | " Pass 0 to go back to using the system time." | |
598 | ); | |
599 | ||
600 | if (!Params().MineBlocksOnDemand()) | |
601 | throw runtime_error("setmocktime for regression testing (-regtest mode) only"); | |
602 | ||
abb0e8cc GA |
603 | // cs_vNodes is locked and node send/receive times are updated |
604 | // atomically with the time change to prevent peers from being | |
605 | // disconnected because we think we haven't communicated with them | |
606 | // in a long time. | |
607 | LOCK2(cs_main, cs_vNodes); | |
4401b2d7 | 608 | |
9756b7bd | 609 | RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); |
a8b2ce55 GA |
610 | SetMockTime(params[0].get_int64()); |
611 | ||
abb0e8cc GA |
612 | uint64_t t = GetTime(); |
613 | BOOST_FOREACH(CNode* pnode, vNodes) { | |
614 | pnode->nLastSend = pnode->nLastRecv = t; | |
615 | } | |
616 | ||
9756b7bd | 617 | return NullUniValue; |
a8b2ce55 | 618 | } |
8b78a819 T |
619 | |
620 | bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address) | |
621 | { | |
622 | if (type == 2) { | |
623 | address = CBitcoinAddress(CScriptID(hash)).ToString(); | |
624 | } else if (type == 1) { | |
625 | address = CBitcoinAddress(CKeyID(hash)).ToString(); | |
fa7bf712 | 626 | } |
fa7bf712 | 627 | else { |
8b78a819 T |
628 | return false; |
629 | } | |
630 | return true; | |
631 | } | |
632 | ||
633 | bool getAddressesFromParams(const UniValue& params, std::vector<std::pair<uint160, int> > &addresses) | |
634 | { | |
635 | if (params[0].isStr()) { | |
636 | CBitcoinAddress address(params[0].get_str()); | |
637 | uint160 hashBytes; | |
638 | int type = 0; | |
639 | if (!address.GetIndexKey(hashBytes, type)) { | |
640 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); | |
641 | } | |
642 | addresses.push_back(std::make_pair(hashBytes, type)); | |
643 | } else if (params[0].isObject()) { | |
644 | ||
645 | UniValue addressValues = find_value(params[0].get_obj(), "addresses"); | |
646 | if (!addressValues.isArray()) { | |
647 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Addresses is expected to be an array"); | |
648 | } | |
649 | ||
650 | std::vector<UniValue> values = addressValues.getValues(); | |
651 | ||
652 | for (std::vector<UniValue>::iterator it = values.begin(); it != values.end(); ++it) { | |
653 | ||
654 | CBitcoinAddress address(it->get_str()); | |
655 | uint160 hashBytes; | |
656 | int type = 0; | |
657 | if (!address.GetIndexKey(hashBytes, type)) { | |
67d4c3be | 658 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid addresses"); |
8b78a819 T |
659 | } |
660 | addresses.push_back(std::make_pair(hashBytes, type)); | |
661 | } | |
662 | } else { | |
67d4c3be | 663 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid addresse"); |
8b78a819 T |
664 | } |
665 | ||
666 | return true; | |
667 | } | |
668 | ||
669 | bool heightSort(std::pair<CAddressUnspentKey, CAddressUnspentValue> a, | |
670 | std::pair<CAddressUnspentKey, CAddressUnspentValue> b) { | |
671 | return a.second.blockHeight < b.second.blockHeight; | |
672 | } | |
673 | ||
674 | bool timestampSort(std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> a, | |
675 | std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> b) { | |
676 | return a.second.time < b.second.time; | |
677 | } | |
678 | ||
679 | UniValue getaddressmempool(const UniValue& params, bool fHelp) | |
680 | { | |
681 | if (fHelp || params.size() != 1) | |
682 | throw runtime_error( | |
683 | "getaddressmempool\n" | |
684 | "\nReturns all mempool deltas for an address (requires addressindex to be enabled).\n" | |
685 | "\nArguments:\n" | |
686 | "{\n" | |
687 | " \"addresses\"\n" | |
688 | " [\n" | |
689 | " \"address\" (string) The base58check encoded address\n" | |
690 | " ,...\n" | |
691 | " ]\n" | |
692 | "}\n" | |
693 | "\nResult:\n" | |
694 | "[\n" | |
695 | " {\n" | |
696 | " \"address\" (string) The base58check encoded address\n" | |
697 | " \"txid\" (string) The related txid\n" | |
698 | " \"index\" (number) The related input or output index\n" | |
699 | " \"satoshis\" (number) The difference of satoshis\n" | |
700 | " \"timestamp\" (number) The time the transaction entered the mempool (seconds)\n" | |
701 | " \"prevtxid\" (string) The previous txid (if spending)\n" | |
702 | " \"prevout\" (string) The previous transaction output index (if spending)\n" | |
703 | " }\n" | |
704 | "]\n" | |
705 | "\nExamples:\n" | |
67d4c3be | 706 | + HelpExampleCli("getaddressmempool", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'") |
707 | + HelpExampleRpc("getaddressmempool", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}") | |
8b78a819 T |
708 | ); |
709 | ||
710 | std::vector<std::pair<uint160, int> > addresses; | |
711 | ||
712 | if (!getAddressesFromParams(params, addresses)) { | |
713 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); | |
714 | } | |
715 | ||
716 | std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> > indexes; | |
717 | ||
718 | if (!mempool.getAddressIndex(addresses, indexes)) { | |
719 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); | |
720 | } | |
721 | ||
722 | std::sort(indexes.begin(), indexes.end(), timestampSort); | |
723 | ||
724 | UniValue result(UniValue::VARR); | |
725 | ||
726 | for (std::vector<std::pair<CMempoolAddressDeltaKey, CMempoolAddressDelta> >::iterator it = indexes.begin(); | |
727 | it != indexes.end(); it++) { | |
728 | ||
729 | std::string address; | |
730 | if (!getAddressFromIndex(it->first.type, it->first.addressBytes, address)) { | |
731 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type"); | |
732 | } | |
733 | ||
734 | UniValue delta(UniValue::VOBJ); | |
735 | delta.push_back(Pair("address", address)); | |
736 | delta.push_back(Pair("txid", it->first.txhash.GetHex())); | |
737 | delta.push_back(Pair("index", (int)it->first.index)); | |
738 | delta.push_back(Pair("satoshis", it->second.amount)); | |
739 | delta.push_back(Pair("timestamp", it->second.time)); | |
740 | if (it->second.amount < 0) { | |
741 | delta.push_back(Pair("prevtxid", it->second.prevhash.GetHex())); | |
742 | delta.push_back(Pair("prevout", (int)it->second.prevout)); | |
743 | } | |
744 | result.push_back(delta); | |
745 | } | |
746 | ||
747 | return result; | |
748 | } | |
749 | ||
750 | UniValue getaddressutxos(const UniValue& params, bool fHelp) | |
751 | { | |
752 | if (fHelp || params.size() != 1) | |
753 | throw runtime_error( | |
754 | "getaddressutxos\n" | |
755 | "\nReturns all unspent outputs for an address (requires addressindex to be enabled).\n" | |
756 | "\nArguments:\n" | |
757 | "{\n" | |
758 | " \"addresses\"\n" | |
759 | " [\n" | |
760 | " \"address\" (string) The base58check encoded address\n" | |
761 | " ,...\n" | |
762 | " ],\n" | |
763 | " \"chainInfo\" (boolean) Include chain info with results\n" | |
764 | "}\n" | |
765 | "\nResult\n" | |
766 | "[\n" | |
767 | " {\n" | |
768 | " \"address\" (string) The address base58check encoded\n" | |
769 | " \"txid\" (string) The output txid\n" | |
770 | " \"height\" (number) The block height\n" | |
771 | " \"outputIndex\" (number) The output index\n" | |
772 | " \"script\" (strin) The script hex encoded\n" | |
773 | " \"satoshis\" (number) The number of satoshis of the output\n" | |
774 | " }\n" | |
775 | "]\n" | |
776 | "\nExamples:\n" | |
67d4c3be | 777 | + HelpExampleCli("getaddressutxos", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'") |
778 | + HelpExampleRpc("getaddressutxos", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}") | |
8b78a819 T |
779 | ); |
780 | ||
781 | bool includeChainInfo = false; | |
782 | if (params[0].isObject()) { | |
783 | UniValue chainInfo = find_value(params[0].get_obj(), "chainInfo"); | |
784 | if (chainInfo.isBool()) { | |
785 | includeChainInfo = chainInfo.get_bool(); | |
786 | } | |
787 | } | |
788 | ||
789 | std::vector<std::pair<uint160, int> > addresses; | |
790 | ||
791 | if (!getAddressesFromParams(params, addresses)) { | |
792 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); | |
793 | } | |
794 | ||
795 | std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs; | |
796 | ||
797 | for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) { | |
798 | if (!GetAddressUnspent((*it).first, (*it).second, unspentOutputs)) { | |
799 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); | |
800 | } | |
801 | } | |
802 | ||
803 | std::sort(unspentOutputs.begin(), unspentOutputs.end(), heightSort); | |
804 | ||
805 | UniValue utxos(UniValue::VARR); | |
806 | ||
807 | for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { | |
808 | UniValue output(UniValue::VOBJ); | |
809 | std::string address; | |
810 | if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) { | |
811 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type"); | |
812 | } | |
813 | ||
814 | output.push_back(Pair("address", address)); | |
815 | output.push_back(Pair("txid", it->first.txhash.GetHex())); | |
816 | output.push_back(Pair("outputIndex", (int)it->first.index)); | |
817 | output.push_back(Pair("script", HexStr(it->second.script.begin(), it->second.script.end()))); | |
818 | output.push_back(Pair("satoshis", it->second.satoshis)); | |
819 | output.push_back(Pair("height", it->second.blockHeight)); | |
820 | utxos.push_back(output); | |
821 | } | |
822 | ||
823 | if (includeChainInfo) { | |
824 | UniValue result(UniValue::VOBJ); | |
825 | result.push_back(Pair("utxos", utxos)); | |
826 | ||
827 | LOCK(cs_main); | |
828 | result.push_back(Pair("hash", chainActive.Tip()->GetBlockHash().GetHex())); | |
829 | result.push_back(Pair("height", (int)chainActive.Height())); | |
830 | return result; | |
831 | } else { | |
832 | return utxos; | |
833 | } | |
834 | } | |
835 | ||
836 | UniValue getaddressdeltas(const UniValue& params, bool fHelp) | |
837 | { | |
838 | if (fHelp || params.size() != 1 || !params[0].isObject()) | |
839 | throw runtime_error( | |
840 | "getaddressdeltas\n" | |
841 | "\nReturns all changes for an address (requires addressindex to be enabled).\n" | |
842 | "\nArguments:\n" | |
843 | "{\n" | |
844 | " \"addresses\"\n" | |
845 | " [\n" | |
846 | " \"address\" (string) The base58check encoded address\n" | |
847 | " ,...\n" | |
848 | " ]\n" | |
849 | " \"start\" (number) The start block height\n" | |
850 | " \"end\" (number) The end block height\n" | |
851 | " \"chainInfo\" (boolean) Include chain info in results, only applies if start and end specified\n" | |
852 | "}\n" | |
853 | "\nResult:\n" | |
854 | "[\n" | |
855 | " {\n" | |
856 | " \"satoshis\" (number) The difference of satoshis\n" | |
857 | " \"txid\" (string) The related txid\n" | |
858 | " \"index\" (number) The related input or output index\n" | |
859 | " \"height\" (number) The block height\n" | |
860 | " \"address\" (string) The base58check encoded address\n" | |
861 | " }\n" | |
862 | "]\n" | |
863 | "\nExamples:\n" | |
67d4c3be | 864 | + HelpExampleCli("getaddressdeltas", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'") |
865 | + HelpExampleRpc("getaddressdeltas", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}") | |
8b78a819 T |
866 | ); |
867 | ||
868 | ||
869 | UniValue startValue = find_value(params[0].get_obj(), "start"); | |
870 | UniValue endValue = find_value(params[0].get_obj(), "end"); | |
871 | ||
872 | UniValue chainInfo = find_value(params[0].get_obj(), "chainInfo"); | |
873 | bool includeChainInfo = false; | |
874 | if (chainInfo.isBool()) { | |
875 | includeChainInfo = chainInfo.get_bool(); | |
876 | } | |
877 | ||
878 | int start = 0; | |
879 | int end = 0; | |
880 | ||
881 | if (startValue.isNum() && endValue.isNum()) { | |
882 | start = startValue.get_int(); | |
883 | end = endValue.get_int(); | |
884 | if (start <= 0 || end <= 0) { | |
885 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start and end is expected to be greater than zero"); | |
886 | } | |
887 | if (end < start) { | |
888 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "End value is expected to be greater than start"); | |
889 | } | |
890 | } | |
891 | ||
892 | std::vector<std::pair<uint160, int> > addresses; | |
893 | ||
894 | if (!getAddressesFromParams(params, addresses)) { | |
895 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); | |
896 | } | |
897 | ||
898 | std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; | |
899 | ||
900 | for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) { | |
901 | if (start > 0 && end > 0) { | |
902 | if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) { | |
903 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); | |
904 | } | |
905 | } else { | |
906 | if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) { | |
907 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); | |
908 | } | |
909 | } | |
910 | } | |
911 | ||
912 | UniValue deltas(UniValue::VARR); | |
913 | ||
914 | for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { | |
915 | std::string address; | |
916 | if (!getAddressFromIndex(it->first.type, it->first.hashBytes, address)) { | |
917 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unknown address type"); | |
918 | } | |
919 | ||
920 | UniValue delta(UniValue::VOBJ); | |
921 | delta.push_back(Pair("satoshis", it->second)); | |
922 | delta.push_back(Pair("txid", it->first.txhash.GetHex())); | |
923 | delta.push_back(Pair("index", (int)it->first.index)); | |
924 | delta.push_back(Pair("blockindex", (int)it->first.txindex)); | |
925 | delta.push_back(Pair("height", it->first.blockHeight)); | |
926 | delta.push_back(Pair("address", address)); | |
927 | deltas.push_back(delta); | |
928 | } | |
929 | ||
930 | UniValue result(UniValue::VOBJ); | |
931 | ||
932 | if (includeChainInfo && start > 0 && end > 0) { | |
933 | LOCK(cs_main); | |
934 | ||
935 | if (start > chainActive.Height() || end > chainActive.Height()) { | |
936 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Start or end is outside chain range"); | |
937 | } | |
938 | ||
939 | CBlockIndex* startIndex = chainActive[start]; | |
940 | CBlockIndex* endIndex = chainActive[end]; | |
941 | ||
942 | UniValue startInfo(UniValue::VOBJ); | |
943 | UniValue endInfo(UniValue::VOBJ); | |
944 | ||
945 | startInfo.push_back(Pair("hash", startIndex->GetBlockHash().GetHex())); | |
946 | startInfo.push_back(Pair("height", start)); | |
947 | ||
948 | endInfo.push_back(Pair("hash", endIndex->GetBlockHash().GetHex())); | |
949 | endInfo.push_back(Pair("height", end)); | |
950 | ||
951 | result.push_back(Pair("deltas", deltas)); | |
952 | result.push_back(Pair("start", startInfo)); | |
953 | result.push_back(Pair("end", endInfo)); | |
954 | ||
955 | return result; | |
956 | } else { | |
957 | return deltas; | |
958 | } | |
959 | } | |
960 | ||
961 | UniValue getaddressbalance(const UniValue& params, bool fHelp) | |
962 | { | |
963 | if (fHelp || params.size() != 1) | |
964 | throw runtime_error( | |
965 | "getaddressbalance\n" | |
966 | "\nReturns the balance for an address(es) (requires addressindex to be enabled).\n" | |
967 | "\nArguments:\n" | |
968 | "{\n" | |
969 | " \"addresses\"\n" | |
970 | " [\n" | |
971 | " \"address\" (string) The base58check encoded address\n" | |
972 | " ,...\n" | |
973 | " ]\n" | |
974 | "}\n" | |
975 | "\nResult:\n" | |
976 | "{\n" | |
977 | " \"balance\" (string) The current balance in satoshis\n" | |
978 | " \"received\" (string) The total number of satoshis received (including change)\n" | |
979 | "}\n" | |
980 | "\nExamples:\n" | |
67d4c3be | 981 | + HelpExampleCli("getaddressbalance", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'") |
982 | + HelpExampleRpc("getaddressbalance", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}") | |
8b78a819 T |
983 | ); |
984 | ||
985 | std::vector<std::pair<uint160, int> > addresses; | |
986 | ||
987 | if (!getAddressesFromParams(params, addresses)) { | |
988 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); | |
989 | } | |
990 | ||
991 | std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; | |
992 | ||
993 | for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) { | |
994 | if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) { | |
995 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); | |
996 | } | |
997 | } | |
998 | ||
999 | CAmount balance = 0; | |
1000 | CAmount received = 0; | |
1001 | ||
1002 | for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { | |
1003 | if (it->second > 0) { | |
1004 | received += it->second; | |
1005 | } | |
1006 | balance += it->second; | |
1007 | } | |
1008 | ||
1009 | UniValue result(UniValue::VOBJ); | |
1010 | result.push_back(Pair("balance", balance)); | |
1011 | result.push_back(Pair("received", received)); | |
1012 | ||
1013 | return result; | |
1014 | ||
1015 | } | |
1016 | ||
329d80d2 | 1017 | int32_t komodo_snapshot(); |
1018 | ||
22007819 | 1019 | UniValue getsnapshot(const UniValue& params, bool fHelp) |
1020 | { | |
67d2e41b | 1021 | UniValue result(UniValue::VOBJ); int64_t total; |
22007819 | 1022 | if ( fHelp || params.size() > 0 ) |
1023 | { | |
1024 | throw runtime_error( | |
1025 | "getsnapshot\n" | |
1026 | ); | |
1027 | } | |
67d2e41b | 1028 | if ( (total= komodo_snapshot()) >= 0 ) |
1029 | result.push_back(Pair("total", (double)total/COIN)); | |
329d80d2 | 1030 | else result.push_back(Pair("error", "no addressindex")); |
22007819 | 1031 | return(result); |
1032 | } | |
1033 | ||
8b78a819 T |
1034 | UniValue getaddresstxids(const UniValue& params, bool fHelp) |
1035 | { | |
1036 | if (fHelp || params.size() != 1) | |
1037 | throw runtime_error( | |
1038 | "getaddresstxids\n" | |
1039 | "\nReturns the txids for an address(es) (requires addressindex to be enabled).\n" | |
1040 | "\nArguments:\n" | |
1041 | "{\n" | |
1042 | " \"addresses\"\n" | |
1043 | " [\n" | |
1044 | " \"address\" (string) The base58check encoded address\n" | |
1045 | " ,...\n" | |
1046 | " ]\n" | |
1047 | " \"start\" (number) The start block height\n" | |
1048 | " \"end\" (number) The end block height\n" | |
1049 | "}\n" | |
1050 | "\nResult:\n" | |
1051 | "[\n" | |
1052 | " \"transactionid\" (string) The transaction id\n" | |
1053 | " ,...\n" | |
1054 | "]\n" | |
1055 | "\nExamples:\n" | |
67d4c3be | 1056 | + HelpExampleCli("getaddresstxids", "'{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}'") |
1057 | + HelpExampleRpc("getaddresstxids", "{\"addresses\": [\"RY5LccmGiX9bUHYGtSWQouNy1yFhc5rM87\"]}") | |
8b78a819 T |
1058 | ); |
1059 | ||
1060 | std::vector<std::pair<uint160, int> > addresses; | |
1061 | ||
1062 | if (!getAddressesFromParams(params, addresses)) { | |
1063 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address"); | |
1064 | } | |
1065 | ||
1066 | int start = 0; | |
1067 | int end = 0; | |
1068 | if (params[0].isObject()) { | |
1069 | UniValue startValue = find_value(params[0].get_obj(), "start"); | |
1070 | UniValue endValue = find_value(params[0].get_obj(), "end"); | |
1071 | if (startValue.isNum() && endValue.isNum()) { | |
1072 | start = startValue.get_int(); | |
1073 | end = endValue.get_int(); | |
1074 | } | |
1075 | } | |
1076 | ||
1077 | std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; | |
1078 | ||
1079 | for (std::vector<std::pair<uint160, int> >::iterator it = addresses.begin(); it != addresses.end(); it++) { | |
1080 | if (start > 0 && end > 0) { | |
1081 | if (!GetAddressIndex((*it).first, (*it).second, addressIndex, start, end)) { | |
1082 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); | |
1083 | } | |
1084 | } else { | |
1085 | if (!GetAddressIndex((*it).first, (*it).second, addressIndex)) { | |
1086 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for address"); | |
1087 | } | |
1088 | } | |
1089 | } | |
1090 | ||
1091 | std::set<std::pair<int, std::string> > txids; | |
1092 | UniValue result(UniValue::VARR); | |
1093 | ||
1094 | for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { | |
1095 | int height = it->first.blockHeight; | |
1096 | std::string txid = it->first.txhash.GetHex(); | |
1097 | ||
1098 | if (addresses.size() > 1) { | |
1099 | txids.insert(std::make_pair(height, txid)); | |
1100 | } else { | |
1101 | if (txids.insert(std::make_pair(height, txid)).second) { | |
1102 | result.push_back(txid); | |
1103 | } | |
1104 | } | |
1105 | } | |
1106 | ||
1107 | if (addresses.size() > 1) { | |
1108 | for (std::set<std::pair<int, std::string> >::const_iterator it=txids.begin(); it!=txids.end(); it++) { | |
1109 | result.push_back(it->second); | |
1110 | } | |
1111 | } | |
1112 | ||
1113 | return result; | |
1114 | ||
1115 | } | |
1116 | ||
1117 | UniValue getspentinfo(const UniValue& params, bool fHelp) | |
1118 | { | |
1119 | ||
1120 | if (fHelp || params.size() != 1 || !params[0].isObject()) | |
1121 | throw runtime_error( | |
1122 | "getspentinfo\n" | |
1123 | "\nReturns the txid and index where an output is spent.\n" | |
1124 | "\nArguments:\n" | |
1125 | "{\n" | |
1126 | " \"txid\" (string) The hex string of the txid\n" | |
1127 | " \"index\" (number) The start block height\n" | |
1128 | "}\n" | |
1129 | "\nResult:\n" | |
1130 | "{\n" | |
1131 | " \"txid\" (string) The transaction id\n" | |
1132 | " \"index\" (number) The spending input index\n" | |
1133 | " ,...\n" | |
1134 | "}\n" | |
1135 | "\nExamples:\n" | |
1136 | + HelpExampleCli("getspentinfo", "'{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}'") | |
1137 | + HelpExampleRpc("getspentinfo", "{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}") | |
1138 | ); | |
1139 | ||
1140 | UniValue txidValue = find_value(params[0].get_obj(), "txid"); | |
1141 | UniValue indexValue = find_value(params[0].get_obj(), "index"); | |
1142 | ||
1143 | if (!txidValue.isStr() || !indexValue.isNum()) { | |
1144 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid txid or index"); | |
1145 | } | |
1146 | ||
1147 | uint256 txid = ParseHashV(txidValue, "txid"); | |
1148 | int outputIndex = indexValue.get_int(); | |
1149 | ||
1150 | CSpentIndexKey key(txid, outputIndex); | |
1151 | CSpentIndexValue value; | |
1152 | ||
1153 | if (!GetSpentIndex(key, value)) { | |
1154 | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to get spent info"); | |
1155 | } | |
1156 | ||
1157 | UniValue obj(UniValue::VOBJ); | |
1158 | obj.push_back(Pair("txid", value.txid.GetHex())); | |
1159 | obj.push_back(Pair("index", (int)value.inputIndex)); | |
1160 | obj.push_back(Pair("height", value.blockHeight)); | |
1161 | ||
1162 | return obj; | |
e8fa58ec | 1163 | } |