diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index d717f3e59..954441d15 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -4,7 +4,6 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "amount.h" -#include "base58.h" #include "chain.h" #include "chainparams.h" #include "checkpoints.h" @@ -14,23 +13,16 @@ #include "policy/policy.h" #include "primitives/transaction.h" #include "rpcserver.h" -#include "script/script.h" -#include "script/script_error.h" -#include "script/sign.h" -#include "script/standard.h" #include "streams.h" #include "sync.h" #include "txmempool.h" #include "util.h" #include "utilstrencodings.h" -#include "hash.h" #include #include -#include // boost::thread::interrupt - using namespace std; extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); @@ -45,7 +37,7 @@ double GetDifficulty(const CBlockIndex* blockindex) if (chainActive.Tip() == NULL) return 1.0; else - blockindex = GetLastBlockIndex(chainActive.Tip(), false); + blockindex = chainActive.Tip(); } int nShift = (blockindex->nBits >> 24) & 0xff; @@ -78,171 +70,26 @@ UniValue blockheaderToJSON(const CBlockIndex* blockindex) result.push_back(Pair("confirmations", confirmations)); result.push_back(Pair("height", blockindex->nHeight)); result.push_back(Pair("version", blockindex->nVersion)); - result.push_back(Pair("versionHex", strprintf("%08x", blockindex->nVersion))); result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); result.push_back(Pair("time", (int64_t)blockindex->nTime)); - result.push_back(Pair("mediantime", (int64_t)blockindex->GetPastTimeLimit())); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce)); result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); - result.push_back(Pair("modifier", blockindex->nStakeModifier.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; -} - -UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) -{ - UniValue result(UniValue::VOBJ); - result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) { - confirmations = chainActive.Height() - blockindex->nHeight + 1; - } else { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block is an orphan"); - } - result.push_back(Pair("confirmations", confirmations)); - 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())); - - UniValue deltas(UniValue::VARR); - - for (unsigned int i = 0; i < block.vtx.size(); i++) { - const CTransaction &tx = block.vtx[i]; - const uint256 txhash = tx.GetHash(); - - UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", txhash.GetHex())); - entry.push_back(Pair("index", (int)i)); - - UniValue inputs(UniValue::VARR); - - if (!tx.IsCoinBase()) { - - for (size_t j = 0; j < tx.vin.size(); j++) { - const CTxIn input = tx.vin[j]; - - UniValue delta(UniValue::VOBJ); - - CSpentIndexValue spentInfo; - CSpentIndexKey spentKey(input.prevout.hash, input.prevout.n); - - if (GetSpentIndex(spentKey, spentInfo)) { - if (spentInfo.addressType == 1) { - delta.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString())); - } else if (spentInfo.addressType == 2) { - delta.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString())); - } else { - continue; - } - delta.push_back(Pair("satoshis", -1 * spentInfo.satoshis)); - delta.push_back(Pair("index", (int)j)); - delta.push_back(Pair("prevtxid", input.prevout.hash.GetHex())); - delta.push_back(Pair("prevout", (int)input.prevout.n)); - - inputs.push_back(delta); - } else { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Spent information not available"); - } - - } - } - - entry.push_back(Pair("inputs", inputs)); - - UniValue outputs(UniValue::VARR); - - for (unsigned int k = 0; k < tx.vout.size(); k++) { - const CTxOut &out = tx.vout[k]; - - UniValue delta(UniValue::VOBJ); - - if (out.scriptPubKey.IsPayToScriptHash()) { - vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); - delta.push_back(Pair("address", CBitcoinAddress(CScriptID(uint160(hashBytes))).ToString())); - - } else if (out.scriptPubKey.IsPayToPublicKeyHash()) { - vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); - delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString())); - } else { - continue; - } - - delta.push_back(Pair("satoshis", out.nValue)); - delta.push_back(Pair("index", (int)k)); - - outputs.push_back(delta); - } - - entry.push_back(Pair("outputs", outputs)); - deltas.push_back(entry); - - } - result.push_back(Pair("deltas", deltas)); - result.push_back(Pair("time", block.GetBlockTime())); - result.push_back(Pair("mediantime", (int64_t)blockindex->GetPastTimeLimit())); - result.push_back(Pair("nonce", (uint64_t)block.nNonce)); - result.push_back(Pair("bits", strprintf("%08x", 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; -} - -double GetPoSKernelPS() -{ - int nPoSInterval = 72; - double dStakeKernelsTriedAvg = 0; - int nStakesHandled = 0, nStakesTime = 0; - - CBlockIndex* pindex = chainActive.Tip();; - CBlockIndex* pindexPrevStake = NULL; - - while (pindex && nStakesHandled < nPoSInterval) - { - if (pindex->IsProofOfStake()) - { - if (pindexPrevStake) - { - dStakeKernelsTriedAvg += GetDifficulty(pindexPrevStake) * 4294967296.0; - nStakesTime += pindexPrevStake->nTime - pindex->nTime; - nStakesHandled++; - } - pindexPrevStake = pindex; - } - - pindex = pindex->pprev; - } - - double result = 0; - - if (nStakesTime) - result = dStakeKernelsTriedAvg / nStakesTime; - - result *= 16; - return result; } UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) { UniValue result(UniValue::VOBJ); - result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); + result.push_back(Pair("hash", block.GetHash().GetHex())); int confirmations = -1; // Only report confirmations if the block is on the main chain if (chainActive.Contains(blockindex)) @@ -251,7 +98,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx 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("versionHex", strprintf("%08x", block.nVersion))); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); UniValue txs(UniValue::VARR); BOOST_FOREACH(const CTransaction&tx, block.vtx) @@ -267,7 +113,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); - result.push_back(Pair("mediantime", (int64_t)blockindex->GetPastTimeLimit())); + result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); result.push_back(Pair("nonce", (uint64_t)block.nNonce)); result.push_back(Pair("bits", strprintf("%08x", block.nBits))); result.push_back(Pair("difficulty", GetDifficulty(blockindex))); @@ -278,10 +124,6 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx CBlockIndex *pnext = chainActive.Next(blockindex); if (pnext) result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); - result.push_back(Pair("flags", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work")); - result.push_back(Pair("modifier", blockindex->nStakeModifier.GetHex())); - if (block.IsProofOfStake()) - result.push_back(Pair("signature", HexStr(block.vchBlockSig.begin(), block.vchBlockSig.end()))); return result; } @@ -321,26 +163,19 @@ UniValue getbestblockhash(const UniValue& params, bool fHelp) UniValue getdifficulty(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 0) - throw runtime_error( - "getdifficulty\n" - "\nReturns the difficulty as a multiple of the minimum difficulty.\n" - "\nResult:\n" - "{ (json object)\n" - " \"proof-of-work\" : n.nnn, (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n" - " \"proof-of-stake\" : n.nnn (numeric) the proof-of-stake difficulty as a multiple of the minimum difficulty.\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("getdifficulty", "") - + HelpExampleRpc("getdifficulty", "") - ); + if (fHelp || params.size() != 0) + throw runtime_error( + "getdifficulty\n" + "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n" + "\nResult:\n" + "n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n" + "\nExamples:\n" + + HelpExampleCli("getdifficulty", "") + + HelpExampleRpc("getdifficulty", "") + ); LOCK(cs_main); - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("proof-of-work", GetDifficulty())); - obj.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(chainActive.Tip(), true)))); - return obj; + return GetDifficulty(); } UniValue mempoolToJSON(bool fVerbose = false) @@ -431,6 +266,8 @@ UniValue getrawmempool(const UniValue& params, bool fHelp) + HelpExampleRpc("getrawmempool", "true") ); + LOCK(cs_main); + bool fVerbose = false; if (params.size() > 0) fVerbose = params[0].get_bool(); @@ -438,102 +275,6 @@ UniValue getrawmempool(const UniValue& params, bool fHelp) return mempoolToJSON(fVerbose); } -UniValue getblockdeltas(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error(""); - - std::string strHash = params[0].get_str(); - uint256 hash(uint256S(strHash)); - - if (mapBlockIndex.count(hash) == 0) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - - CBlock block; - CBlockIndex* pblockindex = mapBlockIndex[hash]; - - if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); - - if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - - return blockToDeltasJSON(block, pblockindex); -} - -UniValue getblockhashes(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 2) - throw runtime_error( - "getblockhashes timestamp\n" - "\nReturns array of hashes of blocks within the timestamp range provided.\n" - "\nArguments:\n" - "1. high (numeric, required) The newer block timestamp\n" - "2. low (numeric, required) The older block timestamp\n" - "3. options (string, required) A json object\n" - " {\n" - " \"noOrphans\":true (boolean) will only include blocks on the main chain\n" - " \"logicalTimes\":true (boolean) will include logical timestamps with hashes\n" - " }\n" - "\nResult:\n" - "[\n" - " \"hash\" (string) The block hash\n" - "]\n" - "[\n" - " {\n" - " \"blockhash\": (string) The block hash\n" - " \"logicalts\": (numeric) The logical timestamp\n" - " }\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("getblockhashes", "1231614698 1231024505") - + HelpExampleRpc("getblockhashes", "1231614698, 1231024505") - + HelpExampleCli("getblockhashes", "1231614698 1231024505 '{\"noOrphans\":false, \"logicalTimes\":true}'") - ); - - unsigned int high = params[0].get_int(); - unsigned int low = params[1].get_int(); - bool fActiveOnly = false; - bool fLogicalTS = false; - - if (params.size() > 2) { - if (params[2].isObject()) { - UniValue noOrphans = find_value(params[2].get_obj(), "noOrphans"); - UniValue returnLogical = find_value(params[2].get_obj(), "logicalTimes"); - - if (noOrphans.isBool()) - fActiveOnly = noOrphans.get_bool(); - - if (returnLogical.isBool()) - fLogicalTS = returnLogical.get_bool(); - } - } - - std::vector > blockHashes; - - if (fActiveOnly) - LOCK(cs_main); - - if (!GetTimestampIndex(high, low, fActiveOnly, blockHashes)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for block hashes"); - } - - UniValue result(UniValue::VARR); - - for (std::vector >::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) { - if (fLogicalTS) { - UniValue item(UniValue::VOBJ); - item.push_back(Pair("blockhash", it->first.GetHex())); - item.push_back(Pair("logicalts", (int)it->second)); - result.push_back(item); - } else { - result.push_back(it->first.GetHex()); - } - } - - return result; -} - UniValue getblockhash(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) @@ -575,7 +316,6 @@ UniValue getblockheader(const UniValue& params, bool fHelp) " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" - " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" " \"mediantime\" : ttt, (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n" @@ -635,7 +375,6 @@ UniValue getblock(const UniValue& params, bool fHelp) " \"size\" : n, (numeric) The block size\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" - " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n" " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" " \"tx\" : [ (array of string) The transaction ids\n" " \"transactionid\" (string) The transaction id\n" @@ -689,60 +428,6 @@ UniValue getblock(const UniValue& params, bool fHelp) return blockToJSON(block, pblockindex); } -struct CCoinsStats -{ - int nHeight; - uint256 hashBlock; - uint64_t nTransactions; - uint64_t nTransactionOutputs; - uint64_t nSerializedSize; - uint256 hashSerialized; - CAmount nTotalAmount; - - CCoinsStats() : nHeight(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), nTotalAmount(0) {} -}; - -//! Calculate statistics about the unspent transaction output set -static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats) -{ - boost::scoped_ptr pcursor(view->Cursor()); - - CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - stats.hashBlock = pcursor->GetBestBlock(); - { - LOCK(cs_main); - stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight; - } - ss << stats.hashBlock; - CAmount nTotalAmount = 0; - while (pcursor->Valid()) { - boost::this_thread::interruption_point(); - uint256 key; - CCoins coins; - if (pcursor->GetKey(key) && pcursor->GetValue(coins)) { - stats.nTransactions++; - ss << key; - for (unsigned int i=0; iGetValueSize(); - ss << VARINT(0); - } else { - return error("%s: unable to read value", __func__); - } - pcursor->Next(); - } - stats.hashSerialized = ss.GetHash(); - stats.nTotalAmount = nTotalAmount; - return true; -} - UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -769,7 +454,7 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) CCoinsStats stats; FlushStateToDisk(); - if (GetUTXOStats(pcoinsTip, stats)) { + if (pcoinsTip->GetStats(stats)) { ret.push_back(Pair("height", (int64_t)stats.nHeight)); ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); ret.push_back(Pair("transactions", (int64_t)stats.nTransactions)); @@ -808,7 +493,6 @@ UniValue gettxout(const UniValue& params, bool fHelp) " },\n" " \"version\" : n, (numeric) The version\n" " \"coinbase\" : true|false (boolean) Coinbase or not\n" - " \"coinstake\" : true|false (boolean) Coinstake or not\n" "}\n" "\nExamples:\n" @@ -858,7 +542,6 @@ UniValue gettxout(const UniValue& params, bool fHelp) ret.push_back(Pair("scriptPubKey", o)); ret.push_back(Pair("version", coins.nVersion)); ret.push_back(Pair("coinbase", coins.fCoinBase)); - ret.push_back(Pair("coinstake", coins.fCoinStake)); return ret; } @@ -921,35 +604,6 @@ static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* return rv; } -static UniValue BIP9SoftForkDesc(const Consensus::Params& consensusParams, Consensus::DeploymentPos id) -{ - UniValue rv(UniValue::VOBJ); - const ThresholdState thresholdState = VersionBitsTipState(consensusParams, id); - switch (thresholdState) { - case THRESHOLD_DEFINED: rv.push_back(Pair("status", "defined")); break; - case THRESHOLD_STARTED: rv.push_back(Pair("status", "started")); break; - case THRESHOLD_LOCKED_IN: rv.push_back(Pair("status", "locked_in")); break; - case THRESHOLD_ACTIVE: rv.push_back(Pair("status", "active")); break; - case THRESHOLD_FAILED: rv.push_back(Pair("status", "failed")); break; - } - if (THRESHOLD_STARTED == thresholdState) - { - rv.push_back(Pair("bit", consensusParams.vDeployments[id].bit)); - } - rv.push_back(Pair("startTime", consensusParams.vDeployments[id].nStartTime)); - rv.push_back(Pair("timeout", consensusParams.vDeployments[id].nTimeout)); - return rv; -} - -void BIP9SoftForkDescPushBack(UniValue& bip9_softforks, const std::string &name, const Consensus::Params& consensusParams, Consensus::DeploymentPos id) -{ - // Deployments with timeout value of 0 are hidden. - // A timeout value of 0 guarantees a softfork will never be activated. - // This is used when softfork codes are merged without specifying the deployment schedule. - if (consensusParams.vDeployments[id].nTimeout > 0) - bip9_softforks.push_back(Pair(name, BIP9SoftForkDesc(consensusParams, id))); -} - UniValue getblockchaininfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -962,10 +616,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n" " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n" - " \"difficulty\": { (json object)\n" - " \"proof-of-work\": xxxxxx, (numeric) the current proof-of-work difficulty\n" - " \"proof-of-stake\": xxxxxx (numeric) the current proof-of-stake difficulty\n" - " },\n" + " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" " \"mediantime\": xxxxxx, (numeric) median time for the current best block\n" " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n" " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n" @@ -983,15 +634,7 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) " },\n" " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" " }, ...\n" - " ],\n" - " \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n" - " \"xxxx\" : { (string) name of the softfork\n" - " \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n" - " \"bit\": xx, (numeric) the bit, 0-28, in the block version field used to signal this soft fork\n" - " \"startTime\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n" - " \"timeout\": xx (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n" - " }\n" - " }\n" + " ]\n" "}\n" "\nExamples:\n" + HelpExampleCli("getblockchaininfo", "") @@ -1000,17 +643,13 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) LOCK(cs_main); - UniValue diff(UniValue::VOBJ); - diff.push_back(Pair("proof-of-work", (double)GetDifficulty())); - diff.push_back(Pair("proof-of-stake", (double)GetDifficulty(GetLastBlockIndex(chainActive.Tip(), true)))); - UniValue obj(UniValue::VOBJ); obj.push_back(Pair("chain", Params().NetworkIDString())); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); obj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); - obj.push_back(Pair("difficulty", diff)); - obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetPastTimeLimit())); + obj.push_back(Pair("difficulty", (double)GetDifficulty())); + obj.push_back(Pair("mediantime", (int64_t)chainActive.Tip()->GetMedianTimePast())); obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip()))); obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); @@ -1018,10 +657,10 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp) const Consensus::Params& consensusParams = Params().GetConsensus(); CBlockIndex* tip = chainActive.Tip(); UniValue softforks(UniValue::VARR); - UniValue bip9_softforks(UniValue::VOBJ); - BIP9SoftForkDescPushBack(bip9_softforks, "csv", consensusParams, Consensus::DEPLOYMENT_CSV); + softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); + softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); + softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams)); obj.push_back(Pair("softforks", softforks)); - obj.push_back(Pair("bip9_softforks", bip9_softforks)); if (fPruneMode) { @@ -1084,30 +723,17 @@ UniValue getchaintips(const UniValue& params, bool fHelp) LOCK(cs_main); - /* - * Idea: the set of chain tips is chainActive.tip, plus orphan blocks which do not have another orphan building off of them. - * Algorithm: - * - Make one pass through mapBlockIndex, picking out the orphan blocks, and also storing a set of the orphan block's pprev pointers. - * - Iterate through the orphan blocks. If the block isn't pointed to by another orphan, it is a chain tip. - * - add chainActive.Tip() - */ + /* Build up a list of chain tips. We start with the list of all + known blocks, and successively remove blocks that appear as pprev + of another block. */ std::set setTips; - std::set setOrphans; - std::set setPrevs; - + BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex) + setTips.insert(item.second); BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex) { - if (!chainActive.Contains(item.second)) { - setOrphans.insert(item.second); - setPrevs.insert(item.second->pprev); - } - } - - for (std::set::iterator it = setOrphans.begin(); it != setOrphans.end(); ++it) - { - if (setPrevs.erase(*it) == 0) { - setTips.insert(*it); - } + const CBlockIndex* pprev = item.second->pprev; + if (pprev) + setTips.erase(pprev); } // Always report the currently active tip. diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index b7ee47c16..958c817d6 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -14,16 +14,11 @@ #include "miner.h" #include "net.h" #include "pow.h" -#include "pos.h" #include "rpcserver.h" #include "txmempool.h" -#include "timedata.h" #include "util.h" #include "utilstrencodings.h" #include "validationinterface.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif #include @@ -73,7 +68,7 @@ UniValue GetNetworkHashPS(int lookup, int height) { arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork; int64_t timeDiff = maxTime - minTime; - return workDiff.getdouble() / timeDiff; + return (int64_t)(workDiff.getdouble() / timeDiff); } UniValue getnetworkhashps(const UniValue& params, bool fHelp) @@ -162,7 +157,7 @@ UniValue generate(const UniValue& params, bool fHelp) UniValue blockHashes(UniValue::VARR); while (nHeight < nHeightEnd) { - auto_ptr pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript, 0, false)); + auto_ptr pblocktemplate(CreateNewBlock(Params(), coinbaseScript->reserveScript)); if (!pblocktemplate.get()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); CBlock *pblock = &pblocktemplate->block; @@ -170,17 +165,16 @@ UniValue generate(const UniValue& params, bool fHelp) LOCK(cs_main); IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } - while (!CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) { + while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { // Yes, there is a chance every nonce could fail to satisfy the -regtest // target -- 1 in 2^(2^32). That ain't gonna happen. ++pblock->nNonce; } CValidationState state; - uint256 hash = pblock->GetHash(); - if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, hash)) + if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL)) throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; - blockHashes.push_back(hash.GetHex()); + blockHashes.push_back(pblock->GetHash().GetHex()); //mark script as important because it was used at least for one coinbase output coinbaseScript->KeepScript(); @@ -274,42 +268,6 @@ UniValue getmininginfo(const UniValue& params, bool fHelp) return obj; } -UniValue getstakinginfo(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getstakinginfo\n" - "Returns an object containing staking-related information."); - - uint64_t nWeight = 0; - if (pwalletMain) - nWeight = pwalletMain->GetStakeWeight(); - - uint64_t nNetworkWeight = GetPoSKernelPS(); - bool staking = nLastCoinStakeSearchInterval && nWeight; - uint64_t nExpectedTime = staking ? 1.0455 * 64 * nNetworkWeight / nWeight : 0; - - UniValue obj(UniValue::VOBJ); - - obj.push_back(Pair("enabled", GetBoolArg("-staking", true))); - obj.push_back(Pair("staking", staking)); - obj.push_back(Pair("errors", GetWarnings("statusbar"))); - - obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); - obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); - obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - - obj.push_back(Pair("difficulty", GetDifficulty(GetLastBlockIndex(chainActive.Tip(), true)))); - obj.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval)); - - obj.push_back(Pair("weight", (uint64_t)nWeight)); - obj.push_back(Pair("netstakeweight", (uint64_t)nNetworkWeight)); - - obj.push_back(Pair("expectedtime", nExpectedTime)); - - return obj; -} - // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts UniValue prioritisetransaction(const UniValue& params, bool fHelp) @@ -468,7 +426,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (block.hashPrevBlock != pindexPrev->GetBlockHash()) return "inconclusive-not-best-prevblk"; CValidationState state; - TestBlockValidity(state, Params(), block, pindexPrev, false, true, true); + TestBlockValidity(state, Params(), block, pindexPrev, false, true); return BIP22ValidationResult(state); } } @@ -482,9 +440,6 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) if (IsInitialBlockDownload()) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Bitcoin is downloading blocks..."); - if (chainActive.Tip()->nHeight > Params().GetConsensus().nLastPOWBlock) - throw JSONRPCError(RPC_MISC_ERROR, "No more PoW blocks"); - static unsigned int nTransactionsUpdatedLast; if (!lpval.isNull()) @@ -555,7 +510,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) pblocktemplate = NULL; } CScript scriptDummy = CScript() << OP_TRUE; - pblocktemplate = CreateNewBlock(Params(), scriptDummy, 0, false); + pblocktemplate = CreateNewBlock(Params(), scriptDummy); if (!pblocktemplate) throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory"); @@ -623,7 +578,7 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp) result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); - result.push_back(Pair("mintime", (int64_t)pindexPrev->GetPastTimeLimit()+1)); + result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); result.push_back(Pair("mutable", aMutable)); result.push_back(Pair("noncerange", "00000000ffffffff")); result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS)); @@ -695,9 +650,9 @@ UniValue submitblock(const UniValue& params, bool fHelp) } CValidationState state; - submitblock_StateCatcher sc(hash); + submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, hash); + bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { @@ -745,128 +700,6 @@ UniValue estimatefee(const UniValue& params, bool fHelp) return ValueFromAmount(feeRate.GetFeePerK()); } -UniValue checkkernel(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "checkkernel [{\"txid\":txid,\"vout\":n},...] [createblocktemplate=false]\n" - "Check if one of given inputs is a kernel input at the moment.\n" - ); - - RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VBOOL)); - - UniValue inputs = params[0].get_array(); - bool fCreateBlockTemplate = params.size() > 1 ? params[1].get_bool() : false; - - if (vNodes.empty()) - throw JSONRPCError(-9, "BlackCoin is not connected!"); - - if (IsInitialBlockDownload()) - throw JSONRPCError(-10, "BlackCoin is downloading blocks..."); - - COutPoint kernel; - CBlockIndex* pindexPrev = chainActive.Tip(); - CBlockHeader blockHeader = pindexPrev->GetBlockHeader(); - unsigned int nBits = GetNextTargetRequired(pindexPrev, &blockHeader, true, Params().GetConsensus()); - int64_t nTime = GetAdjustedTime(); - nTime &= ~Params().GetConsensus().nStakeTimestampMask; - - for (unsigned int idx = 0; idx < inputs.size(); idx++) { - const UniValue& input = inputs[idx]; - const UniValue& o = input.get_obj(); - - const UniValue& txid_v = find_value(o, "txid"); - if (!txid_v.isStr()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key"); - string txid = txid_v.get_str(); - if (!IsHex(txid)) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid"); - - const UniValue& vout_v = find_value(o, "vout"); - if (!vout_v.isNum()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); - int nOutput = vout_v.get_int(); - if (nOutput < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); - - COutPoint cInput(uint256S(txid), nOutput); - if (CheckKernel(pindexPrev, nBits, nTime, cInput)) - { - kernel = cInput; - break; - } - } - - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("found", !kernel.IsNull())); - - if (kernel.IsNull()) - return result; - - UniValue oKernel(UniValue::VOBJ); - oKernel.push_back(Pair("txid", kernel.hash.GetHex())); - oKernel.push_back(Pair("vout", (int64_t)kernel.n)); - oKernel.push_back(Pair("time", nTime)); - result.push_back(Pair("kernel", oKernel)); - - if (!fCreateBlockTemplate) - return result; - - int64_t nFees; - if (!pwalletMain->IsLocked()) - pwalletMain->TopUpKeyPool(); - - CReserveKey pMiningKey(pwalletMain); - auto_ptr pblocktemplate(CreateNewBlock(Params(), pMiningKey.reserveScript, &nFees, true)); - if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); - - CBlock *pblock = &pblocktemplate->block; - pblock->nTime = pblock->vtx[0].nTime = nTime; - - CDataStream ss(SER_DISK, PROTOCOL_VERSION); - ss << *pblock; - - result.push_back(Pair("blocktemplate", HexStr(ss.begin(), ss.end()))); - result.push_back(Pair("blocktemplatefees", nFees)); - - CPubKey pubkey; - if (!pMiningKey.GetReservedKey(pubkey)) - throw JSONRPCError(RPC_MISC_ERROR, "GetReservedKey failed"); - - result.push_back(Pair("blocktemplatesignkey", HexStr(pubkey))); - - return result; - if (fHelp || params.size() != 1) - throw runtime_error( - "estimatefee nblocks\n" - "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" - "confirmation within nblocks blocks.\n" - "\nArguments:\n" - "1. nblocks (numeric)\n" - "\nResult:\n" - "n (numeric) estimated fee-per-kilobyte\n" - "\n" - "A negative value is returned if not enough transactions and blocks\n" - "have been observed to make an estimate.\n" - "\nExample:\n" - + HelpExampleCli("estimatefee", "6") - ); - - RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); - - int nBlocks = params[0].get_int(); - if (nBlocks < 1) - nBlocks = 1; - - CFeeRate feeRate = mempool.estimateFee(nBlocks); - if (feeRate == CFeeRate(0)) - return -1.0; - - return ValueFromAmount(feeRate.GetFeePerK()); -} - UniValue estimatepriority(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1)