test
[VerusCoin.git] / src / rpcblockchain.cpp
CommitLineData
c625ae04 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
c625ae04
JG
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
ac14bcc1 6#include "checkpoints.h"
da29ecbc 7#include "consensus/validation.h"
51ed9ec9 8#include "main.h"
da29ecbc 9#include "primitives/transaction.h"
ac14bcc1 10#include "rpcserver.h"
51ed9ec9 11#include "sync.h"
ad49c256 12#include "util.h"
51ed9ec9
BD
13
14#include <stdint.h>
15
16#include "json/json_spirit_value.h"
c625ae04
JG
17
18using namespace json_spirit;
19using namespace std;
20
73351c36 21extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
be066fad 22void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
4e68391a 23
695a7a88 24double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty)
c625ae04
JG
25{
26 // Floating point number that is a multiple of the minimum difficulty,
27 // minimum difficulty = 1.0.
28 if (blockindex == NULL)
29 {
4c6d41b8 30 if (chainActive.Tip() == NULL)
c625ae04
JG
31 return 1.0;
32 else
4c6d41b8 33 blockindex = chainActive.Tip();
c625ae04
JG
34 }
35
333ea3c4
JG
36 uint32_t bits;
37 if (networkDifficulty) {
38 bits = GetNextWorkRequired(blockindex, nullptr, Params().GetConsensus());
39 } else {
40 bits = blockindex->nBits;
695a7a88
JG
41 }
42
333ea3c4 43 uint32_t powLimit =
f50e8313 44 UintToArith256(Params().GetConsensus().powLimit).GetCompact();
333ea3c4 45 int nShift = (bits >> 24) & 0xff;
24809b16 46 int nShiftAmount = (powLimit >> 24) & 0xff;
c625ae04
JG
47
48 double dDiff =
24809b16 49 (double)(powLimit & 0x00ffffff) /
333ea3c4 50 (double)(bits & 0x00ffffff);
c625ae04 51
24809b16 52 while (nShift < nShiftAmount)
c625ae04
JG
53 {
54 dDiff *= 256.0;
55 nShift++;
56 }
24809b16 57 while (nShift > nShiftAmount)
c625ae04
JG
58 {
59 dDiff /= 256.0;
60 nShift--;
61 }
62
63 return dDiff;
64}
65
695a7a88
JG
66double GetDifficulty(const CBlockIndex* blockindex)
67{
68 return GetDifficultyINTERNAL(blockindex, false);
69}
70
71double GetNetworkDifficulty(const CBlockIndex* blockindex)
72{
73 return GetDifficultyINTERNAL(blockindex, true);
74}
75
c625ae04 76
73351c36 77Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
c625ae04
JG
78{
79 Object result;
80 result.push_back(Pair("hash", block.GetHash().GetHex()));
57153d4e
WL
81 int confirmations = -1;
82 // Only report confirmations if the block is on the main chain
83 if (chainActive.Contains(blockindex))
84 confirmations = chainActive.Height() - blockindex->nHeight + 1;
85 result.push_back(Pair("confirmations", confirmations));
c625ae04
JG
86 result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
87 result.push_back(Pair("height", blockindex->nHeight));
88 result.push_back(Pair("version", block.nVersion));
89 result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
90 Array txs;
91 BOOST_FOREACH(const CTransaction&tx, block.vtx)
73351c36
JS
92 {
93 if(txDetails)
94 {
95 Object objTx;
4f152496 96 TxToJSON(tx, uint256(), objTx);
73351c36
JS
97 txs.push_back(objTx);
98 }
99 else
805344dc 100 txs.push_back(tx.GetHash().GetHex());
73351c36 101 }
c625ae04 102 result.push_back(Pair("tx", txs));
d56e30ca 103 result.push_back(Pair("time", block.GetBlockTime()));
fdda3c50 104 result.push_back(Pair("nonce", block.nNonce.GetHex()));
e1dde421 105 result.push_back(Pair("solution", HexStr(block.nSolution)));
645d497a 106 result.push_back(Pair("bits", strprintf("%08x", block.nBits)));
c625ae04 107 result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
1b3656d5 108 result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
c625ae04
JG
109
110 if (blockindex->pprev)
111 result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
4c6d41b8 112 CBlockIndex *pnext = chainActive.Next(blockindex);
0fe8010a
PW
113 if (pnext)
114 result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
c625ae04
JG
115 return result;
116}
117
118
119Value getblockcount(const Array& params, bool fHelp)
120{
121 if (fHelp || params.size() != 0)
122 throw runtime_error(
123 "getblockcount\n"
a6099ef3 124 "\nReturns the number of blocks in the longest block chain.\n"
125 "\nResult:\n"
126 "n (numeric) The current block count\n"
127 "\nExamples:\n"
128 + HelpExampleCli("getblockcount", "")
129 + HelpExampleRpc("getblockcount", "")
130 );
c625ae04 131
4401b2d7 132 LOCK(cs_main);
4c6d41b8 133 return chainActive.Height();
c625ae04
JG
134}
135
091aa8da
JG
136Value getbestblockhash(const Array& params, bool fHelp)
137{
138 if (fHelp || params.size() != 0)
139 throw runtime_error(
140 "getbestblockhash\n"
a6099ef3 141 "\nReturns the hash of the best (tip) block in the longest block chain.\n"
142 "\nResult\n"
143 "\"hex\" (string) the block hash hex encoded\n"
144 "\nExamples\n"
145 + HelpExampleCli("getbestblockhash", "")
146 + HelpExampleRpc("getbestblockhash", "")
147 );
091aa8da 148
4401b2d7 149 LOCK(cs_main);
4c6d41b8 150 return chainActive.Tip()->GetBlockHash().GetHex();
091aa8da 151}
c625ae04
JG
152
153Value getdifficulty(const Array& params, bool fHelp)
154{
155 if (fHelp || params.size() != 0)
156 throw runtime_error(
157 "getdifficulty\n"
a6099ef3 158 "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
159 "\nResult:\n"
160 "n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
161 "\nExamples:\n"
162 + HelpExampleCli("getdifficulty", "")
163 + HelpExampleRpc("getdifficulty", "")
164 );
c625ae04 165
4401b2d7 166 LOCK(cs_main);
695a7a88 167 return GetNetworkDifficulty();
c625ae04
JG
168}
169
170
c625ae04
JG
171Value getrawmempool(const Array& params, bool fHelp)
172{
4d707d51 173 if (fHelp || params.size() > 1)
c625ae04 174 throw runtime_error(
4d707d51 175 "getrawmempool ( verbose )\n"
a6099ef3 176 "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
4d707d51
GA
177 "\nArguments:\n"
178 "1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n"
179 "\nResult: (for verbose = false):\n"
180 "[ (json array of string)\n"
a6099ef3 181 " \"transactionid\" (string) The transaction id\n"
182 " ,...\n"
183 "]\n"
4d707d51
GA
184 "\nResult: (for verbose = true):\n"
185 "{ (json object)\n"
186 " \"transactionid\" : { (json object)\n"
187 " \"size\" : n, (numeric) transaction size in bytes\n"
188 " \"fee\" : n, (numeric) transaction fee in bitcoins\n"
189 " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
190 " \"height\" : n, (numeric) block height when transaction entered pool\n"
191 " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
192 " \"currentpriority\" : n, (numeric) transaction priority now\n"
193 " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
194 " \"transactionid\", (string) parent transaction id\n"
195 " ... ]\n"
196 " }, ...\n"
803f51ef 197 "}\n"
a6099ef3 198 "\nExamples\n"
4d707d51
GA
199 + HelpExampleCli("getrawmempool", "true")
200 + HelpExampleRpc("getrawmempool", "true")
a6099ef3 201 );
c625ae04 202
4401b2d7
EL
203 LOCK(cs_main);
204
4d707d51
GA
205 bool fVerbose = false;
206 if (params.size() > 0)
207 fVerbose = params[0].get_bool();
c625ae04 208
4d707d51
GA
209 if (fVerbose)
210 {
211 LOCK(mempool.cs);
212 Object o;
213 BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx)
214 {
215 const uint256& hash = entry.first;
216 const CTxMemPoolEntry& e = entry.second;
217 Object info;
218 info.push_back(Pair("size", (int)e.GetTxSize()));
219 info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
d56e30ca 220 info.push_back(Pair("time", e.GetTime()));
4d707d51
GA
221 info.push_back(Pair("height", (int)e.GetHeight()));
222 info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
223 info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
224 const CTransaction& tx = e.GetTx();
225 set<string> setDepends;
226 BOOST_FOREACH(const CTxIn& txin, tx.vin)
227 {
228 if (mempool.exists(txin.prevout.hash))
229 setDepends.insert(txin.prevout.hash.ToString());
230 }
231 Array depends(setDepends.begin(), setDepends.end());
232 info.push_back(Pair("depends", depends));
233 o.push_back(Pair(hash.ToString(), info));
234 }
235 return o;
236 }
237 else
238 {
239 vector<uint256> vtxid;
240 mempool.queryHashes(vtxid);
c625ae04 241
4d707d51
GA
242 Array a;
243 BOOST_FOREACH(const uint256& hash, vtxid)
244 a.push_back(hash.ToString());
245
246 return a;
247 }
c625ae04
JG
248}
249
250Value getblockhash(const Array& params, bool fHelp)
251{
252 if (fHelp || params.size() != 1)
253 throw runtime_error(
a6099ef3 254 "getblockhash index\n"
255 "\nReturns hash of block in best-block-chain at index provided.\n"
256 "\nArguments:\n"
257 "1. index (numeric, required) The block index\n"
258 "\nResult:\n"
259 "\"hash\" (string) The block hash\n"
260 "\nExamples:\n"
261 + HelpExampleCli("getblockhash", "1000")
262 + HelpExampleRpc("getblockhash", "1000")
263 );
c625ae04 264
4401b2d7
EL
265 LOCK(cs_main);
266
c625ae04 267 int nHeight = params[0].get_int();
4c6d41b8 268 if (nHeight < 0 || nHeight > chainActive.Height())
6261e6e6 269 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
c625ae04 270
4c6d41b8
PW
271 CBlockIndex* pblockindex = chainActive[nHeight];
272 return pblockindex->GetBlockHash().GetHex();
c625ae04
JG
273}
274
275Value getblock(const Array& params, bool fHelp)
276{
23319521 277 if (fHelp || params.size() < 1 || params.size() > 2)
c625ae04 278 throw runtime_error(
a6099ef3 279 "getblock \"hash\" ( verbose )\n"
280 "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
281 "If verbose is true, returns an Object with information about block <hash>.\n"
282 "\nArguments:\n"
283 "1. \"hash\" (string, required) The block hash\n"
284 "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
285 "\nResult (for verbose = true):\n"
286 "{\n"
287 " \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
57153d4e 288 " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
a6099ef3 289 " \"size\" : n, (numeric) The block size\n"
290 " \"height\" : n, (numeric) The block height or index\n"
291 " \"version\" : n, (numeric) The block version\n"
292 " \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
293 " \"tx\" : [ (array of string) The transaction ids\n"
294 " \"transactionid\" (string) The transaction id\n"
295 " ,...\n"
296 " ],\n"
297 " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
298 " \"nonce\" : n, (numeric) The nonce\n"
299 " \"bits\" : \"1d00ffff\", (string) The bits\n"
300 " \"difficulty\" : x.xxx, (numeric) The difficulty\n"
301 " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
302 " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
303 "}\n"
304 "\nResult (for verbose=false):\n"
305 "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
306 "\nExamples:\n"
307 + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
308 + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
23319521 309 );
c625ae04 310
4401b2d7
EL
311 LOCK(cs_main);
312
c625ae04 313 std::string strHash = params[0].get_str();
34cdc411 314 uint256 hash(uint256S(strHash));
c625ae04 315
23319521
LD
316 bool fVerbose = true;
317 if (params.size() > 1)
318 fVerbose = params[1].get_bool();
319
c625ae04 320 if (mapBlockIndex.count(hash) == 0)
738835d7 321 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
c625ae04
JG
322
323 CBlock block;
324 CBlockIndex* pblockindex = mapBlockIndex[hash];
954d2e72 325
03c56872
JS
326 if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
327 throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)");
328
f2dd868d 329 if(!ReadBlockFromDisk(block, pblockindex))
954d2e72 330 throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
c625ae04 331
23319521
LD
332 if (!fVerbose)
333 {
334 CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
335 ssBlock << block;
336 std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
337 return strHex;
338 }
339
c625ae04
JG
340 return blockToJSON(block, pblockindex);
341}
342
beeb5761
PW
343Value gettxoutsetinfo(const Array& params, bool fHelp)
344{
345 if (fHelp || params.size() != 0)
346 throw runtime_error(
347 "gettxoutsetinfo\n"
a6099ef3 348 "\nReturns statistics about the unspent transaction output set.\n"
349 "Note this call may take some time.\n"
350 "\nResult:\n"
351 "{\n"
352 " \"height\":n, (numeric) The current block height (index)\n"
353 " \"bestblock\": \"hex\", (string) the best block hash hex\n"
354 " \"transactions\": n, (numeric) The number of transactions\n"
355 " \"txouts\": n, (numeric) The number of output transactions\n"
356 " \"bytes_serialized\": n, (numeric) The serialized size\n"
357 " \"hash_serialized\": \"hash\", (string) The serialized hash\n"
358 " \"total_amount\": x.xxx (numeric) The total amount\n"
359 "}\n"
360 "\nExamples:\n"
361 + HelpExampleCli("gettxoutsetinfo", "")
362 + HelpExampleRpc("gettxoutsetinfo", "")
363 );
beeb5761 364
4401b2d7
EL
365 LOCK(cs_main);
366
beeb5761
PW
367 Object ret;
368
369 CCoinsStats stats;
51ce901a 370 FlushStateToDisk();
beeb5761 371 if (pcoinsTip->GetStats(stats)) {
4b61a6a4 372 ret.push_back(Pair("height", (int64_t)stats.nHeight));
e31aa7c9 373 ret.push_back(Pair("bestblock", stats.hashBlock.GetHex()));
4b61a6a4
KD
374 ret.push_back(Pair("transactions", (int64_t)stats.nTransactions));
375 ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs));
376 ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize));
e31aa7c9
PW
377 ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex()));
378 ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount)));
beeb5761
PW
379 }
380 return ret;
381}
c625ae04 382
17878015 383uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime);
7a77c443 384uint32_t komodo_txtime(uint256 hash);
0bda6249 385uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uint64_t basevolume);
d836ec3f 386int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel);
1e9d15c6 387int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height);
388char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len);
50760585 389uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n);
dbaf1154 390int32_t komodo_minerids(uint8_t *minerids,int32_t height);
391
392Value minerids(const Array& params, bool fHelp)
393{
47cbf8e6 394 Object ret; Array a; uint8_t minerids[1000],pubkeys[64][33]; int32_t i,j,n,numnotaries,tally[65];
dbaf1154 395 if ( fHelp || params.size() != 1 )
396 throw runtime_error("minerids needs height\n");
397 LOCK(cs_main);
056447a6 398 int32_t height = atoi(params[0].get_str().c_str());
55ecfab2 399 if ( height <= 0 )
400 height = chainActive.Tip()->nHeight;
d6be719d 401 if ( (n= komodo_minerids(minerids,height)) > 0 )
dbaf1154 402 {
403 memset(tally,0,sizeof(tally));
47cbf8e6 404 numnotaries = komodo_notaries(pubkeys,height);
405 if ( numnotaries > 0 )
dbaf1154 406 {
47cbf8e6 407 for (i=0; i<n; i++)
408 {
409 if ( minerids[i] >= numnotaries )
410 tally[64]++;
411 else tally[minerids[i]]++;
412 }
dbaf1154 413 for (i=0; i<64; i++)
414 {
415 Object item; std::string hex; char *hexstr;
416 hex.resize(66);
417 hexstr = (char *)hex.data();
418 for (j=0; j<33; j++)
419 sprintf(&hexstr[j*2],"%02x",pubkeys[i][j]);
8711ee8f 420 item.push_back(Pair("notaryid", i));
dbaf1154 421 item.push_back(Pair("pubkey", hex));
422 item.push_back(Pair("blocks", tally[i]));
423 a.push_back(item);
424 }
55ecfab2 425 Object item;
14ecdc67 426 item.push_back(Pair("pubkey", (char *)"external miners"));
427 item.push_back(Pair("blocks", tally[64]));
428 a.push_back(item);
dbaf1154 429 }
430 ret.push_back(Pair("mined", a));
431 } else ret.push_back(Pair("error", (char *)"couldnt extract minerids"));
432 return ret;
433}
e596e202 434
1e9d15c6 435Value notaries(const Array& params, bool fHelp)
436{
ff4657a7 437 Array a; Object ret; int32_t i,j,n,m; char *hexstr; uint8_t pubkeys[64][33]; char btcaddr[64],kmdaddr[64],*ptr;
1e9d15c6 438 if ( fHelp || params.size() != 1 )
439 throw runtime_error("notaries height\n");
440 LOCK(cs_main);
a8af456e 441 int32_t height = atoi(params[0].get_str().c_str());
895f044a 442 if ( height < 0 )
443 height = 0;
6677fa31 444 //fprintf(stderr,"notaries as of height.%d\n",height);
c29e766f 445 //if ( height > chainActive.Height()+20000 )
446 // throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
447 //else
1e9d15c6 448 {
1e9d15c6 449 if ( (n= komodo_notaries(pubkeys,height)) > 0 )
450 {
451 for (i=0; i<n; i++)
452 {
98622aa7 453 Object item;
ff4657a7 454 std::string btcaddress,kmdaddress,hex;
1ffa653a 455 hex.resize(66);
456 hexstr = (char *)hex.data();
457 for (j=0; j<33; j++)
458 sprintf(&hexstr[j*2],"%02x",pubkeys[i][j]);
459 item.push_back(Pair("pubkey", hex));
460
1e9d15c6 461 bitcoin_address(btcaddr,0,pubkeys[i],33);
462 m = (int32_t)strlen(btcaddr);
69900ca4 463 btcaddress.resize(m);
1e9d15c6 464 ptr = (char *)btcaddress.data();
6eb6f5f7 465 memcpy(ptr,btcaddr,m);
1ffa653a 466 item.push_back(Pair("BTCaddress", btcaddress));
467
1e9d15c6 468 bitcoin_address(kmdaddr,60,pubkeys[i],33);
469 m = (int32_t)strlen(kmdaddr);
69900ca4 470 kmdaddress.resize(m);
1e9d15c6 471 ptr = (char *)kmdaddress.data();
69900ca4 472 memcpy(ptr,kmdaddr,m);
1e9d15c6 473 item.push_back(Pair("KMDaddress", kmdaddress));
474 a.push_back(item);
475 }
476 }
477 ret.push_back(Pair("notaries", a));
37e7db08 478 ret.push_back(Pair("numnotaries", n));
1e9d15c6 479 }
480 return ret;
481}
a9869d0d 482
9bd3a9cd 483int32_t komodo_pending_withdraws(char *opretstr);
aa114a60 484int32_t pax_fiatstatus(uint64_t *available,uint64_t *deposited,uint64_t *issued,uint64_t *withdrawn,uint64_t *approved,uint64_t *redeemed,char *base);
700606cc 485extern char CURRENCIES[][8];
9bd3a9cd 486
487Value paxpending(const Array& params, bool fHelp)
7cc6844b 488{
aa114a60 489 Object ret; Array a; char opretbuf[10000*2]; int32_t opretlen,baseid; uint64_t available,deposited,issued,withdrawn,approved,redeemed;
7cc6844b 490 if ( fHelp || params.size() != 0 )
9bd3a9cd 491 throw runtime_error("paxpending needs no args\n");
7cc6844b 492 LOCK(cs_main);
493 if ( (opretlen= komodo_pending_withdraws(opretbuf)) > 0 )
494 ret.push_back(Pair("withdraws", opretbuf));
495 else ret.push_back(Pair("withdraws", (char *)""));
3cbfd2b4 496 for (baseid=0; baseid<32; baseid++)
497 {
498 Object item,obj;
499 if ( pax_fiatstatus(&deposited,&issued,&withdrawn,&approved,&redeemed,CURRENCIES[baseid]) == 0 )
500 {
501 if ( deposited != 0 || issued != 0 || withdrawn != 0 || approved != 0 || redeemed != 0 )
502 {
aa114a60 503 item.push_back(Pair("available", ValueFromAmount(available)));
1db587b5 504 item.push_back(Pair("deposited", ValueFromAmount(deposited)));
505 item.push_back(Pair("issued", ValueFromAmount(issued)));
506 item.push_back(Pair("withdrawn", ValueFromAmount(withdrawn)));
507 item.push_back(Pair("approved", ValueFromAmount(approved)));
508 item.push_back(Pair("redeemed", ValueFromAmount(redeemed)));
3cbfd2b4 509 obj.push_back(Pair(CURRENCIES[baseid],item));
510 a.push_back(obj);
511 }
512 }
513 }
514 ret.push_back(Pair("fiatstatus", a));
7cc6844b 515 return ret;
516}
517
a9869d0d 518Value paxprice(const Array& params, bool fHelp)
519{
1f346363 520 if ( fHelp || params.size() < 3 || params.size() > 4 )
05f1a5d1 521 throw runtime_error("paxprice \"base\" \"rel\" height amount\n");
a9869d0d 522 LOCK(cs_main);
0bda6249 523 Object ret; uint64_t basevolume=0,relvolume,seed;
a9869d0d 524 std::string base = params[0].get_str();
525 std::string rel = params[1].get_str();
96eb75ee 526 int32_t height = atoi(params[2].get_str().c_str());
05f1a5d1 527 if ( params.size() == 3 || (basevolume= COIN * atof(params[3].get_str().c_str())) == 0 )
1f346363 528 basevolume = COIN;
0bda6249 529 relvolume = komodo_paxprice(&seed,height,(char *)base.c_str(),(char *)rel.c_str(),basevolume);
a9869d0d 530 ret.push_back(Pair("base", base));
531 ret.push_back(Pair("rel", rel));
532 ret.push_back(Pair("height", height));
73ccdf55 533 char seedstr[32];
534 sprintf(seedstr,"%llu",(long long)seed);
535 ret.push_back(Pair("seed", seedstr));
d019c447 536 if ( height < 0 || height > chainActive.Height() )
537 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
538 else
1f346363 539 {
d019c447 540 CBlockIndex *pblockindex = chainActive[height];
1d8bddf7 541 ret.push_back(Pair("timestamp", (int64_t)pblockindex->nTime));
d019c447 542 if ( basevolume != 0 && relvolume != 0 )
543 {
544 ret.push_back(Pair("price",((double)relvolume / (double)basevolume)));
545 ret.push_back(Pair("invprice",((double)basevolume / (double)relvolume)));
546 ret.push_back(Pair("basevolume", ValueFromAmount(basevolume)));
547 ret.push_back(Pair("relvolume", ValueFromAmount(relvolume)));
46e78b7f 548 } else ret.push_back(Pair("error", "overflow or error in one or more of parameters"));
a4ebaad7 549 }
550 return ret;
551}
552
553Value paxprices(const Array& params, bool fHelp)
554{
555 if ( fHelp || params.size() != 3 )
d836ec3f 556 throw runtime_error("paxprices \"base\" \"rel\" maxsamples\n");
a4ebaad7 557 LOCK(cs_main);
d836ec3f 558 Object ret; uint64_t relvolume,prices[4096]; uint32_t i,n; int32_t heights[sizeof(prices)/sizeof(*prices)];
a4ebaad7 559 std::string base = params[0].get_str();
560 std::string rel = params[1].get_str();
0d195951 561 int32_t maxsamples = atoi(params[2].get_str().c_str());
05dfe053 562 if ( maxsamples < 1 )
563 maxsamples = 1;
d836ec3f 564 else if ( maxsamples > sizeof(heights)/sizeof(*heights) )
565 maxsamples = sizeof(heights)/sizeof(*heights);
a4ebaad7 566 ret.push_back(Pair("base", base));
567 ret.push_back(Pair("rel", rel));
d836ec3f 568 n = komodo_paxprices(heights,prices,maxsamples,(char *)base.c_str(),(char *)rel.c_str());
96eb75ee 569 Array a;
570 for (i=0; i<n; i++)
a4ebaad7 571 {
96eb75ee 572 Object item;
56d91e9c 573 if ( heights[i] < 0 || heights[i] > chainActive.Height() )
574 throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
575 else
576 {
577 CBlockIndex *pblockindex = chainActive[heights[i]];
578
579 item.push_back(Pair("t", (int64_t)pblockindex->nTime));
580 item.push_back(Pair("p", (double)prices[i] / COIN));
581 a.push_back(item);
582 }
1f346363 583 }
96eb75ee 584 ret.push_back(Pair("array", a));
a9869d0d 585 return ret;
586}
7a77c443 587
798f28c7 588uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue);
0fec0cc4 589
beeb5761
PW
590Value gettxout(const Array& params, bool fHelp)
591{
592 if (fHelp || params.size() < 2 || params.size() > 3)
593 throw runtime_error(
a6099ef3 594 "gettxout \"txid\" n ( includemempool )\n"
595 "\nReturns details about an unspent transaction output.\n"
596 "\nArguments:\n"
597 "1. \"txid\" (string, required) The transaction id\n"
598 "2. n (numeric, required) vout value\n"
599 "3. includemempool (boolean, optional) Whether to included the mem pool\n"
600 "\nResult:\n"
601 "{\n"
602 " \"bestblock\" : \"hash\", (string) the block hash\n"
603 " \"confirmations\" : n, (numeric) The number of confirmations\n"
604 " \"value\" : x.xxx, (numeric) The transaction value in btc\n"
605 " \"scriptPubKey\" : { (json object)\n"
606 " \"asm\" : \"code\", (string) \n"
607 " \"hex\" : \"hex\", (string) \n"
608 " \"reqSigs\" : n, (numeric) Number of required signatures\n"
609 " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n"
610 " \"addresses\" : [ (array of string) array of bitcoin addresses\n"
611 " \"bitcoinaddress\" (string) bitcoin address\n"
612 " ,...\n"
613 " ]\n"
614 " },\n"
615 " \"version\" : n, (numeric) The version\n"
616 " \"coinbase\" : true|false (boolean) Coinbase or not\n"
617 "}\n"
618
619 "\nExamples:\n"
620 "\nGet unspent transactions\n"
621 + HelpExampleCli("listunspent", "") +
622 "\nView the details\n"
623 + HelpExampleCli("gettxout", "\"txid\" 1") +
624 "\nAs a json rpc call\n"
625 + HelpExampleRpc("gettxout", "\"txid\", 1")
626 );
c625ae04 627
4401b2d7
EL
628 LOCK(cs_main);
629
beeb5761
PW
630 Object ret;
631
632 std::string strHash = params[0].get_str();
34cdc411 633 uint256 hash(uint256S(strHash));
beeb5761
PW
634 int n = params[1].get_int();
635 bool fMempool = true;
636 if (params.size() > 2)
637 fMempool = params[2].get_bool();
638
639 CCoins coins;
640 if (fMempool) {
641 LOCK(mempool.cs);
7c70438d 642 CCoinsViewMemPool view(pcoinsTip, mempool);
beeb5761
PW
643 if (!view.GetCoins(hash, coins))
644 return Value::null;
645 mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
646 } else {
647 if (!pcoinsTip->GetCoins(hash, coins))
648 return Value::null;
649 }
650 if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
651 return Value::null;
652
145d5be8 653 BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
7a77c443 654 CBlockIndex *pindex = it->second;
84674082 655 ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex()));
beeb5761
PW
656 if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
657 ret.push_back(Pair("confirmations", 0));
cad0d1ca 658 else ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
4e68391a 659 ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
798f28c7 660 uint64_t interest; int32_t txheight; uint32_t locktime;
661 if ( (interest= komodo_accrued_interest(&txheight,&locktime,hash,n,coins.nHeight,coins.vout[n].nValue)) != 0 )
0fec0cc4 662 ret.push_back(Pair("interest", ValueFromAmount(interest)));
beeb5761 663 Object o;
be066fad 664 ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
beeb5761
PW
665 ret.push_back(Pair("scriptPubKey", o));
666 ret.push_back(Pair("version", coins.nVersion));
667 ret.push_back(Pair("coinbase", coins.fCoinBase));
668
669 return ret;
670}
c625ae04 671
29eccc7c 672int32_t gettxout_scriptPubKey(uint8_t *scriptPubKey,int32_t maxsize,uint256 txid,int32_t n)
fc318ffe 673{
674 int32_t i,m; uint8_t *ptr;
675 LOCK(cs_main);
676 CCoins coins;
29eccc7c 677 if ( 1 )
fc318ffe 678 {
679 LOCK(mempool.cs);
680 CCoinsViewMemPool view(pcoinsTip,mempool);
681 if ( view.GetCoins(txid,coins) == 0 )
682 return(-1);
683 mempool.pruneSpent(txid, coins); // TODO: this should be done by the CCoinsViewMemPool
684 } else if ( pcoinsTip->GetCoins(txid,coins) == 0 )
685 return(-1);
686 if ( n < 0 || (unsigned int)n >= coins.vout.size() || coins.vout[n].IsNull() )
687 return(-1);
688 ptr = (uint8_t *)coins.vout[n].scriptPubKey.data();
689 m = coins.vout[n].scriptPubKey.size();
690 for (i=0; i<maxsize&&i<m; i++)
691 scriptPubKey[i] = ptr[i];
692 return(i);
693}
694
f5906533
JG
695Value verifychain(const Array& params, bool fHelp)
696{
697 if (fHelp || params.size() > 2)
698 throw runtime_error(
a6099ef3 699 "verifychain ( checklevel numblocks )\n"
700 "\nVerifies blockchain database.\n"
701 "\nArguments:\n"
6943cb9b
PK
702 "1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is.\n"
703 "2. numblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n"
a6099ef3 704 "\nResult:\n"
705 "true|false (boolean) Verified or not\n"
706 "\nExamples:\n"
707 + HelpExampleCli("verifychain", "")
708 + HelpExampleRpc("verifychain", "")
709 );
f5906533 710
4401b2d7
EL
711 LOCK(cs_main);
712
f5906533
JG
713 int nCheckLevel = GetArg("-checklevel", 3);
714 int nCheckDepth = GetArg("-checkblocks", 288);
715 if (params.size() > 0)
716 nCheckLevel = params[0].get_int();
717 if (params.size() > 1)
718 nCheckDepth = params[1].get_int();
719
2e280311 720 return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth);
f5906533 721}
c625ae04 722
ba1da90b
WL
723/** Implementation of IsSuperMajority with better feedback */
724Object SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams)
725{
726 int nFound = 0;
727 CBlockIndex* pstart = pindex;
728 for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++)
729 {
730 if (pstart->nVersion >= minVersion)
731 ++nFound;
732 pstart = pstart->pprev;
733 }
734
735 Object rv;
736 rv.push_back(Pair("status", nFound >= nRequired));
737 rv.push_back(Pair("found", nFound));
738 rv.push_back(Pair("required", nRequired));
739 rv.push_back(Pair("window", consensusParams.nMajorityWindow));
740 return rv;
741}
742
743Object SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
744{
745 Object rv;
746 rv.push_back(Pair("id", name));
747 rv.push_back(Pair("version", version));
748 rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)));
749 rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams)));
750 return rv;
751}
752
d387b8ec
WL
753Value getblockchaininfo(const Array& params, bool fHelp)
754{
755 if (fHelp || params.size() != 0)
756 throw runtime_error(
757 "getblockchaininfo\n"
758 "Returns an object containing various state info regarding block chain processing.\n"
759 "\nResult:\n"
760 "{\n"
f6984e81 761 " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
d387b8ec 762 " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
ad6e6017 763 " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
d387b8ec
WL
764 " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
765 " \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
766 " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
767 " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
ba1da90b
WL
768 " \"softforks\": [ (array) status of softforks in progress\n"
769 " {\n"
770 " \"id\": \"xxxx\", (string) name of softfork\n"
771 " \"version\": xx, (numeric) block version\n"
772 " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n"
773 " \"status\": xx, (boolean) true if threshold reached\n"
774 " \"found\": xx, (numeric) number of blocks with the new version found\n"
775 " \"required\": xx, (numeric) number of blocks required to trigger\n"
776 " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n"
777 " },\n"
778 " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
779 " }, ...\n"
780 " ]\n"
d387b8ec
WL
781 "}\n"
782 "\nExamples:\n"
783 + HelpExampleCli("getblockchaininfo", "")
784 + HelpExampleRpc("getblockchaininfo", "")
785 );
786
4401b2d7
EL
787 LOCK(cs_main);
788
d387b8ec 789 Object obj;
f5ae6c98
PK
790 obj.push_back(Pair("chain", Params().NetworkIDString()));
791 obj.push_back(Pair("blocks", (int)chainActive.Height()));
ad6e6017 792 obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
f5ae6c98 793 obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex()));
695a7a88 794 obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty()));
11982d36 795 obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip())));
f5ae6c98 796 obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
1b2e5555 797 obj.push_back(Pair("pruned", fPruneMode));
ba1da90b
WL
798
799 const Consensus::Params& consensusParams = Params().GetConsensus();
800 CBlockIndex* tip = chainActive.Tip();
801 Array softforks;
802 softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
803 softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
6af25b0f 804 softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams));
ba1da90b
WL
805 obj.push_back(Pair("softforks", softforks));
806
1b2e5555
JS
807 if (fPruneMode)
808 {
809 CBlockIndex *block = chainActive.Tip();
810 while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA))
811 block = block->pprev;
812
813 obj.push_back(Pair("pruneheight", block->nHeight));
814 }
d387b8ec
WL
815 return obj;
816}
b33bd7a3 817
72fb3d29 818/** Comparison function for sorting the getchaintips heads. */
b33bd7a3
DK
819struct CompareBlocksByHeight
820{
821 bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
822 {
823 /* Make sure that unequal blocks with the same height do not compare
771d5002 824 equal. Use the pointers themselves to make a distinction. */
b33bd7a3
DK
825
826 if (a->nHeight != b->nHeight)
827 return (a->nHeight > b->nHeight);
828
829 return a < b;
830 }
831};
832
833Value getchaintips(const Array& params, bool fHelp)
834{
835 if (fHelp || params.size() != 0)
836 throw runtime_error(
837 "getchaintips\n"
838 "Return information about all known tips in the block tree,"
839 " including the main chain as well as orphaned branches.\n"
840 "\nResult:\n"
841 "[\n"
842 " {\n"
843 " \"height\": xxxx, (numeric) height of the chain tip\n"
844 " \"hash\": \"xxxx\", (string) block hash of the tip\n"
845 " \"branchlen\": 0 (numeric) zero for main chain\n"
1b91be49 846 " \"status\": \"active\" (string) \"active\" for the main chain\n"
b33bd7a3
DK
847 " },\n"
848 " {\n"
849 " \"height\": xxxx,\n"
850 " \"hash\": \"xxxx\",\n"
851 " \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
1b91be49 852 " \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
b33bd7a3
DK
853 " }\n"
854 "]\n"
32b93a1b
PW
855 "Possible values for status:\n"
856 "1. \"invalid\" This branch contains at least one invalid block\n"
857 "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n"
858 "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n"
859 "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n"
860 "5. \"active\" This is the tip of the active main chain, which is certainly valid\n"
b33bd7a3
DK
861 "\nExamples:\n"
862 + HelpExampleCli("getchaintips", "")
863 + HelpExampleRpc("getchaintips", "")
864 );
865
4401b2d7
EL
866 LOCK(cs_main);
867
b33bd7a3
DK
868 /* Build up a list of chain tips. We start with the list of all
869 known blocks, and successively remove blocks that appear as pprev
870 of another block. */
871 std::set<const CBlockIndex*, CompareBlocksByHeight> setTips;
872 BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
873 setTips.insert(item.second);
874 BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
875 {
876 const CBlockIndex* pprev = item.second->pprev;
877 if (pprev)
878 setTips.erase(pprev);
879 }
880
1b91be49
PW
881 // Always report the currently active tip.
882 setTips.insert(chainActive.Tip());
883
b33bd7a3
DK
884 /* Construct the output array. */
885 Array res;
886 BOOST_FOREACH(const CBlockIndex* block, setTips)
887 {
888 Object obj;
889 obj.push_back(Pair("height", block->nHeight));
890 obj.push_back(Pair("hash", block->phashBlock->GetHex()));
891
892 const int branchLen = block->nHeight - chainActive.FindFork(block)->nHeight;
893 obj.push_back(Pair("branchlen", branchLen));
894
1b91be49
PW
895 string status;
896 if (chainActive.Contains(block)) {
897 // This block is part of the currently active chain.
898 status = "active";
899 } else if (block->nStatus & BLOCK_FAILED_MASK) {
900 // This block or one of its ancestors is invalid.
901 status = "invalid";
902 } else if (block->nChainTx == 0) {
903 // This block cannot be connected because full block data for it or one of its parents is missing.
904 status = "headers-only";
905 } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) {
906 // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized.
907 status = "valid-fork";
908 } else if (block->IsValid(BLOCK_VALID_TREE)) {
909 // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain.
910 status = "valid-headers";
911 } else {
912 // No clue.
913 status = "unknown";
914 }
915 obj.push_back(Pair("status", status));
916
b33bd7a3
DK
917 res.push_back(obj);
918 }
919
920 return res;
921}
6f2c26a4
JG
922
923Value getmempoolinfo(const Array& params, bool fHelp)
924{
925 if (fHelp || params.size() != 0)
926 throw runtime_error(
927 "getmempoolinfo\n"
928 "\nReturns details on the active state of the TX memory pool.\n"
929 "\nResult:\n"
930 "{\n"
931 " \"size\": xxxxx (numeric) Current tx count\n"
932 " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n"
933 "}\n"
934 "\nExamples:\n"
935 + HelpExampleCli("getmempoolinfo", "")
936 + HelpExampleRpc("getmempoolinfo", "")
937 );
938
939 Object ret;
940 ret.push_back(Pair("size", (int64_t) mempool.size()));
941 ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
942
943 return ret;
944}
945
9b0a8d31
PW
946Value invalidateblock(const Array& params, bool fHelp)
947{
948 if (fHelp || params.size() != 1)
949 throw runtime_error(
950 "invalidateblock \"hash\"\n"
951 "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n"
952 "\nArguments:\n"
953 "1. hash (string, required) the hash of the block to mark as invalid\n"
954 "\nResult:\n"
955 "\nExamples:\n"
956 + HelpExampleCli("invalidateblock", "\"blockhash\"")
957 + HelpExampleRpc("invalidateblock", "\"blockhash\"")
958 );
959
960 std::string strHash = params[0].get_str();
34cdc411 961 uint256 hash(uint256S(strHash));
9b0a8d31
PW
962 CValidationState state;
963
964 {
965 LOCK(cs_main);
966 if (mapBlockIndex.count(hash) == 0)
967 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
968
969 CBlockIndex* pblockindex = mapBlockIndex[hash];
970 InvalidateBlock(state, pblockindex);
971 }
972
973 if (state.IsValid()) {
974 ActivateBestChain(state);
975 }
976
977 if (!state.IsValid()) {
978 throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
979 }
980
981 return Value::null;
982}
983
984Value reconsiderblock(const Array& params, bool fHelp)
985{
986 if (fHelp || params.size() != 1)
987 throw runtime_error(
988 "reconsiderblock \"hash\"\n"
989 "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n"
990 "This can be used to undo the effects of invalidateblock.\n"
991 "\nArguments:\n"
992 "1. hash (string, required) the hash of the block to reconsider\n"
993 "\nResult:\n"
994 "\nExamples:\n"
995 + HelpExampleCli("reconsiderblock", "\"blockhash\"")
996 + HelpExampleRpc("reconsiderblock", "\"blockhash\"")
997 );
998
999 std::string strHash = params[0].get_str();
34cdc411 1000 uint256 hash(uint256S(strHash));
9b0a8d31
PW
1001 CValidationState state;
1002
1003 {
1004 LOCK(cs_main);
1005 if (mapBlockIndex.count(hash) == 0)
1006 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1007
1008 CBlockIndex* pblockindex = mapBlockIndex[hash];
1009 ReconsiderBlock(state, pblockindex);
1010 }
1011
1012 if (state.IsValid()) {
1013 ActivateBestChain(state);
1014 }
1015
1016 if (!state.IsValid()) {
1017 throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
1018 }
1019
1020 return Value::null;
1021}
This page took 0.448471 seconds and 4 git commands to generate.