Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| // 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; | |
| } |