Permalink
Fetching contributors…
Cannot retrieve contributors at this time
411 lines (324 sloc) 13.4 KB
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
#include "bitcoinrpc.h"
#include <boost/filesystem.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
#include <ostream>
using namespace json_spirit;
using namespace std;
extern void TxToJSON(const CTransaction& tx, const uint256& hashBlock, json_spirit::Object& entry);
extern enum Checkpoints::CPMode CheckpointsMode;
double GetDifficulty(const CBlockIndex* blockindex)
{
// Floating point number that is a multiple of the minimum difficulty,
// minimum difficulty = 1.0.
if (blockindex == NULL)
{
if (pindexBest == NULL)
return 1.0;
else
blockindex = GetLastBlockIndex(pindexBest, false);
}
int nShift = (blockindex->nBits >> 24) & 0xff;
double dDiff =
(double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
while (nShift < 29)
{
dDiff *= 256.0;
nShift++;
}
while (nShift > 29)
{
dDiff /= 256.0;
nShift--;
}
return dDiff;
}
double GetPoWMHashPS()
{
int nPoWInterval = 72;
int64_t nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30;
CBlockIndex* pindex = pindexGenesisBlock;
CBlockIndex* pindexPrevWork = pindexGenesisBlock;
while (pindex)
{
if (pindex->IsProofOfWork())
{
int64_t nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
nTargetSpacingWork = ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nPoWInterval + 1);
nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin);
pindexPrevWork = pindex;
}
pindex = pindex->pnext;
}
return GetDifficulty() * 4294.967296 / nTargetSpacingWork;
}
double GetPoSKernelPS()
{
int nPoSInterval = 72;
double dStakeKernelsTriedAvg = 0;
int nStakesHandled = 0, nStakesTime = 0;
CBlockIndex* pindex = pindexBest;;
CBlockIndex* pindexPrevStake = NULL;
while (pindex && nStakesHandled < nPoSInterval)
{
if (pindex->IsProofOfStake())
{
dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296.0;
nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0;
pindexPrevStake = pindex;
nStakesHandled++;
}
pindex = pindex->pprev;
}
if (!nStakesHandled)
return 0;
return dStakeKernelsTriedAvg / nStakesTime;
}
Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPrintTransactionDetail)
{
Object result;
result.push_back(Pair("hash", block.GetHash().GetHex()));
CMerkleTx txGen(block.vtx[0]);
txGen.SetMerkleBranch(&block);
result.push_back(Pair("confirmations", (int)txGen.GetDepthInMainChain()));
result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION)));
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
result.push_back(Pair("mint", ValueFromAmount(blockindex->nMint)));
result.push_back(Pair("time", (int64_t)block.GetBlockTime()));
result.push_back(Pair("nonce", (uint64_t)block.nNonce));
result.push_back(Pair("bits", HexBits(block.nBits)));
result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
result.push_back(Pair("blocktrust", leftTrim(blockindex->GetBlockTrust().GetHex(), '0')));
result.push_back(Pair("chaintrust", leftTrim(blockindex->nChainTrust.GetHex(), '0')));
if (blockindex->pprev)
result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
if (blockindex->pnext)
result.push_back(Pair("nextblockhash", blockindex->pnext->GetBlockHash().GetHex()));
result.push_back(Pair("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": "")));
result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex()));
result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit()));
result.push_back(Pair("modifier", strprintf("%016" PRIx64, blockindex->nStakeModifier)));
result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum)));
Array txinfo;
BOOST_FOREACH (const CTransaction& tx, block.vtx)
{
if (fPrintTransactionDetail)
{
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
string strHex = HexStr(ssTx.begin(), ssTx.end());
txinfo.push_back(strHex);
}
else
txinfo.push_back(tx.GetHash().GetHex());
}
result.push_back(Pair("tx", txinfo));
if ( block.IsProofOfStake() )
result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end())));
return result;
}
Value getbestblockhash(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getbestblockhash\n"
"Returns the hash of the best block in the longest block chain.");
return hashBestChain.GetHex();
}
Value getblockcount(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getblockcount\n"
"Returns the number of blocks in the longest block chain.");
return nBestHeight;
}
Value getdifficulty(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getdifficulty\n"
"Returns the difficulty as a multiple of the minimum difficulty.");
Object obj;
obj.push_back(Pair("proof-of-work", GetDifficulty()));
obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true))));
obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval));
return obj;
}
Value settxfee(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 1 || AmountFromValue(params[0]) < MIN_TX_FEE)
throw runtime_error(
"settxfee <amount>\n"
"<amount> is a real and is rounded to the nearest " + FormatMoney(MIN_TX_FEE));
nTransactionFee = AmountFromValue(params[0]);
nTransactionFee = (nTransactionFee / MIN_TX_FEE) * MIN_TX_FEE; // round to minimum fee
return true;
}
Value getrawmempool(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getrawmempool\n"
"Returns all transaction ids in memory pool.");
vector<uint256> vtxid;
mempool.queryHashes(vtxid);
Array a;
BOOST_FOREACH(const uint256& hash, vtxid)
a.push_back(hash.ToString());
return a;
}
Value getblockhash(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"getblockhash <index>\n"
"Returns hash of block in best-block-chain at <index>.");
int nHeight = params[0].get_int();
if (nHeight < 0 || nHeight > nBestHeight)
throw runtime_error("Block number out of range.");
CBlockIndex* pblockindex = FindBlockByHeight(nHeight);
return pblockindex->phashBlock->GetHex();
}
Value getblock(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getblock <hash> [txinfo]\n"
"txinfo optional to print more detailed tx info\n"
"Returns details of a block with given block-hash.");
std::string strHash = params[0].get_str();
uint256 hash(strHash);
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
block.ReadFromDisk(pblockindex, true);
return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}
Value getblockbynumber(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getblockbynumber <number> [txinfo]\n"
"txinfo optional to print more detailed tx info\n"
"Returns details of a block with given block-number.");
int nHeight = params[0].get_int();
if (nHeight < 0 || nHeight > nBestHeight)
throw runtime_error("Block number out of range.");
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
while (pblockindex->nHeight > nHeight)
pblockindex = pblockindex->pprev;
pblockindex = mapBlockIndex[*pblockindex->phashBlock];
block.ReadFromDisk(pblockindex, true);
return blockToJSON(block, pblockindex, params.size() > 1 ? params[1].get_bool() : false);
}
bool ExportBlock(const string& strBlockHash, const CDataStream& ssBlock)
{
boost::filesystem::path pathDest = GetDataDir() / strBlockHash;
if (boost::filesystem::is_directory(pathDest))
pathDest /= strBlockHash;
try {
boost::iostreams::stream_buffer<boost::iostreams::file_sink> buf(pathDest.string());
ostream exportStream(&buf);
exportStream << HexStr(ssBlock.begin(), ssBlock.end());
exportStream.flush();
printf("Successfully exported block to %s\n", pathDest.string().c_str());
return true;
} catch(const boost::filesystem::filesystem_error &e) {
printf("error exporting the block data %s (%s)\n", pathDest.string().c_str(), e.what());
return false;
}
}
Value dumpblock(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"dumpblock <hash> [destination]\n"
"Returns serialized contents of a block with given block-hash.");
std::string strHash = params[0].get_str();
uint256 hash(strHash);
if (mapBlockIndex.count(hash) == 0)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hash];
block.ReadFromDisk(pblockindex, true);
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
ssBlock << block;
if (params.size() > 1)
{
return ExportBlock(params[1].get_str(), ssBlock);
}
return HexStr(ssBlock.begin(), ssBlock.end());
}
Value dumpblockbynumber(const Array& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"dumpblockbynumber <number> [destination]\n"
"Returns serialized contents of a block with given block-number.");
int nHeight = params[0].get_int();
if (nHeight < 0 || nHeight > nBestHeight)
throw runtime_error("Block number out of range.");
CBlock block;
CBlockIndex* pblockindex = mapBlockIndex[hashBestChain];
while (pblockindex->nHeight > nHeight)
pblockindex = pblockindex->pprev;
pblockindex = mapBlockIndex[*pblockindex->phashBlock];
block.ReadFromDisk(pblockindex, true);
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
ssBlock << block;
if (params.size() > 1)
{
return ExportBlock(params[1].get_str(), ssBlock);
}
return HexStr(ssBlock.begin(), ssBlock.end());
}
// get information of sync-checkpoint
Value getcheckpoint(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getcheckpoint\n"
"Show info of synchronized checkpoint.\n");
Object result;
CBlockIndex* pindexCheckpoint;
result.push_back(Pair("synccheckpoint", Checkpoints::hashSyncCheckpoint.ToString().c_str()));
pindexCheckpoint = mapBlockIndex[Checkpoints::hashSyncCheckpoint];
result.push_back(Pair("height", pindexCheckpoint->nHeight));
result.push_back(Pair("timestamp", DateTimeStrFormat(pindexCheckpoint->GetBlockTime()).c_str()));
if (Checkpoints::checkpointMessage.vchSig.size() != 0)
{
Object msgdata;
CUnsignedSyncCheckpoint checkpoint;
CDataStream sMsg(Checkpoints::checkpointMessage.vchMsg, SER_NETWORK, PROTOCOL_VERSION);
sMsg >> checkpoint;
Object parsed; // message version and data (block hash)
parsed.push_back(Pair("version", checkpoint.nVersion));
parsed.push_back(Pair("hash", checkpoint.hashCheckpoint.GetHex().c_str()));
msgdata.push_back(Pair("parsed", parsed));
Object raw; // raw checkpoint message data
raw.push_back(Pair("data", HexStr(Checkpoints::checkpointMessage.vchMsg).c_str()));
raw.push_back(Pair("signature", HexStr(Checkpoints::checkpointMessage.vchSig).c_str()));
msgdata.push_back(Pair("raw", raw));
result.push_back(Pair("data", msgdata));
}
// Check that the block satisfies synchronized checkpoint
if (CheckpointsMode == Checkpoints::STRICT)
result.push_back(Pair("policy", "strict"));
if (CheckpointsMode == Checkpoints::ADVISORY)
result.push_back(Pair("policy", "advisory"));
if (CheckpointsMode == Checkpoints::PERMISSIVE)
result.push_back(Pair("policy", "permissive"));
if (mapArgs.count("-checkpointkey"))
result.push_back(Pair("checkpointmaster", true));
return result;
}