Add transaction and block header timestamps to gettxout RPC call result.
[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
9 using namespace json_spirit;
10 using namespace std;
11
12 extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, json_spirit::Object& entry);
13 extern enum Checkpoints::CPMode CheckpointsMode;
14
15 double GetDifficulty(const CBlockIndex* blockindex)
16 {
17     // Floating point number that is a multiple of the minimum difficulty,
18     // minimum difficulty = 1.0.
19     if (blockindex == NULL)
20     {
21         if (pindexBest == NULL)
22             return 1.0;
23         else
24             blockindex = GetLastBlockIndex(pindexBest, false);
25     }
26
27     int nShift = (blockindex->nBits >> 24) & 0xff;
28
29     double dDiff =
30         (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
31
32     while (nShift < 29)
33     {
34         dDiff *= 256.0;
35         nShift++;
36     }
37     while (nShift > 29)
38     {
39         dDiff /= 256.0;
40         nShift--;
41     }
42
43     return dDiff;
44 }
45
46 double GetPoWMHashPS()
47 {
48     int nPoWInterval = 72;
49     int64 nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;
50
51     CBlockIndex* pindex = pindexGenesisBlock;
52     CBlockIndex* pindexPrevWork = pindexGenesisBlock;
53
54     while (pindex)
55     {
56         if (pindex->IsProofOfWork())
57         {
58             int64 nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
59             nTargetSpacingWork = ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nPoWInterval + 1);
60             nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
61             pindexPrevWork = pindex;
62         }
63
64         pindex = pindex->pnext;
65     }
66
67     return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
68 }
69
70 double GetPoSKernelPS()
71 {
72     int nPoSInterval = 72;
73     double dStakeKernelsTriedAvg = 0;
74     int nStakesHandled = 0, nStakesTime = 0;
75
76     CBlockIndex* pindex = pindexBest;;
77     CBlockIndex* pindexPrevStake = NULL;
78
79     while (pindex && nStakesHandled < nPoSInterval)
80     {
81         if (pindex->IsProofOfStake())
82         {
83             dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
84             nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
85             pindexPrevStake = pindex;
86             nStakesHandled++;
87         }
88
89         pindex = pindex->pprev;
90     }
91
92     return dStakeKernelsTriedAvg / nStakesTime;
93 }
94
95 Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
96 {
97     Object result;
98     result.push_back(Pair("hash", block.GetHash().GetHex()));
99     CMerkleTx txGen(block.vtx[0]);
100     txGen.SetMerkleBranch(&block);
101     result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
102     result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
103     result.push_back(Pair("height", blockindex->nHeight));
104     result.push_back(Pair("version", block.nVersion));
105     result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
106     result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
107     result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime()));
108     result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce));
109     result.push_back(Pair("bits", HexBits(block.nBits)));
110     result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
111     result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
112     result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
113     if (blockindex->pprev)
114         result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
115     if (blockindex->pnext)
116         result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
117
118     result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
119     result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
120     result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
121     result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier)));
122     result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
123     Array txinfo;
124     BOOST_FOREACH (const CTransaction& tx, block.vtx)
125     {
126         if (fPrintTransactionDetail)
127         {
128             Object entry;
129
130             entry.push_back(Pair("txid", tx.GetHash().GetHex()));
131             TxToJSON(tx, 0, entry);
132
133             txinfo.push_back(entry);
134         }
135         else
136             txinfo.push_back(tx.GetHash().GetHex());
137     }
138
139     result.push_back(Pair("tx", txinfo));
140
141     if ( block.IsProofOfStake() )
142     {
143         CKey key;
144         block.GetGenerator(key);
145         result.push_back(Pair("generator", HexStr(key.GetPubKey().Raw())));
146         result.push_back(Pair("signature", HexStr(block.vchBlockSig)));
147     }
148
149     return result;
150 }
151
152 Value getbestblockhash(const Array& params, bool fHelp)
153 {
154     if (fHelp || params.size() != 0)
155         throw runtime_error(
156             "getbestblockhash\n"
157             "Returns the hash of the best block in the longest block chain.");
158
159     return hashBestChain.GetHex();
160 }
161
162 Value getblockcount(const Array& params, bool fHelp)
163 {
164     if (fHelp || params.size() != 0)
165         throw runtime_error(
166             "getblockcount\n"
167             "Returns the number of blocks in the longest block chain.");
168
169     return nBestHeight;
170 }
171
172
173 Value getdifficulty(const Array& params, bool fHelp)
174 {
175     if (fHelp || params.size() != 0)
176         throw runtime_error(
177             "getdifficulty\n"
178             "Returns the difficulty as a multiple of the minimum difficulty.");
179
180     Object obj;
181     obj.push_back(Pair("proof-of-work",        GetDifficulty()));
182     obj.push_back(Pair("proof-of-stake",       GetDifficulty(GetLastBlockIndex(pindexBest, true))));
183     obj.push_back(Pair("search-interval",      (int)nLastCoinStakeSearchInterval));
184     return obj;
185 }
186
187
188 Value settxfee(const Array& params, bool fHelp)
189 {
190     if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
191         throw runtime_error(
192             "settxfee <amount>\n"
193             "<amount> is a real and is rounded to the nearest 0.01");
194
195     nTransactionFee = AmountFromValue(params[0]);
196     nTransactionFee = (nTransactionFee / CENT) * CENT;  // round to cent
197
198     return true;
199 }
200
201 Value getrawmempool(const Array& params, bool fHelp)
202 {
203     if (fHelp || params.size() != 0)
204         throw runtime_error(
205             "getrawmempool\n"
206             "Returns all transaction ids in memory pool.");
207
208     vector<uint256> vtxid;
209     mempool.queryHashes(vtxid);
210
211     Array a;
212     BOOST_FOREACH(const uint256& hash, vtxid)
213         a.push_back(hash.ToString());
214
215     return a;
216 }
217
218 Value getblockhash(const Array& params, bool fHelp)
219 {
220     if (fHelp || params.size() != 1)
221         throw runtime_error(
222             "getblockhash <index>\n"
223             "Returns hash of block in best-block-chain at <index>.");
224
225     int nHeight = params[0].get_int();
226     if (nHeight < 0 || nHeight > nBestHeight)
227         throw runtime_error("Block number out of range.");
228
229     CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
230     return pblockindex->phashBlock->GetHex();
231 }
232
233 Value getblock(const Array& params, bool fHelp)
234 {
235     if (fHelp || params.size() < 1 || params.size() > 2)
236         throw runtime_error(
237             "getblock <hash> [txinfo]\n"
238             "txinfo optional to print more detailed tx info\n"
239             "Returns details of a block with given block-hash.");
240
241     std::string strHash = params[0].get_str();
242     uint256 hash(strHash);
243
244     if (mapBlockIndex.count(hash) == 0)
245         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
246
247     CBlock block;
248     CBlockIndex* pblockindex = mapBlockIndex[hash];
249     block.ReadFromDisk(pblockindex, true);
250
251     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
252 }
253
254 Value getblockbynumber(const Array& params, bool fHelp)
255 {
256     if (fHelp || params.size() < 1 || params.size() > 2)
257         throw runtime_error(
258             "getblock <number> [txinfo]\n"
259             "txinfo optional to print more detailed tx info\n"
260             "Returns details of a block with given block-number.");
261
262     int nHeight = params[0].get_int();
263     if (nHeight < 0 || nHeight > nBestHeight)
264         throw runtime_error("Block number out of range.");
265
266     CBlock block;
267     CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
268     while (pblockindex->nHeight > nHeight)
269         pblockindex = pblockindex->pprev;
270
271     uint256 hash = *pblockindex->phashBlock;
272
273     pblockindex = mapBlockIndex[hash];
274     block.ReadFromDisk(pblockindex, true);
275
276     return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
277 }
278
279 // ppcoin: get information of sync-checkpoint
280 Value getcheckpoint(const Array& params, bool fHelp)
281 {
282     if (fHelp || params.size() != 0)
283         throw runtime_error(
284             "getcheckpoint\n"
285             "Show info of synchronized checkpoint.\n");
286
287     Object result;
288     CBlockIndex* pindexCheckpoint;
289
290     result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
291     pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
292     result.push_back(Pair("height", pindexCheckpoint->nHeight));
293     result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
294
295     // Check that the block satisfies synchronized checkpoint
296     if (CheckpointsMode == Checkpoints::STRICT)
297         result.push_back(Pair("policy", "strict"));
298
299     if (CheckpointsMode == Checkpoints::ADVISORY)
300         result.push_back(Pair("policy", "advisory"));
301
302     if (CheckpointsMode == Checkpoints::PERMISSIVE)
303         result.push_back(Pair("policy", "permissive"));
304
305     if (mapArgs.count("-checkpointkey"))
306         result.push_back(Pair("checkpointmaster", true));
307
308     return result;
309 }
310
311 Value gettxoutsetinfo(const Array& params, bool fHelp)
312 {
313     if (fHelp || params.size() != 0)
314         throw runtime_error(
315             "gettxoutsetinfo\n"
316             "Returns statistics about the unspent transaction output set.");
317
318     Object ret;
319
320     CCoinsStats stats;
321     if (pcoinsTip->GetStats(stats)) {
322         ret.push_back(Pair("bestblock", pcoinsTip->GetBestBlock()->GetBlockHash().GetHex()));
323         ret.push_back(Pair("transactions", (boost::int64_t)stats.nTransactions));
324         ret.push_back(Pair("txouts", (boost::int64_t)stats.nTransactionOutputs));
325         ret.push_back(Pair("bytes_serialized", (boost::int64_t)stats.nSerializedSize));
326     }
327     return ret;
328 }
329
330 Value gettxout(const Array& params, bool fHelp)
331 {
332     if (fHelp || params.size() < 2 || params.size() > 3)
333         throw runtime_error(
334             "gettxout <txid> <n> [includemempool=true]\n"
335             "Returns details about an unspent transaction output.");
336
337     Object ret;
338
339     std::string strHash = params[0].get_str();
340     uint256 hash(strHash);
341     int n = params[1].get_int();
342     bool fMempool = true;
343     if (params.size() > 2)
344         fMempool = params[2].get_bool();
345
346     CCoins coins;
347     if (fMempool) {
348         LOCK(mempool.cs);
349         CCoinsViewMemPool view(*pcoinsTip, mempool);
350         if (!view.GetCoins(hash, coins))
351             return Value::null;
352         mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
353     } else {
354         if (!pcoinsTip->GetCoins(hash, coins))
355             return Value::null;
356     }
357     if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
358         return Value::null;
359
360     ret.push_back(Pair("bestblock", pcoinsTip->GetBestBlock()->GetBlockHash().GetHex()));
361     if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT)
362         ret.push_back(Pair("confirmations", 0));
363     else
364         ret.push_back(Pair("confirmations", pcoinsTip->GetBestBlock()->nHeight - coins.nHeight + 1));
365     ret.push_back(Pair("amount", (boost::int64_t)coins.vout[n].nValue));
366     Object o;
367     o.push_back(Pair("asm", coins.vout[n].scriptPubKey.ToString()));
368     o.push_back(Pair("hex", HexStr(coins.vout[n].scriptPubKey.begin(), coins.vout[n].scriptPubKey.end())));
369     ret.push_back(Pair("scriptPubKey", o));
370     ret.push_back(Pair("version", coins.nVersion));
371     ret.push_back(Pair("coinbase", coins.fCoinBase));
372     ret.push_back(Pair("coinstake", coins.fCoinStake));
373     ret.push_back(Pair("time", (boost::int64_t)coins.nTime));
374     ret.push_back(Pair("blocktime", (boost::int64_t)coins.nBlockTime));
375
376     return ret;
377 }