Update CMakeLists.txt - play with openssl
[novacoin.git] / src / rpcmining.cpp
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2012 The Bitcoin developers
3 // Distributed under the MIT/X11 software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6 #include "db.h"
7 #include "txdb-leveldb.h"
8 #include "init.h"
9 #include "miner.h"
10 #include "kernel.h"
11 #include "bitcoinrpc.h"
12 #include "wallet.h"
13
14 using namespace json_spirit;
15 using namespace std;
16
17 extern uint256 nPoWBase;
18 extern uint64_t nStakeInputsMapSize;
19
20 Value getsubsidy(const Array& params, bool fHelp)
21 {
22     if (fHelp || params.size() > 1)
23         throw runtime_error(
24             "getsubsidy [nTarget]\n"
25             "Returns proof-of-work subsidy value for the specified value of target.");
26
27     unsigned int nBits = 0;
28
29     if (params.size() != 0)
30     {
31         CBigNum bnTarget(uint256(params[0].get_str()));
32         nBits = bnTarget.GetCompact();
33     }
34     else
35     {
36         nBits = GetNextTargetRequired(pindexBest, false);
37     }
38
39     return (uint64_t)GetProofOfWorkReward(nBits);
40 }
41
42 Value getmininginfo(const Array& params, bool fHelp)
43 {
44     if (fHelp || params.size() != 0)
45         throw runtime_error(
46             "getmininginfo\n"
47             "Returns an object containing mining-related information.");
48
49     Object obj, diff;
50     obj.push_back(Pair("blocks",        (int)nBestHeight));
51     obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize));
52     obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx));
53
54     diff.push_back(Pair("proof-of-work",        GetDifficulty()));
55     diff.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
56     diff.push_back(Pair("search-interval",      (int)nLastCoinStakeSearchInterval));
57     obj.push_back(Pair("difficulty",    diff));
58
59     obj.push_back(Pair("blockvalue",    (uint64_t)GetProofOfWorkReward(GetLastBlockIndex(pindexBest, false)->nBits)));
60     obj.push_back(Pair("netmhashps",    GetPoWMHashPS()));
61     obj.push_back(Pair("netstakeweight",GetPoSKernelPS()));
62     obj.push_back(Pair("errors",        GetWarnings("statusbar")));
63     obj.push_back(Pair("pooledtx",      (uint64_t)mempool.size()));
64
65     obj.push_back(Pair("stakeinputs",   (uint64_t)nStakeInputsMapSize));
66     obj.push_back(Pair("stakeinterest", GetProofOfStakeReward(0, GetLastBlockIndex(pindexBest, true)->nBits, GetLastBlockIndex(pindexBest, true)->nTime, true)));
67
68     obj.push_back(Pair("testnet",       fTestNet));
69     return obj;
70 }
71
72 // scaninput '{"txid":"95d640426fe66de866a8cf2d0601d2c8cf3ec598109b4d4ffa7fd03dad6d35ce","difficulty":0.01, "days":10}'
73 Value scaninput(const Array& params, bool fHelp)
74 {
75     if (fHelp || params.size() != 1)
76         throw runtime_error(
77             "scaninput '{\"txid\":\"txid\", \"vout\":[vout1, vout2, ..., voutN], \"difficulty\":difficulty, \"days\":days}'\n"
78             "Scan specified transaction or input for suitable kernel solutions.\n"
79             "    difficulty - upper limit for difficulty, current difficulty by default;\n"
80             "    days - time window, 90 days by default.\n"
81         );
82
83     RPCTypeCheck(params, { obj_type });
84
85     Object scanParams = params[0].get_obj();
86
87     const Value& txid_v = find_value(scanParams, "txid");
88     if (txid_v.type() != str_type)
89         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
90
91     string txid = txid_v.get_str();
92     if (!IsHex(txid))
93         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
94
95     uint256 hash(txid);
96     int32_t nDays = 90;
97     uint32_t nBits = GetNextTargetRequired(pindexBest, true);
98
99     const Value& diff_v = find_value(scanParams, "difficulty");
100     if (diff_v.type() == real_type || diff_v.type() == int_type)
101     {
102         double dDiff = diff_v.get_real();
103         if (dDiff <= 0)
104             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, diff must be greater than zero");
105
106         CBigNum bnTarget(nPoWBase);
107         bnTarget *= 1000;
108         bnTarget /= (int) (dDiff * 1000);
109         nBits = bnTarget.GetCompact();
110     }
111
112     const Value& days_v = find_value(scanParams, "days");
113     if (days_v.type() == int_type)
114     {
115         nDays = days_v.get_int();
116         if (nDays <= 0)
117             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, interval length must be greater than zero");
118     }
119
120
121     CTransaction tx;
122     uint256 hashBlock = 0;
123     if (GetTransaction(hash, tx, hashBlock))
124     {
125         if (hashBlock == 0)
126             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to find transaction in the blockchain");
127
128         vector<int> vInputs(0);
129         const Value& inputs_v = find_value(scanParams, "vout");
130         if (inputs_v.type() == array_type)
131         {
132             Array inputs = inputs_v.get_array();
133             for (const Value &v_out : inputs)
134             {
135                 int nOut = v_out.get_int();
136                 if (nOut < 0 || nOut > (int)tx.vout.size() - 1)
137                 {
138                     stringstream strErrorMsg;
139                     strErrorMsg << "Invalid parameter, input number " << to_string(nOut) << " is out of range";
140                     throw JSONRPCError(RPC_INVALID_PARAMETER, strErrorMsg.str());
141                 }
142
143                 vInputs.push_back(nOut);
144             }
145         }
146         else if(inputs_v.type() == int_type)
147         {
148             int nOut = inputs_v.get_int();
149             if (nOut < 0 || nOut > (int)tx.vout.size() - 1)
150             {
151                 stringstream strErrorMsg;
152                 strErrorMsg << "Invalid parameter, input number " << to_string(nOut) << " is out of range";
153                 throw JSONRPCError(RPC_INVALID_PARAMETER, strErrorMsg.str());
154             }
155
156             vInputs.push_back(nOut);
157         }
158         else
159         {
160             for (size_t i = 0; i != tx.vout.size(); ++i) vInputs.push_back(i);
161         }
162
163         CTxDB txdb("r");
164
165         CBlock block;
166         CTxIndex txindex;
167
168         // Load transaction index item
169         if (!txdb.ReadTxIndex(tx.GetHash(), txindex))
170             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to read block index item");
171
172         // Read block header
173         if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
174             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "CBlock::ReadFromDisk() failed");
175
176         uint64_t nStakeModifier = 0;
177         if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier))
178             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No kernel stake modifier generated yet");
179
180         std::pair<uint32_t, uint32_t> interval;
181         interval.first = GetTime();
182         // Only count coins meeting min age requirement
183         if (nStakeMinAge + block.nTime > interval.first)
184             interval.first += (nStakeMinAge + block.nTime - interval.first);
185         interval.second = interval.first + nDays * nOneDay;
186
187         Array results;
188         for (const int &nOut : vInputs)
189         {
190             // Check for spent flag
191             // It doesn't make sense to scan spent inputs.
192             if (!txindex.vSpent[nOut].IsNull())
193                 continue;
194
195             // Skip zero value outputs
196             if (tx.vout[nOut].nValue == 0)
197                 continue;
198
199             // Build static part of kernel
200             CDataStream ssKernel(SER_GETHASH, 0);
201             ssKernel << nStakeModifier;
202             ssKernel << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << tx.nTime << nOut;
203             CDataStream::const_iterator itK = ssKernel.begin();
204
205             std::vector<std::pair<uint256, uint32_t> > result;
206             if (ScanKernelForward((unsigned char *)&itK[0], nBits, tx.nTime, tx.vout[nOut].nValue, interval, result))
207             {
208                 for (const auto &solution : result)
209                 {
210                     Object item;
211                     item.push_back(Pair("nout", nOut));
212                     item.push_back(Pair("hash", solution.first.GetHex()));
213                     item.push_back(Pair("time", DateTimeStrFormat(solution.second)));
214
215                     results.push_back(item);
216                 }
217             }
218         }
219
220         if (results.size() == 0)
221             return false;
222
223         return results;
224     }
225     else
226         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction");
227 }
228
229 Value getworkex(const Array& params, bool fHelp)
230 {
231     if (fHelp || params.size() > 2)
232         throw runtime_error(
233             "getworkex [data, coinbase]\n"
234             "If [data, coinbase] is not specified, returns extended work data.\n"
235         );
236
237     if (vNodes.empty())
238         throw JSONRPCError(-9, "NovaCoin is not connected!");
239
240     if (IsInitialBlockDownload())
241         throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
242
243     typedef map<uint256, pair<shared_ptr<CBlock>, CScript> > mapNewBlock_t;
244     static mapNewBlock_t mapNewBlock;
245     static vector<std::shared_ptr<CBlock>> vNewBlock;
246     static CReserveKey reservekey(pwalletMain);
247
248     if (params.size() == 0)
249     {
250         // Update block
251         static unsigned int nTransactionsUpdatedLast;
252         static CBlockIndex* pindexPrev;
253         static int64_t nStart;
254         static shared_ptr<CBlock> pblock;
255         if (pindexPrev != pindexBest ||
256             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
257         {
258             if (pindexPrev != pindexBest)
259             {
260                 // Deallocate old blocks since they're obsolete now
261                 mapNewBlock.clear();
262                 vNewBlock.clear();
263             }
264             nTransactionsUpdatedLast = nTransactionsUpdated;
265             pindexPrev = pindexBest;
266             nStart = GetTime();
267
268             // Create new block
269             pblock = CreateNewBlock(pwalletMain);
270             if (!pblock)
271                 throw JSONRPCError(-7, "Out of memory");
272             vNewBlock.push_back(pblock);
273         }
274
275         // Update nTime
276         pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
277         pblock->nNonce = 0;
278
279         // Update nExtraNonce
280         static unsigned int nExtraNonce = 0;
281         IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
282
283         // Save
284         mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
285
286         // Prebuild hash buffers
287         char pmidstate[32];
288         char pdata[128];
289         char phash1[64];
290         FormatHashBuffers(pblock, pmidstate, pdata, phash1);
291
292         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
293
294         CTransaction coinbaseTx = pblock->vtx[0];
295         std::vector<uint256> merkle = pblock->GetMerkleBranch(0);
296
297         Object result;
298         result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
299         result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
300
301         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
302         ssTx << coinbaseTx;
303         result.push_back(Pair("coinbase", HexStr(ssTx.begin(), ssTx.end())));
304
305         Array merkle_arr;
306
307         for (uint256 merkleh : merkle) {
308             merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
309         }
310
311         result.push_back(Pair("merkle", merkle_arr));
312
313
314         return result;
315     }
316     else
317     {
318         // Parse parameters
319         vector<unsigned char> vchData = ParseHex(params[0].get_str());
320         vector<unsigned char> coinbase;
321
322         if(params.size() == 2)
323             coinbase = ParseHex(params[1].get_str());
324
325         if (vchData.size() != 128)
326             throw JSONRPCError(-8, "Invalid parameter");
327
328         CBlock* pdata = (CBlock*)&vchData[0];
329
330         // Byte reverse
331         for (int i = 0; i < 128/4; i++)
332             ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
333
334         // Get saved block
335         if (!mapNewBlock.count(pdata->hashMerkleRoot))
336             return false;
337         std::shared_ptr<CBlock> pblock = mapNewBlock[pdata->hashMerkleRoot].first;
338
339         pblock->nTime = pdata->nTime;
340         pblock->nNonce = pdata->nNonce;
341
342         if(coinbase.size() == 0)
343             pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
344         else
345             CDataStream(coinbase, SER_NETWORK, PROTOCOL_VERSION) >> pblock->vtx[0]; // FIXME - HACK!
346
347         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
348
349         return CheckWork(pblock, *pwalletMain, reservekey);
350     }
351 }
352
353
354 Value getwork(const Array& params, bool fHelp)
355 {
356     if (fHelp || params.size() > 1)
357         throw runtime_error(
358             "getwork [data]\n"
359             "If [data] is not specified, returns formatted hash data to work on:\n"
360             "  \"midstate\" : precomputed hash state after hashing the first half of the data (DEPRECATED)\n" // deprecated
361             "  \"data\" : block data\n"
362             "  \"hash1\" : formatted hash buffer for second hash (DEPRECATED)\n" // deprecated
363             "  \"target\" : little endian hash target\n"
364             "If [data] is specified, tries to solve the block and returns true if it was successful.");
365
366     if (vNodes.empty())
367         throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "NovaCoin is not connected!");
368
369     if (IsInitialBlockDownload())
370         throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "NovaCoin is downloading blocks...");
371
372     typedef map<uint256, pair<shared_ptr<CBlock>, CScript> > mapNewBlock_t;
373     static mapNewBlock_t mapNewBlock;    // FIXME: thread safety
374     static vector<shared_ptr<CBlock>> vNewBlock;
375     static CReserveKey reservekey(pwalletMain);
376
377     if (params.size() == 0)
378     {
379         // Update block
380         static unsigned int nTransactionsUpdatedLast;
381         static CBlockIndex* pindexPrev;
382         static int64_t nStart;
383         static shared_ptr<CBlock> pblock;
384         if (pindexPrev != pindexBest ||
385             (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
386         {
387             if (pindexPrev != pindexBest)
388             {
389                 // Deallocate old blocks since they're obsolete now
390                 mapNewBlock.clear();
391                 vNewBlock.clear();
392             }
393
394             // Clear pindexPrev so future getworks make a new block, despite any failures from here on
395             pindexPrev = NULL;
396
397             // Store the pindexBest used before CreateNewBlock, to avoid races
398             nTransactionsUpdatedLast = nTransactionsUpdated;
399             CBlockIndex* pindexPrevNew = pindexBest;
400             nStart = GetTime();
401
402             // Create new block
403             pblock = CreateNewBlock(pwalletMain);
404             if (!pblock)
405                 throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
406             vNewBlock.push_back(pblock);
407
408             // Need to update only after we know CreateNewBlock succeeded
409             pindexPrev = pindexPrevNew;
410         }
411
412         // Update nTime
413         pblock->UpdateTime(pindexPrev);
414         pblock->nNonce = 0;
415
416         // Update nExtraNonce
417         static unsigned int nExtraNonce = 0;
418         IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
419
420         // Save
421         mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
422
423         // Pre-build hash buffers
424         char pmidstate[32];
425         char pdata[128];
426         char phash1[64];
427         FormatHashBuffers(pblock, pmidstate, pdata, phash1);
428
429         uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
430
431         Object result;
432         result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
433         result.push_back(Pair("data",     HexStr(BEGIN(pdata), END(pdata))));
434         result.push_back(Pair("hash1",    HexStr(BEGIN(phash1), END(phash1)))); // deprecated
435         result.push_back(Pair("target",   HexStr(BEGIN(hashTarget), END(hashTarget))));
436         return result;
437     }
438     else
439     {
440         // Parse parameters
441         vector<unsigned char> vchData = ParseHex(params[0].get_str());
442         if (vchData.size() != 128)
443             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
444         CBlock* pdata = (CBlock*)&vchData[0];
445
446         // Byte reverse
447         for (int i = 0; i < 128/4; i++)
448             ((unsigned int*)pdata)[i] = ByteReverse(((unsigned int*)pdata)[i]);
449
450         // Get saved block
451         if (!mapNewBlock.count(pdata->hashMerkleRoot))
452             return false;
453         std::shared_ptr<CBlock> pblock = mapNewBlock[pdata->hashMerkleRoot].first;
454
455         pblock->nTime = pdata->nTime;
456         pblock->nNonce = pdata->nNonce;
457         pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second;
458         pblock->hashMerkleRoot = pblock->BuildMerkleTree();
459
460         return CheckWork(pblock, *pwalletMain, reservekey);
461     }
462 }
463
464
465 Value getblocktemplate(const Array& params, bool fHelp)
466 {
467     if (fHelp || params.size() > 1)
468         throw runtime_error(
469             "getblocktemplate [params]\n"
470             "Returns data needed to construct a block to work on:\n"
471             "  \"version\" : block version\n"
472             "  \"previousblockhash\" : hash of current highest block\n"
473             "  \"transactions\" : contents of non-coinbase transactions that should be included in the next block\n"
474             "  \"coinbaseaux\" : data that should be included in coinbase\n"
475             "  \"coinbasevalue\" : maximum allowable input to coinbase transaction, including the generation award and transaction fees\n"
476             "  \"target\" : hash target\n"
477             "  \"mintime\" : minimum timestamp appropriate for next block\n"
478             "  \"curtime\" : current timestamp\n"
479             "  \"mutable\" : list of ways the block template may be changed\n"
480             "  \"noncerange\" : range of valid nonces\n"
481             "  \"sigoplimit\" : limit of sigops in blocks\n"
482             "  \"sizelimit\" : limit of block size\n"
483             "  \"bits\" : compressed target of next block\n"
484             "  \"height\" : height of the next block\n"
485             "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
486
487     std::string strMode = "template";
488     if (params.size() > 0)
489     {
490         const Object& oparam = params[0].get_obj();
491         const Value& modeval = find_value(oparam, "mode");
492         if (modeval.type() == str_type)
493             strMode = modeval.get_str();
494         else if (modeval.type() == null_type)
495         {
496             /* Do nothing */
497         }
498         else
499             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
500     }
501
502     if (strMode != "template")
503         throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
504
505     if (vNodes.empty())
506         throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "NovaCoin is not connected!");
507
508     if (IsInitialBlockDownload())
509         throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "NovaCoin is downloading blocks...");
510
511     static CReserveKey reservekey(pwalletMain);
512
513     // Update block
514     static unsigned int nTransactionsUpdatedLast;
515     static CBlockIndex* pindexPrev;
516     static int64_t nStart;
517     static std::shared_ptr<CBlock> pblock;
518     if (pindexPrev != pindexBest ||
519         (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
520     {
521         // Clear pindexPrev so future calls make a new block, despite any failures from here on
522         pindexPrev = NULL;
523
524         // Store the pindexBest used before CreateNewBlock, to avoid races
525         nTransactionsUpdatedLast = nTransactionsUpdated;
526         CBlockIndex* pindexPrevNew = pindexBest;
527         nStart = GetTime();
528
529         // Create new block
530         if(pblock)
531         {
532             pblock.reset();
533         }
534         pblock = CreateNewBlock(pwalletMain);
535         if (!pblock)
536             throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
537
538         // Need to update only after we know CreateNewBlock succeeded
539         pindexPrev = pindexPrevNew;
540     }
541
542     // Update nTime
543     pblock->UpdateTime(pindexPrev);
544     pblock->nNonce = 0;
545
546     Array transactions;
547     map<uint256, int64_t> setTxIndex;
548     int i = 0;
549     CTxDB txdb("r");
550     for (CTransaction& tx : pblock->vtx)
551     {
552         uint256 txHash = tx.GetHash();
553         setTxIndex[txHash] = i++;
554
555         if (tx.IsCoinBase() || tx.IsCoinStake())
556             continue;
557
558         Object entry;
559
560         CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
561         ssTx << tx;
562         entry.push_back(Pair("data", HexStr(ssTx.begin(), ssTx.end())));
563
564         entry.push_back(Pair("hash", txHash.GetHex()));
565
566         MapPrevTx mapInputs;
567         map<uint256, CTxIndex> mapUnused;
568         bool fInvalid = false;
569         if (tx.FetchInputs(txdb, mapUnused, false, false, mapInputs, fInvalid))
570         {
571             entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
572
573             Array deps;
574             for (MapPrevTx::value_type& inp : mapInputs)
575             {
576                 if (setTxIndex.count(inp.first))
577                     deps.push_back(setTxIndex[inp.first]);
578             }
579             entry.push_back(Pair("depends", deps));
580
581             int64_t nSigOps = tx.GetLegacySigOpCount();
582             nSigOps += tx.GetP2SHSigOpCount(mapInputs);
583             entry.push_back(Pair("sigops", nSigOps));
584         }
585
586         transactions.push_back(entry);
587     }
588
589     Object aux;
590     aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
591
592     uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
593
594     static Array aMutable;
595     if (aMutable.empty())
596     {
597         aMutable.push_back("time");
598         aMutable.push_back("transactions");
599         aMutable.push_back("prevblock");
600     }
601
602     Object result;
603     result.push_back(Pair("version", pblock->nVersion));
604     result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
605     result.push_back(Pair("transactions", transactions));
606     result.push_back(Pair("coinbaseaux", aux));
607     result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue));
608     result.push_back(Pair("target", hashTarget.GetHex()));
609     result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1));
610     result.push_back(Pair("mutable", aMutable));
611     result.push_back(Pair("noncerange", "00000000ffffffff"));
612     result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
613     result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
614     result.push_back(Pair("curtime", (int64_t)pblock->nTime));
615     result.push_back(Pair("bits", HexBits(pblock->nBits)));
616     result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight+1)));
617
618     return result;
619 }
620
621 Value submitblock(const Array& params, bool fHelp)
622 {
623     if (fHelp || params.size() < 1 || params.size() > 2)
624         throw runtime_error(
625             "submitblock <hex data> [optional-params-obj]\n"
626             "[optional-params-obj] parameter is currently ignored.\n"
627             "Attempts to submit new block to network.\n"
628             "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
629
630     vector<unsigned char> blockData(ParseHex(params[0].get_str()));
631     CDataStream ssBlock(blockData, SER_NETWORK, PROTOCOL_VERSION);
632     CBlock block;
633     try {
634         ssBlock >> block;
635     }
636     catch (const std::exception&) {
637         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
638     }
639
640     bool fAccepted = ProcessBlock(NULL, &block);
641     if (!fAccepted)
642         return "rejected";
643
644     return Value::null;
645 }
646