// Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2013 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 "bitcoinrpc.h" #include "main.h" #include "sync.h" #include #include "json/json_spirit_value.h" using namespace json_spirit; using namespace std; void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex); double GetDifficulty(const CBlockIndex* blockindex) { // Floating point number that is a multiple of the minimum difficulty, // minimum difficulty = 1.0. if (blockindex == NULL) { if (chainActive.Tip() == NULL) return 1.0; else blockindex = chainActive.Tip(); } 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; } Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex) { 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())); Array txs; BOOST_FOREACH(const CTransaction&tx, block.vtx) txs.push_back(tx.GetHash().GetHex()); result.push_back(Pair("tx", txs)); result.push_back(Pair("time", (boost::int64_t)block.GetBlockTime())); result.push_back(Pair("nonce", (boost::uint64_t)block.nNonce)); result.push_back(Pair("bits", HexBits(block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); if (blockindex->pprev) result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); return result; } 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 chainActive.Height(); } Value getbestblockhash(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getbestblockhash\n" "Returns the hash of the best (tip) block in the longest block chain."); return chainActive.Tip()->GetBlockHash().GetHex(); } Value getdifficulty(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "getdifficulty\n" "Returns the proof-of-work difficulty as a multiple of the minimum difficulty."); return GetDifficulty(); } Value settxfee(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 1) throw runtime_error( "settxfee \n" " is a real and is rounded to the nearest 0.00000001 btc per kb"); // Amount int64_t nAmount = 0; if (params[0].get_real() != 0.0) nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts nTransactionFee = nAmount; 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 > chainActive.Height()) throw runtime_error("Block number out of range."); CBlockIndex* pblockindex = chainActive[nHeight]; return pblockindex->GetBlockHash().GetHex(); } Value getblock(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getblock [verbose=true]\n" "If verbose is false, returns a string that is serialized, hex-encoded data for block .\n" "If verbose is true, returns an Object with information about block ." ); std::string strHash = params[0].get_str(); uint256 hash(strHash); bool fVerbose = true; if (params.size() > 1) fVerbose = params[1].get_bool(); if (mapBlockIndex.count(hash) == 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); CBlock block; CBlockIndex* pblockindex = mapBlockIndex[hash]; ReadBlockFromDisk(block, pblockindex); if (!fVerbose) { CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); ssBlock << block; std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); return strHex; } return blockToJSON(block, pblockindex); } Value gettxoutsetinfo(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( "gettxoutsetinfo\n" "Returns statistics about the unspent transaction output set."); Object ret; CCoinsStats stats; if (pcoinsTip->GetStats(stats)) { ret.push_back(Pair("height", (boost::int64_t)stats.nHeight)); ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); ret.push_back(Pair("transactions", (boost::int64_t)stats.nTransactions)); ret.push_back(Pair("txouts", (boost::int64_t)stats.nTransactionOutputs)); ret.push_back(Pair("bytes_serialized", (boost::int64_t)stats.nSerializedSize)); ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex())); ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount))); } return ret; } Value gettxout(const Array& params, bool fHelp) { if (fHelp || params.size() < 2 || params.size() > 3) throw runtime_error( "gettxout [includemempool=true]\n" "Returns details about an unspent transaction output."); Object ret; std::string strHash = params[0].get_str(); uint256 hash(strHash); int n = params[1].get_int(); bool fMempool = true; if (params.size() > 2) fMempool = params[2].get_bool(); CCoins coins; if (fMempool) { LOCK(mempool.cs); CCoinsViewMemPool view(*pcoinsTip, mempool); if (!view.GetCoins(hash, coins)) return Value::null; mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool } else { if (!pcoinsTip->GetCoins(hash, coins)) return Value::null; } if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull()) return Value::null; ret.push_back(Pair("bestblock", pcoinsTip->GetBestBlock()->GetBlockHash().GetHex())); if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT) ret.push_back(Pair("confirmations", 0)); else ret.push_back(Pair("confirmations", pcoinsTip->GetBestBlock()->nHeight - coins.nHeight + 1)); ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); Object o; ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); ret.push_back(Pair("scriptPubKey", o)); ret.push_back(Pair("version", coins.nVersion)); ret.push_back(Pair("coinbase", coins.fCoinBase)); return ret; } Value verifychain(const Array& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( "verifychain [check level] [num blocks]\n" "Verifies blockchain database."); int nCheckLevel = GetArg("-checklevel", 3); int nCheckDepth = GetArg("-checkblocks", 288); if (params.size() > 0) nCheckLevel = params[0].get_int(); if (params.size() > 1) nCheckDepth = params[1].get_int(); return VerifyDB(nCheckLevel, nCheckDepth); }