d19869dbb568c6b4c639ef93b12d84f3fa0b208f
[novacoin.git] / src / rpcblockchain.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 "main.h"
7 #include "bitcoinrpc.h"
8 #include <boost/filesystem.hpp>
9 #include <boost/iostreams/device/file.hpp>
10 #include <boost/iostreams/stream.hpp>
11 #include <ostream>
12
13 using namespace json_spirit;
14 using namespace std;
15
16 extern void TxToJSON(const CTransaction& tx, const uint256& hashBlock, json_spirit::Object& entry);
17 extern enum Checkpoints::CPMode CheckpointsMode;
18
19 double GetDifficulty(const CBlockIndex* blockindex)
20 {
21     // Floating point number that is a multiple of the minimum difficulty,
22     // minimum difficulty = 1.0.
23     if (blockindex == NULL)
24     {
25         if (pindexBest == NULL)
26             return 1.0;
27         else
28             blockindex = GetLastBlockIndex(pindexBest, false);
29     }
30
31     int nShift = (blockindex->nBits >> 24) & 0xff;
32
33     double dDiff =
34         (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
35
36     while (nShift < 29)
37     {
38         dDiff *= 256.0;
39         nShift++;
40     }
41     while (nShift > 29)
42     {
43         dDiff /= 256.0;
44         nShift--;
45     }
46
47     return dDiff;
48 }
49
50 double GetPoWMHashPS()
51 {
52     int nPoWInterval = 72;
53     int64_t nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;
54
55     CBlockIndex* pindex = pindexGenesisBlock;
56     CBlockIndex* pindexPrevWork = pindexGenesisBlock;
57
58     while (pindex)
59     {
60         if (pindex->IsProofOfWork())
61         {
62             int64_t nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
63             nTargetSpacingWork = ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nPoWInterval + 1);
64             nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
65             pindexPrevWork = pindex;
66         }
67
68         pindex = pindex->pnext;
69     }
70
71     return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
72 }
73
74 double GetPoSKernelPS()
75 {
76     int nPoSInterval = 72;
77     double dStakeKernelsTriedAvg = 0;
78     int nStakesHandled = 0, nStakesTime = 0;
79
80     CBlockIndex* pindex = pindexBest;;
81     CBlockIndex* pindexPrevStake = NULL;
82
83     while (pindex && nStakesHandled < nPoSInterval)
84     {
85         if (pindex->IsProofOfStake())
86         {
87             dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
88             nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
89             pindexPrevStake = pindex;
90             nStakesHandled++;
91         }
92
93         pindex = pindex->pprev;
94     }
95
96     if (!nStakesHandled)
97         return 0;
98
99     return dStakeKernelsTriedAvg / nStakesTime;
100 }
101
102 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
103 {
104     Object result;
105     result.push_back(Pair("hash", block.GetHash().GetHex()));
106     CMerkleTx txGen(block.vtx[0]);
107     txGen.SetMerkleBranch(block);
108     result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
109     result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
110     result.push_back(Pair("height", blockindex->nHeight));
111     result.push_back(Pair("version", block.nVersion));
112     result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
113     result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
114     result.push_back(Pair("time", (int64_t)block.GetBlockTime()));
115     result.push_back(Pair("nonce", (uint64_t)block.nNonce));
116     result.push_back(Pair("bits", HexBits(block.nBits)));
117     result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
118     result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
119     result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
120     if (blockindex->pprev)
121         result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
122     if (blockindex->pnext)
123         result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
124
125     result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
126     result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
127     result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
128     result.push_back(Pair("modifier", strprintf("%016" PRIx64, blockindex->nStakeModifier)));
129     result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
130     Array txinfo;
131     BOOST_FOREACH (const CTransaction& tx, block.vtx)
132     {
133         if (fPrintTransactionDetail)
134         {
135             CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
136             ssTx << tx;
137             string strHex = HexStr(ssTx.begin(), ssTx.end());
138
139             txinfo.push_back(strHex);
140         }
141         else
142             txinfo.push_back(tx.GetHash().GetHex());
143     }
144
145     result.push_back(Pair("tx", txinfo));
146
147     if ( block.IsProofOfStake() )
148         result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));
149
150     return result;
151 }
152
153 Value getbestblockhash(const Array& params, bool fHelp)
154 {
155     if (fHelp || params.size() != 0)
156         throw runtime_error(
157             "getbestblockhash\n"
158             "Returns the hash of the best block in the longest block chain.");
159
160     return hashBestChain.GetHex();
161 }
162
163 Value getblockcount(const Array& params, bool fHelp)
164 {
165     if (fHelp || params.size() != 0)
166         throw runtime_error(
167             "getblockcount\n"
168             "Returns the number of blocks in the longest block chain.");
169
170     return nBestHeight;
171 }
172
173
174 Value getdifficulty(const Array& params, bool fHelp)
175 {
176     if (fHelp || params.size() != 0)
177         throw runtime_error(
178             "getdifficulty\n"
179             "Returns the difficulty as a multiple of the minimum difficulty.");
180
181     Object obj;
182     obj.push_back(Pair("proof-of-work",        GetDifficulty()));
183     obj.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
184     obj.push_back(Pair("search-interval",      (int)nLastCoinStakeSearchInterval));
185     return obj;
186 }
187
188
189 Value settxfee(const Array& params, bool fHelp)
190 {
191     if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
192         throw runtime_error(
193             "settxfee <amount>\n"
194             "<amount> is a real and is rounded to the nearest " + FormatMoney(MIN_TX_FEE));
195
196     nTransactionFee = AmountFromValue(params[0]);
197     nTransactionFee = (nTransactionFee / MIN_TX_FEE) * MIN_TX_FEE;  // round to minimum fee
198
199     return true;
200 }
201
202 Value getrawmempool(const Array& params, bool fHelp)
203 {
204     if (fHelp || params.size() != 0)
205         throw runtime_error(
206             "getrawmempool\n"
207             "Returns all transaction ids in memory pool.");
208
209     vector<uint256> vtxid;
210     mempool.queryHashes(vtxid);
211
212     Array a;
213     BOOST_FOREACH(const uint256& hash, vtxid)
214         a.push_back(hash.ToString());
215
216     return a;
217 }
218
219 Value getblockhash(const Array& params, bool fHelp)
220 {
221     if (fHelp || params.size() != 1)
222         throw runtime_error(
223             "getblockhash <index>\n"
224             "Returns hash of block in best-block-chain at <index>.");
225
226     int nHeight = params[0].get_int();
227     if (nHeight < 0 || nHeight > nBestHeight)
228         throw runtime_error("Block number out of range.");
229
230     CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
231     return pblockindex->phashBlock->GetHex();
232 }
233
234 Value getblock(const Array& params, bool fHelp)
235 {
236     if (fHelp || params.size() < 1 || params.size() > 2)
237         throw runtime_error(
238             "getblock <hash> [txinfo]\n"
239             "txinfo optional to print more detailed tx info\n"
240             "Returns details of a block with given block-hash.");
241
242     std::string strHash = params[0].get_str();
243     uint256 hash(strHash);
244
245     if (mapBlockIndex.count(hash) == 0)
246         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
247
248     CBlock block;
249     CBlockIndex* pblockindex = mapBlockIndex[hash];
250     block.ReadFromDisk(pblockindex, true);
251
252     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
253 }
254
255 Value getblockbynumber(const Array& params, bool fHelp)
256 {
257     if (fHelp || params.size() < 1 || params.size() > 2)
258         throw runtime_error(
259             "getblockbynumber <number> [txinfo]\n"
260             "txinfo optional to print more detailed tx info\n"
261             "Returns details of a block with given block-number.");
262
263     int nHeight = params[0].get_int();
264     if (nHeight < 0 || nHeight > nBestHeight)
265         throw runtime_error("Block number out of range.");
266
267     CBlock block;
268     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
269     while (pblockindex->nHeight > nHeight)
270         pblockindex = pblockindex->pprev;
271
272     pblockindex = mapBlockIndex[*pblockindex->phashBlock];
273     block.ReadFromDisk(pblockindex, true);
274
275     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
276 }
277
278 bool ExportBlock(const string& strBlockHash, const CDataStream& ssBlock)
279 {
280     boost::filesystem::path pathDest = GetDataDir() / strBlockHash;
281     if (boost::filesystem::is_directory(pathDest))
282         pathDest /= strBlockHash;
283
284     try {
285         boost::iostreams::stream_buffer<boost::iostreams::file_sink> buf(pathDest.string());
286         ostream                     exportStream(&buf);
287         exportStream << HexStr(ssBlock.begin(), ssBlock.end());
288         exportStream.flush();
289
290         printf("Successfully exported block to %s\n", pathDest.string().c_str());
291         return true;
292     } catch(const boost::filesystem::filesystem_error &e) {
293         printf("error exporting the block data %s (%s)\n", pathDest.string().c_str(), e.what());
294         return false;
295     }
296 }
297
298
299 Value dumpblock(const Array& params, bool fHelp)
300 {
301     if (fHelp || params.size() < 1 || params.size() > 2)
302         throw runtime_error(
303             "dumpblock <hash> [destination]\n"
304             "Returns serialized contents of a block with given block-hash.");
305
306     std::string strHash = params[0].get_str();
307     uint256 hash(strHash);
308
309     if (mapBlockIndex.count(hash) == 0)
310         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
311
312     CBlock block;
313     CBlockIndex* pblockindex = mapBlockIndex[hash];
314     block.ReadFromDisk(pblockindex, true);
315
316     CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
317     ssBlock << block;
318
319     if (params.size() > 1)
320     {
321         return ExportBlock(params[1].get_str(), ssBlock);
322     }
323
324     return HexStr(ssBlock.begin(), ssBlock.end());
325 }
326
327
328 Value dumpblockbynumber(const Array& params, bool fHelp)
329 {
330     if (fHelp || params.size() < 1 || params.size() > 2)
331         throw runtime_error(
332             "dumpblockbynumber <number>  [destination]\n"
333             "Returns serialized contents of a block with given block-number.");
334
335     int nHeight = params[0].get_int();
336     if (nHeight < 0 || nHeight > nBestHeight)
337         throw runtime_error("Block number out of range.");
338
339     CBlock block;
340     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
341     while (pblockindex->nHeight > nHeight)
342         pblockindex = pblockindex->pprev;
343
344     pblockindex = mapBlockIndex[*pblockindex->phashBlock];
345     block.ReadFromDisk(pblockindex, true);
346
347     CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
348     ssBlock << block;
349
350     if (params.size() > 1)
351     {
352         return ExportBlock(params[1].get_str(), ssBlock);
353     }
354
355     return HexStr(ssBlock.begin(), ssBlock.end());
356 }
357
358
359 // get information of sync-checkpoint
360 Value getcheckpoint(const Array& params, bool fHelp)
361 {
362     if (fHelp || params.size() != 0)
363         throw runtime_error(
364             "getcheckpoint\n"
365             "Show info of synchronized checkpoint.\n");
366
367     Object result;
368     CBlockIndex* pindexCheckpoint;
369
370     result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
371     pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
372     result.push_back(Pair("height", pindexCheckpoint->nHeight));
373     result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
374
375     if (Checkpoints::checkpointMessage.vchSig.size() != 0)
376     {
377         Object msgdata;
378         CUnsignedSyncCheckpoint checkpoint;
379
380         CDataStream sMsg(Checkpoints::checkpointMessage.vchMsg, SER_NETWORK, PROTOCOL_VERSION);
381         sMsg >> checkpoint;
382
383         Object parsed; // message version and data (block hash)
384         parsed.push_back(Pair("version", checkpoint.nVersion));
385         parsed.push_back(Pair("hash", checkpoint.hashCheckpoint.GetHex().c_str()));
386         msgdata.push_back(Pair("parsed", parsed));
387
388         Object raw; // raw checkpoint message data
389         raw.push_back(Pair("data", HexStr(Checkpoints::checkpointMessage.vchMsg).c_str()));
390         raw.push_back(Pair("signature", HexStr(Checkpoints::checkpointMessage.vchSig).c_str()));
391         msgdata.push_back(Pair("raw", raw));
392
393         result.push_back(Pair("data", msgdata));
394     }
395
396     // Check that the block satisfies synchronized checkpoint
397     if (CheckpointsMode == Checkpoints::STRICT)
398         result.push_back(Pair("policy", "strict"));
399
400     if (CheckpointsMode == Checkpoints::ADVISORY)
401         result.push_back(Pair("policy", "advisory"));
402
403     if (CheckpointsMode == Checkpoints::PERMISSIVE)
404         result.push_back(Pair("policy", "permissive"));
405
406     if (mapArgs.count("-checkpointkey"))
407         result.push_back(Pair("checkpointmaster", true));
408
409     return result;
410 }