// 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 #include #include #include 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", blockindex->GetBlockHash().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 \n" " 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 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 \n" "Returns hash of block in best-block-chain at ."); 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 [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 [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 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 [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 [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; }