]>
Commit | Line | Data |
---|---|---|
7600e7fc | 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 |
7600e7fc JG |
4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
5 | ||
eda37330 | 6 | #include "amount.h" |
0e4b3175 | 7 | #include "chainparams.h" |
691161d4 | 8 | #include "consensus/consensus.h" |
da29ecbc | 9 | #include "consensus/validation.h" |
611116d4 | 10 | #include "core_io.h" |
8e8b6d70 | 11 | #ifdef ENABLE_MINING |
fdda3c50 | 12 | #include "crypto/equihash.h" |
8e8b6d70 | 13 | #endif |
7600e7fc | 14 | #include "init.h" |
51ed9ec9 | 15 | #include "main.h" |
a6df7ab5 | 16 | #include "metrics.h" |
d247a5d1 | 17 | #include "miner.h" |
691161d4 | 18 | #include "net.h" |
df852d2b | 19 | #include "pow.h" |
611116d4 | 20 | #include "rpcserver.h" |
ad49c256 | 21 | #include "util.h" |
cbb2cf55 | 22 | #include "validationinterface.h" |
df840de5 | 23 | #ifdef ENABLE_WALLET |
50c72f23 | 24 | #include "wallet/wallet.h" |
df840de5 | 25 | #endif |
ac14bcc1 | 26 | |
51ed9ec9 BD |
27 | #include <stdint.h> |
28 | ||
171ca774 | 29 | #include <boost/assign/list_of.hpp> |
ac14bcc1 | 30 | |
a10a6e2a | 31 | #include <univalue.h> |
7600e7fc | 32 | |
7600e7fc JG |
33 | using namespace std; |
34 | ||
16593898 | 35 | |
72fb3d29 MF |
36 | /** |
37 | * Return average network hashes per second based on the last 'lookup' blocks, | |
f2c48e15 | 38 | * or over the difficulty averaging window if 'lookup' is nonpositive. |
72fb3d29 MF |
39 | * If 'height' is nonnegative, compute the estimate at the time when a given block was found. |
40 | */ | |
eb5b582e | 41 | int64_t GetNetworkHashPS(int lookup, int height) { |
aec55a07 GM |
42 | CBlockIndex *pb = chainActive.Tip(); |
43 | ||
44 | if (height >= 0 && height < chainActive.Height()) | |
45 | pb = chainActive[height]; | |
d64eef48 | 46 | |
47 | if (pb == NULL || !pb->nHeight) | |
48 | return 0; | |
49 | ||
5e207f4e | 50 | // If lookup is nonpositive, then use difficulty averaging window. |
d64eef48 | 51 | if (lookup <= 0) |
cdec0b92 | 52 | lookup = Params().GetConsensus().nPowAveragingWindow; |
f2c48e15 | 53 | |
cdec0b92 JG |
54 | // If lookup is larger than chain, then set it to chain length. |
55 | if (lookup > pb->nHeight) | |
d64eef48 | 56 | lookup = pb->nHeight; |
57 | ||
58 | CBlockIndex *pb0 = pb; | |
51ed9ec9 BD |
59 | int64_t minTime = pb0->GetBlockTime(); |
60 | int64_t maxTime = minTime; | |
d64eef48 | 61 | for (int i = 0; i < lookup; i++) { |
62 | pb0 = pb0->pprev; | |
51ed9ec9 | 63 | int64_t time = pb0->GetBlockTime(); |
d64eef48 | 64 | minTime = std::min(time, minTime); |
65 | maxTime = std::max(time, maxTime); | |
66 | } | |
67 | ||
68 | // In case there's a situation where minTime == maxTime, we don't want a divide by zero exception. | |
69 | if (minTime == maxTime) | |
70 | return 0; | |
71 | ||
734f85c4 | 72 | arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork; |
51ed9ec9 | 73 | int64_t timeDiff = maxTime - minTime; |
d64eef48 | 74 | |
4b61a6a4 | 75 | return (int64_t)(workDiff.getdouble() / timeDiff); |
d64eef48 | 76 | } |
77 | ||
0d37ae3a | 78 | UniValue getlocalsolps(const UniValue& params, bool fHelp) |
000499ae JG |
79 | { |
80 | if (fHelp) | |
81 | throw runtime_error( | |
82 | "getlocalsolps\n" | |
83 | "\nReturns the average local solutions per second since this node was started.\n" | |
84 | "This is the same information shown on the metrics screen (if enabled).\n" | |
85 | "\nResult:\n" | |
86 | "xxx.xxxxx (numeric) Solutions per second average\n" | |
87 | "\nExamples:\n" | |
88 | + HelpExampleCli("getlocalsolps", "") | |
89 | + HelpExampleRpc("getlocalsolps", "") | |
90 | ); | |
91 | ||
92 | LOCK(cs_main); | |
93 | return GetLocalSolPS(); | |
94 | } | |
95 | ||
0d37ae3a | 96 | UniValue getnetworksolps(const UniValue& params, bool fHelp) |
000499ae JG |
97 | { |
98 | if (fHelp || params.size() > 2) | |
99 | throw runtime_error( | |
100 | "getnetworksolps ( blocks height )\n" | |
101 | "\nReturns the estimated network solutions per second based on the last n blocks.\n" | |
102 | "Pass in [blocks] to override # of blocks, -1 specifies over difficulty averaging window.\n" | |
103 | "Pass in [height] to estimate the network speed at the time when a certain block was found.\n" | |
104 | "\nArguments:\n" | |
105 | "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks over difficulty averaging window.\n" | |
106 | "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" | |
107 | "\nResult:\n" | |
108 | "x (numeric) Solutions per second estimated\n" | |
109 | "\nExamples:\n" | |
110 | + HelpExampleCli("getnetworksolps", "") | |
111 | + HelpExampleRpc("getnetworksolps", "") | |
112 | ); | |
113 | ||
114 | LOCK(cs_main); | |
115 | return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); | |
116 | } | |
117 | ||
d014114d | 118 | UniValue getnetworkhashps(const UniValue& params, bool fHelp) |
d64eef48 | 119 | { |
120 | if (fHelp || params.size() > 2) | |
121 | throw runtime_error( | |
a6099ef3 | 122 | "getnetworkhashps ( blocks height )\n" |
000499ae JG |
123 | "\nDEPRECATED - left for backwards-compatibility. Use getnetworksolps instead.\n" |
124 | "\nReturns the estimated network solutions per second based on the last n blocks.\n" | |
f2c48e15 | 125 | "Pass in [blocks] to override # of blocks, -1 specifies over difficulty averaging window.\n" |
a6099ef3 | 126 | "Pass in [height] to estimate the network speed at the time when a certain block was found.\n" |
127 | "\nArguments:\n" | |
f2c48e15 | 128 | "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks over difficulty averaging window.\n" |
a6099ef3 | 129 | "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" |
130 | "\nResult:\n" | |
000499ae | 131 | "x (numeric) Solutions per second estimated\n" |
a6099ef3 | 132 | "\nExamples:\n" |
133 | + HelpExampleCli("getnetworkhashps", "") | |
134 | + HelpExampleRpc("getnetworkhashps", "") | |
135 | ); | |
d64eef48 | 136 | |
4401b2d7 | 137 | LOCK(cs_main); |
d64eef48 | 138 | return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); |
139 | } | |
140 | ||
8e8b6d70 | 141 | #ifdef ENABLE_MINING |
d014114d | 142 | UniValue getgenerate(const UniValue& params, bool fHelp) |
7600e7fc JG |
143 | { |
144 | if (fHelp || params.size() != 0) | |
145 | throw runtime_error( | |
146 | "getgenerate\n" | |
a6099ef3 | 147 | "\nReturn if the server is set to generate coins or not. The default is false.\n" |
5166804f | 148 | "It is set with the command line argument -gen (or komodo.conf setting gen)\n" |
a6099ef3 | 149 | "It can also be set with the setgenerate call.\n" |
150 | "\nResult\n" | |
151 | "true|false (boolean) If the server is set to generate coins or not\n" | |
152 | "\nExamples:\n" | |
153 | + HelpExampleCli("getgenerate", "") | |
154 | + HelpExampleRpc("getgenerate", "") | |
155 | ); | |
7600e7fc | 156 | |
4401b2d7 | 157 | LOCK(cs_main); |
3260b4c0 | 158 | return GetBoolArg("-gen", false); |
7600e7fc JG |
159 | } |
160 | ||
f2dd868d | 161 | extern uint8_t NOTARY_PUBKEY33[33]; |
8c3623fe | 162 | |
945f015d | 163 | //Value generate(const Array& params, bool fHelp) |
d014114d | 164 | UniValue generate(const UniValue& params, bool fHelp) |
6b04508e PW |
165 | { |
166 | if (fHelp || params.size() < 1 || params.size() > 1) | |
167 | throw runtime_error( | |
168 | "generate numblocks\n" | |
169 | "\nMine blocks immediately (before the RPC call returns)\n" | |
48265f3c | 170 | "\nNote: this function can only be used on the regtest network\n" |
a33cd5ba | 171 | "\nArguments:\n" |
6b04508e PW |
172 | "1. numblocks (numeric) How many blocks are generated immediately.\n" |
173 | "\nResult\n" | |
174 | "[ blockhashes ] (array) hashes of blocks generated\n" | |
175 | "\nExamples:\n" | |
176 | "\nGenerate 11 blocks\n" | |
177 | + HelpExampleCli("generate", "11") | |
178 | ); | |
179 | ||
8e8b6d70 JG |
180 | if (GetArg("-mineraddress", "").empty()) { |
181 | #ifdef ENABLE_WALLET | |
182 | if (!pwalletMain) { | |
183 | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Wallet disabled and -mineraddress not set"); | |
184 | } | |
185 | #else | |
a7322d77 | 186 | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "komodod compiled without wallet and -mineraddress not set"); |
8e8b6d70 JG |
187 | #endif |
188 | } | |
48265f3c WL |
189 | if (!Params().MineBlocksOnDemand()) |
190 | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); | |
6b04508e PW |
191 | |
192 | int nHeightStart = 0; | |
193 | int nHeightEnd = 0; | |
194 | int nHeight = 0; | |
195 | int nGenerate = params[0].get_int(); | |
8e8b6d70 | 196 | #ifdef ENABLE_WALLET |
48265f3c | 197 | CReserveKey reservekey(pwalletMain); |
8e8b6d70 | 198 | #endif |
6b04508e PW |
199 | |
200 | { // Don't keep cs_main locked | |
201 | LOCK(cs_main); | |
202 | nHeightStart = chainActive.Height(); | |
203 | nHeight = nHeightStart; | |
204 | nHeightEnd = nHeightStart+nGenerate; | |
205 | } | |
48265f3c | 206 | unsigned int nExtraNonce = 0; |
38fc4b70 | 207 | UniValue blockHashes(UniValue::VARR); |
e9574728 JG |
208 | unsigned int n = Params().EquihashN(); |
209 | unsigned int k = Params().EquihashK(); | |
a8acafb3 | 210 | uint64_t lastTime = 0; |
48265f3c WL |
211 | while (nHeight < nHeightEnd) |
212 | { | |
a8acafb3 SS |
213 | // Validation may fail if block generation is too fast |
214 | if (GetTime() == lastTime) MilliSleep(1001); | |
215 | lastTime = GetTime(); | |
216 | ||
8e8b6d70 | 217 | #ifdef ENABLE_WALLET |
16593898 | 218 | std::unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey,nHeight,KOMODO_MAXGPUCOUNT)); |
8e8b6d70 | 219 | #else |
08c58194 | 220 | std::unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey()); |
8e8b6d70 | 221 | #endif |
48265f3c | 222 | if (!pblocktemplate.get()) |
6b04508e | 223 | throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); |
48265f3c WL |
224 | CBlock *pblock = &pblocktemplate->block; |
225 | { | |
226 | LOCK(cs_main); | |
227 | IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); | |
228 | } | |
fdda3c50 JG |
229 | |
230 | // Hash state | |
231 | crypto_generichash_blake2b_state eh_state; | |
e9574728 | 232 | EhInitialiseState(n, k, eh_state); |
fdda3c50 JG |
233 | |
234 | // I = the block header minus nonce and solution. | |
235 | CEquihashInput I{*pblock}; | |
236 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
237 | ss << I; | |
238 | ||
239 | // H(I||... | |
240 | crypto_generichash_blake2b_update(&eh_state, (unsigned char*)&ss[0], ss.size()); | |
241 | ||
242 | while (true) { | |
48265f3c | 243 | // Yes, there is a chance every nonce could fail to satisfy the -regtest |
fdda3c50 JG |
244 | // target -- 1 in 2^(2^256). That ain't gonna happen |
245 | pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); | |
246 | ||
247 | // H(I||V||... | |
248 | crypto_generichash_blake2b_state curr_state; | |
249 | curr_state = eh_state; | |
250 | crypto_generichash_blake2b_update(&curr_state, | |
251 | pblock->nNonce.begin(), | |
252 | pblock->nNonce.size()); | |
253 | ||
254 | // (x_1, x_2, ...) = A(I, V, n, k) | |
5be6abbf | 255 | std::function<bool(std::vector<unsigned char>)> validBlock = |
50027f06 | 256 | [&pblock](std::vector<unsigned char> soln) |
257 | { | |
6830264a | 258 | LOCK(cs_main); |
fdda3c50 | 259 | pblock->nSolution = soln; |
e7d59bbc | 260 | solutionTargetChecks.increment(); |
4263420b | 261 | return CheckProofOfWork(chainActive.Height(),NOTARY_PUBKEY33,pblock->GetHash(), pblock->nBits, Params().GetConsensus(),pblock->nTime); |
51eb5273 | 262 | }; |
a6df7ab5 JG |
263 | bool found = EhBasicSolveUncancellable(n, k, curr_state, validBlock); |
264 | ehSolverRuns.increment(); | |
265 | if (found) { | |
51eb5273 | 266 | goto endloop; |
a6df7ab5 | 267 | } |
48265f3c | 268 | } |
fdda3c50 | 269 | endloop: |
48265f3c | 270 | CValidationState state; |
70c6301c | 271 | if (!ProcessNewBlock(1,chainActive.Tip()->nHeight+1,state, NULL, pblock, true, NULL)) |
48265f3c | 272 | throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); |
6b04508e | 273 | ++nHeight; |
48265f3c | 274 | blockHashes.push_back(pblock->GetHash().GetHex()); |
6b04508e PW |
275 | } |
276 | return blockHashes; | |
277 | } | |
7600e7fc | 278 | |
48265f3c | 279 | |
d014114d | 280 | UniValue setgenerate(const UniValue& params, bool fHelp) |
7600e7fc JG |
281 | { |
282 | if (fHelp || params.size() < 1 || params.size() > 2) | |
283 | throw runtime_error( | |
a6099ef3 | 284 | "setgenerate generate ( genproclimit )\n" |
285 | "\nSet 'generate' true or false to turn generation on or off.\n" | |
286 | "Generation is limited to 'genproclimit' processors, -1 is unlimited.\n" | |
287 | "See the getgenerate call for the current setting.\n" | |
288 | "\nArguments:\n" | |
289 | "1. generate (boolean, required) Set to true to turn on generation, off to turn off.\n" | |
290 | "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" | |
291 | "\nExamples:\n" | |
292 | "\nSet the generation on with a limit of one processor\n" | |
293 | + HelpExampleCli("setgenerate", "true 1") + | |
294 | "\nCheck the setting\n" | |
295 | + HelpExampleCli("getgenerate", "") + | |
296 | "\nTurn off generation\n" | |
297 | + HelpExampleCli("setgenerate", "false") + | |
298 | "\nUsing json rpc\n" | |
299 | + HelpExampleRpc("setgenerate", "true, 1") | |
300 | ); | |
7600e7fc | 301 | |
8e8b6d70 JG |
302 | if (GetArg("-mineraddress", "").empty()) { |
303 | #ifdef ENABLE_WALLET | |
304 | if (!pwalletMain) { | |
305 | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Wallet disabled and -mineraddress not set"); | |
306 | } | |
307 | #else | |
a7322d77 | 308 | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "komodod compiled without wallet and -mineraddress not set"); |
8e8b6d70 JG |
309 | #endif |
310 | } | |
27ce808f WL |
311 | if (Params().MineBlocksOnDemand()) |
312 | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); | |
c8b74258 | 313 | |
7600e7fc JG |
314 | bool fGenerate = true; |
315 | if (params.size() > 0) | |
316 | fGenerate = params[0].get_bool(); | |
317 | ||
c8b74258 | 318 | int nGenProcLimit = -1; |
7600e7fc JG |
319 | if (params.size() > 1) |
320 | { | |
c8b74258 | 321 | nGenProcLimit = params[1].get_int(); |
7600e7fc JG |
322 | if (nGenProcLimit == 0) |
323 | fGenerate = false; | |
324 | } | |
7600e7fc | 325 | |
6b04508e PW |
326 | mapArgs["-gen"] = (fGenerate ? "1" : "0"); |
327 | mapArgs ["-genproclimit"] = itostr(nGenProcLimit); | |
8e8b6d70 | 328 | #ifdef ENABLE_WALLET |
6b04508e | 329 | GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); |
8e8b6d70 JG |
330 | #else |
331 | GenerateBitcoins(fGenerate, nGenProcLimit); | |
332 | #endif | |
c8b74258 | 333 | |
ed21d5bd | 334 | return NullUniValue; |
7600e7fc | 335 | } |
4a85e067 | 336 | #endif |
7600e7fc JG |
337 | |
338 | ||
d014114d | 339 | UniValue getmininginfo(const UniValue& params, bool fHelp) |
7600e7fc JG |
340 | { |
341 | if (fHelp || params.size() != 0) | |
342 | throw runtime_error( | |
343 | "getmininginfo\n" | |
a6099ef3 | 344 | "\nReturns a json object containing mining-related information." |
345 | "\nResult:\n" | |
346 | "{\n" | |
347 | " \"blocks\": nnn, (numeric) The current block\n" | |
348 | " \"currentblocksize\": nnn, (numeric) The last block size\n" | |
349 | " \"currentblocktx\": nnn, (numeric) The last block transaction\n" | |
350 | " \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n" | |
351 | " \"errors\": \"...\" (string) Current errors\n" | |
352 | " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n" | |
353 | " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" | |
000499ae JG |
354 | " \"localsolps\": xxx.xxxxx (numeric) The average local solution rate in Sol/s since this node was started\n" |
355 | " \"networksolps\": x (numeric) The estimated network solution rate in Sol/s\n" | |
a6099ef3 | 356 | " \"pooledtx\": n (numeric) The size of the mem pool\n" |
357 | " \"testnet\": true|false (boolean) If using testnet or not\n" | |
f6984e81 | 358 | " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" |
a6099ef3 | 359 | "}\n" |
360 | "\nExamples:\n" | |
361 | + HelpExampleCli("getmininginfo", "") | |
362 | + HelpExampleRpc("getmininginfo", "") | |
363 | ); | |
7600e7fc | 364 | |
4401b2d7 EL |
365 | |
366 | LOCK(cs_main); | |
367 | ||
38fc4b70 | 368 | UniValue obj(UniValue::VOBJ); |
4c6d41b8 | 369 | obj.push_back(Pair("blocks", (int)chainActive.Height())); |
3260b4c0 PK |
370 | obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); |
371 | obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); | |
695a7a88 | 372 | obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty())); |
3260b4c0 | 373 | obj.push_back(Pair("errors", GetWarnings("statusbar"))); |
3260b4c0 | 374 | obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); |
000499ae JG |
375 | obj.push_back(Pair("localsolps" , getlocalsolps(params, false))); |
376 | obj.push_back(Pair("networksolps", getnetworksolps(params, false))); | |
377 | obj.push_back(Pair("networkhashps", getnetworksolps(params, false))); | |
3260b4c0 | 378 | obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); |
cc972107 | 379 | obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); |
f6984e81 | 380 | obj.push_back(Pair("chain", Params().NetworkIDString())); |
8e8b6d70 | 381 | #ifdef ENABLE_MINING |
4a85e067 | 382 | obj.push_back(Pair("generate", getgenerate(params, false))); |
4a85e067 | 383 | #endif |
7600e7fc JG |
384 | return obj; |
385 | } | |
386 | ||
387 | ||
8a20cd3c | 388 | // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts |
d014114d | 389 | UniValue prioritisetransaction(const UniValue& params, bool fHelp) |
2a72d459 LD |
390 | { |
391 | if (fHelp || params.size() != 3) | |
392 | throw runtime_error( | |
393 | "prioritisetransaction <txid> <priority delta> <fee delta>\n" | |
ebdcc360 CL |
394 | "Accepts the transaction into mined blocks at a higher (or lower) priority\n" |
395 | "\nArguments:\n" | |
396 | "1. \"txid\" (string, required) The transaction id.\n" | |
397 | "2. priority delta (numeric, required) The priority to add or subtract.\n" | |
398 | " The transaction selection algorithm considers the tx as it would have a higher priority.\n" | |
399 | " (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n" | |
8a20cd3c | 400 | "3. fee delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n" |
ebdcc360 CL |
401 | " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" |
402 | " considers the transaction as it would have paid a higher (or lower) fee.\n" | |
403 | "\nResult\n" | |
404 | "true (boolean) Returns true\n" | |
405 | "\nExamples:\n" | |
8a20cd3c LD |
406 | + HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") |
407 | + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000") | |
ebdcc360 | 408 | ); |
2a72d459 | 409 | |
4401b2d7 | 410 | LOCK(cs_main); |
ebdcc360 | 411 | |
4401b2d7 | 412 | uint256 hash = ParseHashStr(params[0].get_str(), "txid"); |
8a20cd3c | 413 | CAmount nAmount = params[2].get_int64(); |
ebdcc360 CL |
414 | |
415 | mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount); | |
2a72d459 LD |
416 | return true; |
417 | } | |
418 | ||
419 | ||
3dcbb9b6 | 420 | // NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller |
851f58f9 | 421 | static UniValue BIP22ValidationResult(const CValidationState& state) |
3dcbb9b6 LD |
422 | { |
423 | if (state.IsValid()) | |
d014114d | 424 | return NullUniValue; |
3dcbb9b6 LD |
425 | |
426 | std::string strRejectReason = state.GetRejectReason(); | |
427 | if (state.IsError()) | |
428 | throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason); | |
429 | if (state.IsInvalid()) | |
430 | { | |
431 | if (strRejectReason.empty()) | |
432 | return "rejected"; | |
433 | return strRejectReason; | |
434 | } | |
435 | // Should be impossible | |
436 | return "valid?"; | |
437 | } | |
438 | ||
d014114d | 439 | UniValue getblocktemplate(const UniValue& params, bool fHelp) |
7600e7fc | 440 | { |
3beac983 | 441 | if (fHelp || params.size() > 1) |
7600e7fc | 442 | throw runtime_error( |
a6099ef3 | 443 | "getblocktemplate ( \"jsonrequestobject\" )\n" |
444 | "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" | |
445 | "It returns data needed to construct a block to work on.\n" | |
446 | "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" | |
447 | ||
448 | "\nArguments:\n" | |
449 | "1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n" | |
450 | " {\n" | |
451 | " \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n" | |
452 | " \"capabilities\":[ (array, optional) A list of strings\n" | |
453 | " \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n" | |
454 | " ,...\n" | |
455 | " ]\n" | |
456 | " }\n" | |
457 | "\n" | |
458 | ||
459 | "\nResult:\n" | |
460 | "{\n" | |
461 | " \"version\" : n, (numeric) The block version\n" | |
462 | " \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n" | |
463 | " \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n" | |
464 | " {\n" | |
465 | " \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n" | |
466 | " \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n" | |
467 | " \"depends\" : [ (array) array of numbers \n" | |
468 | " n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n" | |
469 | " ,...\n" | |
470 | " ],\n" | |
471 | " \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in Satoshis); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n" | |
472 | " \"sigops\" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n" | |
473 | " \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n" | |
474 | " }\n" | |
475 | " ,...\n" | |
476 | " ],\n" | |
53ddbaed JG |
477 | // " \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n" |
478 | // " \"flags\" : \"flags\" (string) \n" | |
479 | // " },\n" | |
480 | // " \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in Satoshis)\n" | |
a6099ef3 | 481 | " \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n" |
482 | " \"target\" : \"xxxx\", (string) The hash target\n" | |
483 | " \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n" | |
484 | " \"mutable\" : [ (array of string) list of ways the block template may be changed \n" | |
485 | " \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n" | |
486 | " ,...\n" | |
487 | " ],\n" | |
488 | " \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n" | |
489 | " \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n" | |
490 | " \"sizelimit\" : n, (numeric) limit of block size\n" | |
491 | " \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n" | |
492 | " \"bits\" : \"xxx\", (string) compressed target of next block\n" | |
493 | " \"height\" : n (numeric) The height of the next block\n" | |
494 | "}\n" | |
495 | ||
496 | "\nExamples:\n" | |
497 | + HelpExampleCli("getblocktemplate", "") | |
498 | + HelpExampleRpc("getblocktemplate", "") | |
499 | ); | |
7600e7fc | 500 | |
4401b2d7 EL |
501 | LOCK(cs_main); |
502 | ||
8e8b6d70 JG |
503 | // Wallet or miner address is required because we support coinbasetxn |
504 | if (GetArg("-mineraddress", "").empty()) { | |
2cc0a252 | 505 | #ifdef ENABLE_WALLET |
8e8b6d70 JG |
506 | if (!pwalletMain) { |
507 | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Wallet disabled and -mineraddress not set"); | |
508 | } | |
509 | #else | |
a7322d77 | 510 | throw JSONRPCError(RPC_METHOD_NOT_FOUND, "komodod compiled without wallet and -mineraddress not set"); |
8e8b6d70 | 511 | #endif |
53ddbaed JG |
512 | } |
513 | ||
7600e7fc | 514 | std::string strMode = "template"; |
851f58f9 | 515 | UniValue lpval = NullUniValue; |
53ddbaed JG |
516 | // TODO: Re-enable coinbasevalue once a specification has been written |
517 | bool coinbasetxn = true; | |
7600e7fc JG |
518 | if (params.size() > 0) |
519 | { | |
d014114d JS |
520 | const UniValue& oparam = params[0].get_obj(); |
521 | const UniValue& modeval = find_value(oparam, "mode"); | |
ed21d5bd | 522 | if (modeval.isStr()) |
7600e7fc | 523 | strMode = modeval.get_str(); |
ed21d5bd | 524 | else if (modeval.isNull()) |
0689a7eb LD |
525 | { |
526 | /* Do nothing */ | |
527 | } | |
7600e7fc | 528 | else |
738835d7 | 529 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); |
ff6a7af1 | 530 | lpval = find_value(oparam, "longpollid"); |
9765a50c LD |
531 | |
532 | if (strMode == "proposal") | |
533 | { | |
d014114d | 534 | const UniValue& dataval = find_value(oparam, "data"); |
f70084cf | 535 | if (!dataval.isStr()) |
9765a50c LD |
536 | throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); |
537 | ||
538 | CBlock block; | |
539 | if (!DecodeHexBlk(block, dataval.get_str())) | |
540 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); | |
541 | ||
542 | uint256 hash = block.GetHash(); | |
543 | BlockMap::iterator mi = mapBlockIndex.find(hash); | |
544 | if (mi != mapBlockIndex.end()) { | |
545 | CBlockIndex *pindex = mi->second; | |
546 | if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) | |
547 | return "duplicate"; | |
548 | if (pindex->nStatus & BLOCK_FAILED_MASK) | |
549 | return "duplicate-invalid"; | |
550 | return "duplicate-inconclusive"; | |
551 | } | |
552 | ||
553 | CBlockIndex* const pindexPrev = chainActive.Tip(); | |
554 | // TestBlockValidity only supports blocks built on the current Tip | |
555 | if (block.hashPrevBlock != pindexPrev->GetBlockHash()) | |
556 | return "inconclusive-not-best-prevblk"; | |
557 | CValidationState state; | |
558 | TestBlockValidity(state, block, pindexPrev, false, true); | |
559 | return BIP22ValidationResult(state); | |
560 | } | |
7600e7fc JG |
561 | } |
562 | ||
563 | if (strMode != "template") | |
738835d7 | 564 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode"); |
7600e7fc JG |
565 | |
566 | if (vNodes.empty()) | |
a7322d77 | 567 | throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Komodo is not connected!"); |
7600e7fc | 568 | |
269fe243 | 569 | //if (IsInitialBlockDownload()) |
570 | // throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Zcash is downloading blocks..."); | |
7600e7fc | 571 | |
7600e7fc | 572 | static unsigned int nTransactionsUpdatedLast; |
ff6a7af1 | 573 | |
ed21d5bd | 574 | if (!lpval.isNull()) |
ff6a7af1 LD |
575 | { |
576 | // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions | |
577 | uint256 hashWatchedChain; | |
578 | boost::system_time checktxtime; | |
579 | unsigned int nTransactionsUpdatedLastLP; | |
580 | ||
ed21d5bd | 581 | if (lpval.isStr()) |
ff6a7af1 LD |
582 | { |
583 | // Format: <hashBestChain><nTransactionsUpdatedLast> | |
584 | std::string lpstr = lpval.get_str(); | |
585 | ||
586 | hashWatchedChain.SetHex(lpstr.substr(0, 64)); | |
587 | nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64)); | |
588 | } | |
589 | else | |
590 | { | |
591 | // NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier | |
592 | hashWatchedChain = chainActive.Tip()->GetBlockHash(); | |
593 | nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; | |
594 | } | |
595 | ||
596 | // Release the wallet and main lock while waiting | |
ff6a7af1 LD |
597 | LEAVE_CRITICAL_SECTION(cs_main); |
598 | { | |
599 | checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); | |
600 | ||
601 | boost::unique_lock<boost::mutex> lock(csBestBlock); | |
602 | while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) | |
603 | { | |
604 | if (!cvBlockChange.timed_wait(lock, checktxtime)) | |
605 | { | |
606 | // Timeout: Check transactions for update | |
607 | if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) | |
608 | break; | |
609 | checktxtime += boost::posix_time::seconds(10); | |
610 | } | |
611 | } | |
612 | } | |
613 | ENTER_CRITICAL_SECTION(cs_main); | |
ff6a7af1 LD |
614 | |
615 | if (!IsRPCRunning()) | |
616 | throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); | |
617 | // TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners? | |
618 | } | |
619 | ||
620 | // Update block | |
7600e7fc | 621 | static CBlockIndex* pindexPrev; |
51ed9ec9 | 622 | static int64_t nStart; |
03cac0bb | 623 | static CBlockTemplate* pblocktemplate; |
4c6d41b8 | 624 | if (pindexPrev != chainActive.Tip() || |
319b1160 | 625 | (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) |
7600e7fc JG |
626 | { |
627 | // Clear pindexPrev so future calls make a new block, despite any failures from here on | |
628 | pindexPrev = NULL; | |
629 | ||
53ddbaed | 630 | // Store the pindexBest used before CreateNewBlockWithKey, to avoid races |
319b1160 | 631 | nTransactionsUpdatedLast = mempool.GetTransactionsUpdated(); |
48265f3c | 632 | CBlockIndex* pindexPrevNew = chainActive.Tip(); |
7600e7fc JG |
633 | nStart = GetTime(); |
634 | ||
635 | // Create new block | |
03cac0bb | 636 | if(pblocktemplate) |
7600e7fc | 637 | { |
03cac0bb FV |
638 | delete pblocktemplate; |
639 | pblocktemplate = NULL; | |
7600e7fc | 640 | } |
8e8b6d70 | 641 | #ifdef ENABLE_WALLET |
53ddbaed | 642 | CReserveKey reservekey(pwalletMain); |
16593898 | 643 | pblocktemplate = CreateNewBlockWithKey(reservekey,chainActive.Tip()->nHeight+1,KOMODO_MAXGPUCOUNT); |
8e8b6d70 JG |
644 | #else |
645 | pblocktemplate = CreateNewBlockWithKey(); | |
646 | #endif | |
03cac0bb | 647 | if (!pblocktemplate) |
738835d7 | 648 | throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); |
7600e7fc | 649 | |
53ddbaed | 650 | // Need to update only after we know CreateNewBlockWithKey succeeded |
7600e7fc JG |
651 | pindexPrev = pindexPrevNew; |
652 | } | |
03cac0bb | 653 | CBlock* pblock = &pblocktemplate->block; // pointer for convenience |
7600e7fc JG |
654 | |
655 | // Update nTime | |
bebe7282 | 656 | UpdateTime(pblock, Params().GetConsensus(), pindexPrev); |
fdda3c50 | 657 | pblock->nNonce = uint256(); |
7600e7fc | 658 | |
38fc4b70 | 659 | UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); |
9765a50c | 660 | |
0d37ae3a | 661 | UniValue txCoinbase = NullUniValue; |
38fc4b70 | 662 | UniValue transactions(UniValue::VARR); |
7600e7fc JG |
663 | map<uint256, int64_t> setTxIndex; |
664 | int i = 0; | |
db954a65 | 665 | BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { |
805344dc | 666 | uint256 txHash = tx.GetHash(); |
7600e7fc JG |
667 | setTxIndex[txHash] = i++; |
668 | ||
53ddbaed | 669 | if (tx.IsCoinBase() && !coinbasetxn) |
7600e7fc JG |
670 | continue; |
671 | ||
38fc4b70 | 672 | UniValue entry(UniValue::VOBJ); |
7600e7fc | 673 | |
ae775b5b | 674 | entry.push_back(Pair("data", EncodeHexTx(tx))); |
7600e7fc JG |
675 | |
676 | entry.push_back(Pair("hash", txHash.GetHex())); | |
677 | ||
38fc4b70 | 678 | UniValue deps(UniValue::VARR); |
450cbb09 | 679 | BOOST_FOREACH (const CTxIn &in, tx.vin) |
7600e7fc | 680 | { |
450cbb09 PW |
681 | if (setTxIndex.count(in.prevout.hash)) |
682 | deps.push_back(setTxIndex[in.prevout.hash]); | |
683 | } | |
684 | entry.push_back(Pair("depends", deps)); | |
7600e7fc | 685 | |
ba1d0800 | 686 | int index_in_template = i - 1; |
f3d872d1 FV |
687 | entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template])); |
688 | entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template])); | |
7600e7fc | 689 | |
408a4d91 | 690 | if (tx.IsCoinBase()) { |
89aa746c | 691 | // Show founders' reward if it is required |
408a4d91 | 692 | //if (pblock->vtx[0].vout.size() > 1) { |
89aa746c | 693 | // Correct this if GetBlockTemplate changes the order |
408a4d91 | 694 | // entry.push_back(Pair("foundersreward", (int64_t)tx.vout[1].nValue)); |
695 | //} | |
9be15e1c | 696 | CAmount nReward = GetBlockSubsidy(chainActive.Tip()->nHeight+1, Params().GetConsensus()); |
697 | entry.push_back(Pair("coinbasevalue", nReward)); | |
53ddbaed JG |
698 | entry.push_back(Pair("required", true)); |
699 | txCoinbase = entry; | |
408a4d91 | 700 | } else |
53ddbaed | 701 | transactions.push_back(entry); |
7600e7fc JG |
702 | } |
703 | ||
38fc4b70 | 704 | UniValue aux(UniValue::VOBJ); |
7600e7fc JG |
705 | aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); |
706 | ||
734f85c4 | 707 | arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); |
7600e7fc | 708 | |
38fc4b70 | 709 | static UniValue aMutable(UniValue::VARR); |
7600e7fc JG |
710 | if (aMutable.empty()) |
711 | { | |
712 | aMutable.push_back("time"); | |
713 | aMutable.push_back("transactions"); | |
714 | aMutable.push_back("prevblock"); | |
715 | } | |
716 | ||
38fc4b70 | 717 | UniValue result(UniValue::VOBJ); |
9765a50c | 718 | result.push_back(Pair("capabilities", aCaps)); |
7600e7fc JG |
719 | result.push_back(Pair("version", pblock->nVersion)); |
720 | result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); | |
721 | result.push_back(Pair("transactions", transactions)); | |
53ddbaed | 722 | if (coinbasetxn) { |
0d37ae3a | 723 | assert(txCoinbase.isObject()); |
53ddbaed JG |
724 | result.push_back(Pair("coinbasetxn", txCoinbase)); |
725 | } else { | |
726 | result.push_back(Pair("coinbaseaux", aux)); | |
727 | result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); | |
728 | } | |
ff6a7af1 | 729 | result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); |
7600e7fc JG |
730 | result.push_back(Pair("target", hashTarget.GetHex())); |
731 | result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); | |
732 | result.push_back(Pair("mutable", aMutable)); | |
733 | result.push_back(Pair("noncerange", "00000000ffffffff")); | |
734 | result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); | |
735 | result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE)); | |
209377a7 | 736 | result.push_back(Pair("curtime", pblock->GetBlockTime())); |
645d497a | 737 | result.push_back(Pair("bits", strprintf("%08x", pblock->nBits))); |
7600e7fc | 738 | result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1))); |
c837f4bf | 739 | |
e317db75 | 740 | //fprintf(stderr,"return complete template\n"); |
7600e7fc JG |
741 | return result; |
742 | } | |
743 | ||
f877aaaf LD |
744 | class submitblock_StateCatcher : public CValidationInterface |
745 | { | |
746 | public: | |
747 | uint256 hash; | |
748 | bool found; | |
749 | CValidationState state; | |
750 | ||
751 | submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}; | |
752 | ||
753 | protected: | |
754 | virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) { | |
755 | if (block.GetHash() != hash) | |
756 | return; | |
757 | found = true; | |
758 | state = stateIn; | |
759 | }; | |
760 | }; | |
761 | ||
d014114d | 762 | UniValue submitblock(const UniValue& params, bool fHelp) |
7600e7fc JG |
763 | { |
764 | if (fHelp || params.size() < 1 || params.size() > 2) | |
765 | throw runtime_error( | |
a6099ef3 | 766 | "submitblock \"hexdata\" ( \"jsonparametersobject\" )\n" |
767 | "\nAttempts to submit new block to network.\n" | |
768 | "The 'jsonparametersobject' parameter is currently ignored.\n" | |
769 | "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" | |
770 | ||
771 | "\nArguments\n" | |
772 | "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n" | |
773 | "2. \"jsonparametersobject\" (string, optional) object of optional parameters\n" | |
774 | " {\n" | |
775 | " \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n" | |
776 | " }\n" | |
777 | "\nResult:\n" | |
552d7553 JG |
778 | "\"duplicate\" - node already has valid copy of block\n" |
779 | "\"duplicate-invalid\" - node already has block, but it is invalid\n" | |
780 | "\"duplicate-inconclusive\" - node already has block but has not validated it\n" | |
781 | "\"inconclusive\" - node has not validated the block, it may not be on the node's current best chain\n" | |
782 | "\"rejected\" - block was rejected as invalid\n" | |
783 | "For more information on submitblock parameters and results, see: https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki#block-submission\n" | |
a6099ef3 | 784 | "\nExamples:\n" |
785 | + HelpExampleCli("submitblock", "\"mydata\"") | |
786 | + HelpExampleRpc("submitblock", "\"mydata\"") | |
787 | ); | |
7600e7fc | 788 | |
60755dbf LD |
789 | CBlock block; |
790 | if (!DecodeHexBlk(block, params[0].get_str())) | |
738835d7 | 791 | throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); |
7600e7fc | 792 | |
60755dbf | 793 | uint256 hash = block.GetHash(); |
eb63bf86 MC |
794 | bool fBlockPresent = false; |
795 | { | |
796 | LOCK(cs_main); | |
797 | BlockMap::iterator mi = mapBlockIndex.find(hash); | |
798 | if (mi != mapBlockIndex.end()) { | |
799 | CBlockIndex *pindex = mi->second; | |
800 | if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) | |
801 | return "duplicate"; | |
802 | if (pindex->nStatus & BLOCK_FAILED_MASK) | |
803 | return "duplicate-invalid"; | |
804 | // Otherwise, we might only have the header - process the block before returning | |
805 | fBlockPresent = true; | |
806 | } | |
7600e7fc JG |
807 | } |
808 | ||
ef3988ca | 809 | CValidationState state; |
60755dbf | 810 | submitblock_StateCatcher sc(block.GetHash()); |
f877aaaf | 811 | RegisterValidationInterface(&sc); |
8a1b1894 | 812 | bool fAccepted = ProcessNewBlock(1,chainActive.Tip()->nHeight+1,state, NULL, &block, true, NULL); |
f877aaaf | 813 | UnregisterValidationInterface(&sc); |
eb63bf86 | 814 | if (fBlockPresent) |
60755dbf LD |
815 | { |
816 | if (fAccepted && !sc.found) | |
817 | return "duplicate-inconclusive"; | |
818 | return "duplicate"; | |
819 | } | |
f877aaaf LD |
820 | if (fAccepted) |
821 | { | |
822 | if (!sc.found) | |
823 | return "inconclusive"; | |
824 | state = sc.state; | |
825 | } | |
3dcbb9b6 | 826 | return BIP22ValidationResult(state); |
7600e7fc | 827 | } |
171ca774 | 828 | |
d014114d | 829 | UniValue estimatefee(const UniValue& params, bool fHelp) |
171ca774 GA |
830 | { |
831 | if (fHelp || params.size() != 1) | |
832 | throw runtime_error( | |
833 | "estimatefee nblocks\n" | |
834 | "\nEstimates the approximate fee per kilobyte\n" | |
a15dba5d | 835 | "needed for a transaction to begin confirmation\n" |
171ca774 GA |
836 | "within nblocks blocks.\n" |
837 | "\nArguments:\n" | |
838 | "1. nblocks (numeric)\n" | |
839 | "\nResult:\n" | |
840 | "n : (numeric) estimated fee-per-kilobyte\n" | |
841 | "\n" | |
842 | "-1.0 is returned if not enough transactions and\n" | |
843 | "blocks have been observed to make an estimate.\n" | |
844 | "\nExample:\n" | |
845 | + HelpExampleCli("estimatefee", "6") | |
846 | ); | |
847 | ||
ed21d5bd | 848 | RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); |
171ca774 GA |
849 | |
850 | int nBlocks = params[0].get_int(); | |
851 | if (nBlocks < 1) | |
852 | nBlocks = 1; | |
853 | ||
854 | CFeeRate feeRate = mempool.estimateFee(nBlocks); | |
855 | if (feeRate == CFeeRate(0)) | |
856 | return -1.0; | |
857 | ||
858 | return ValueFromAmount(feeRate.GetFeePerK()); | |
859 | } | |
860 | ||
d014114d | 861 | UniValue estimatepriority(const UniValue& params, bool fHelp) |
171ca774 GA |
862 | { |
863 | if (fHelp || params.size() != 1) | |
864 | throw runtime_error( | |
865 | "estimatepriority nblocks\n" | |
866 | "\nEstimates the approximate priority\n" | |
a15dba5d | 867 | "a zero-fee transaction needs to begin confirmation\n" |
171ca774 GA |
868 | "within nblocks blocks.\n" |
869 | "\nArguments:\n" | |
870 | "1. nblocks (numeric)\n" | |
871 | "\nResult:\n" | |
872 | "n : (numeric) estimated priority\n" | |
873 | "\n" | |
874 | "-1.0 is returned if not enough transactions and\n" | |
875 | "blocks have been observed to make an estimate.\n" | |
876 | "\nExample:\n" | |
877 | + HelpExampleCli("estimatepriority", "6") | |
878 | ); | |
879 | ||
ed21d5bd | 880 | RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); |
171ca774 GA |
881 | |
882 | int nBlocks = params[0].get_int(); | |
883 | if (nBlocks < 1) | |
884 | nBlocks = 1; | |
885 | ||
886 | return mempool.estimatePriority(nBlocks); | |
887 | } | |
1b114e54 | 888 | |
0d37ae3a | 889 | UniValue getblocksubsidy(const UniValue& params, bool fHelp) |
1b114e54 | 890 | { |
5d50130b | 891 | if (fHelp || params.size() > 1) |
1b114e54 | 892 | throw runtime_error( |
1db13d50 | 893 | "getblocksubsidy height\n" |
ea26d328 | 894 | "\nReturns block subsidy reward, taking into account the mining slow start and the founders reward, of block at index provided.\n" |
1b114e54 | 895 | "\nArguments:\n" |
5d50130b | 896 | "1. height (numeric, optional) The block height. If not provided, defaults to the current height of the chain.\n" |
1b114e54 | 897 | "\nResult:\n" |
ea26d328 | 898 | "{\n" |
0233ea28 | 899 | " \"miner\" : x.xxx (numeric) The mining reward amount in KMD.\n" |
ea26d328 | 900 | "}\n" |
1b114e54 S |
901 | "\nExamples:\n" |
902 | + HelpExampleCli("getblocksubsidy", "1000") | |
903 | + HelpExampleRpc("getblockubsidy", "1000") | |
904 | ); | |
905 | ||
933bff47 | 906 | LOCK(cs_main); |
5d50130b S |
907 | int nHeight = (params.size()==1) ? params[0].get_int() : chainActive.Height(); |
908 | if (nHeight < 0) | |
1b114e54 S |
909 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); |
910 | ||
911 | CAmount nReward = GetBlockSubsidy(nHeight, Params().GetConsensus()); | |
0d37ae3a | 912 | UniValue result(UniValue::VOBJ); |
ea26d328 | 913 | result.push_back(Pair("miner", ValueFromAmount(nReward))); |
3a02f67b | 914 | //result.push_back(Pair("founders", ValueFromAmount(nFoundersReward))); |
ea26d328 | 915 | return result; |
1b114e54 | 916 | } |