diff options
Diffstat (limited to 'src/rpcmining.cpp')
| -rw-r--r-- | src/rpcmining.cpp | 279 |
1 files changed, 136 insertions, 143 deletions
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 17552bc38..9c6fb10af 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -5,27 +5,25 @@ #include "amount.h" #include "chainparams.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" #include "core_io.h" #include "init.h" -#include "net.h" #include "main.h" #include "miner.h" +#include "net.h" #include "pow.h" #include "rpcserver.h" #include "util.h" -#ifdef ENABLE_WALLET -#include "db.h" -#include "wallet.h" -#endif +#include "validationinterface.h" #include <stdint.h> #include <boost/assign/list_of.hpp> +#include <boost/shared_ptr.hpp> -#include "json/json_spirit_utils.h" -#include "json/json_spirit_value.h" +#include "univalue/univalue.h" -using namespace json_spirit; using namespace std; /** @@ -33,7 +31,7 @@ using namespace std; * or from the last difficulty change if 'lookup' is nonpositive. * If 'height' is nonnegative, compute the estimate at the time when a given block was found. */ -Value GetNetworkHashPS(int lookup, int height) { +UniValue GetNetworkHashPS(int lookup, int height) { CBlockIndex *pb = chainActive.Tip(); if (height >= 0 && height < chainActive.Height()) @@ -44,7 +42,7 @@ Value GetNetworkHashPS(int lookup, int height) { // If lookup is -1, then use blocks since last difficulty change. if (lookup <= 0) - lookup = pb->nHeight % 2016 + 1; + lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1; // If lookup is larger than chain, then set it to chain length. if (lookup > pb->nHeight) @@ -64,13 +62,13 @@ Value GetNetworkHashPS(int lookup, int height) { if (minTime == maxTime) return 0; - uint256 workDiff = pb->nChainWork - pb0->nChainWork; + arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork; int64_t timeDiff = maxTime - minTime; return (int64_t)(workDiff.getdouble() / timeDiff); } -Value getnetworkhashps(const Array& params, bool fHelp) +UniValue getnetworkhashps(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 2) throw runtime_error( @@ -88,11 +86,11 @@ Value getnetworkhashps(const Array& params, bool fHelp) + HelpExampleRpc("getnetworkhashps", "") ); + LOCK(cs_main); return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1); } -#ifdef ENABLE_WALLET -Value getgenerate(const Array& params, bool fHelp) +UniValue getgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -107,11 +105,76 @@ Value getgenerate(const Array& params, bool fHelp) + HelpExampleRpc("getgenerate", "") ); + LOCK(cs_main); return GetBoolArg("-gen", false); } +UniValue generate(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 1) + throw runtime_error( + "generate numblocks\n" + "\nMine blocks immediately (before the RPC call returns)\n" + "\nNote: this function can only be used on the regtest network\n" + "1. numblocks (numeric) How many blocks are generated immediately.\n" + "\nResult\n" + "[ blockhashes ] (array) hashes of blocks generated\n" + "\nExamples:\n" + "\nGenerate 11 blocks\n" + + HelpExampleCli("generate", "11") + ); + + if (!Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest"); + + int nHeightStart = 0; + int nHeightEnd = 0; + int nHeight = 0; + int nGenerate = params[0].get_int(); + + boost::shared_ptr<CReserveScript> coinbaseScript; + GetMainSignals().ScriptForMining(coinbaseScript); + + //throw an error if no script was provided + if (!coinbaseScript->reserveScript.size()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)"); + + { // Don't keep cs_main locked + LOCK(cs_main); + nHeightStart = chainActive.Height(); + nHeight = nHeightStart; + nHeightEnd = nHeightStart+nGenerate; + } + unsigned int nExtraNonce = 0; + UniValue blockHashes(UniValue::VARR); + while (nHeight < nHeightEnd) + { + auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript)); + if (!pblocktemplate.get()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); + CBlock *pblock = &pblocktemplate->block; + { + LOCK(cs_main); + IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); + } + 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; + if (!ProcessNewBlock(state, NULL, pblock, true, NULL)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); + ++nHeight; + blockHashes.push_back(pblock->GetHash().GetHex()); + + //mark script as important because it was used at least for one coinbase output + coinbaseScript->KeepScript(); + } + return blockHashes; +} -Value setgenerate(const Array& params, bool fHelp) +UniValue setgenerate(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -122,9 +185,6 @@ Value setgenerate(const Array& params, bool fHelp) "\nArguments:\n" "1. generate (boolean, required) Set to true to turn on generation, off to turn off.\n" "2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n" - " Note: in -regtest mode, genproclimit controls how many blocks are generated immediately.\n" - "\nResult\n" - "[ blockhashes ] (array, -regtest only) hashes of blocks generated\n" "\nExamples:\n" "\nSet the generation on with a limit of one processor\n" + HelpExampleCli("setgenerate", "true 1") + @@ -136,8 +196,8 @@ Value setgenerate(const Array& params, bool fHelp) + HelpExampleRpc("setgenerate", "true, 1") ); - if (pwalletMain == NULL) - throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)"); + if (Params().MineBlocksOnDemand()) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network"); bool fGenerate = true; if (params.size() > 0) @@ -151,78 +211,14 @@ Value setgenerate(const Array& params, bool fHelp) fGenerate = false; } - // -regtest mode: don't return until nGenProcLimit blocks are generated - if (fGenerate && Params().MineBlocksOnDemand()) - { - int nHeightStart = 0; - int nHeightEnd = 0; - int nHeight = 0; - int nGenerate = (nGenProcLimit > 0 ? nGenProcLimit : 1); - CReserveKey reservekey(pwalletMain); + mapArgs["-gen"] = (fGenerate ? "1" : "0"); + mapArgs ["-genproclimit"] = itostr(nGenProcLimit); + GenerateBitcoins(fGenerate, nGenProcLimit, Params()); - { // Don't keep cs_main locked - LOCK(cs_main); - nHeightStart = chainActive.Height(); - nHeight = nHeightStart; - nHeightEnd = nHeightStart+nGenerate; - } - unsigned int nExtraNonce = 0; - Array blockHashes; - while (nHeight < nHeightEnd) - { - auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey)); - if (!pblocktemplate.get()) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty"); - CBlock *pblock = &pblocktemplate->block; - { - LOCK(cs_main); - IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); - } - while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits)) { - // 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; - if (!ProcessNewBlock(state, NULL, pblock)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); - ++nHeight; - blockHashes.push_back(pblock->GetHash().GetHex()); - } - return blockHashes; - } - else // Not -regtest: start generate thread, return immediately - { - mapArgs["-gen"] = (fGenerate ? "1" : "0"); - mapArgs ["-genproclimit"] = itostr(nGenProcLimit); - GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit); - } - - return Value::null; + return NullUniValue; } -Value gethashespersec(const Array& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "gethashespersec\n" - "\nReturns a recent hashes per second performance measurement while generating.\n" - "See the getgenerate and setgenerate calls to turn generation on and off.\n" - "\nResult:\n" - "n (numeric) The recent hashes per second when generation is on (will return 0 if generation is off)\n" - "\nExamples:\n" - + HelpExampleCli("gethashespersec", "") - + HelpExampleRpc("gethashespersec", "") - ); - - if (GetTimeMillis() - nHPSTimerStart > 8000) - return (int64_t)0; - return (int64_t)dHashesPerSec; -} -#endif - - -Value getmininginfo(const Array& params, bool fHelp) +UniValue getmininginfo(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 0) throw runtime_error( @@ -237,7 +233,6 @@ Value getmininginfo(const Array& params, bool fHelp) " \"errors\": \"...\" (string) Current errors\n" " \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n" " \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n" - " \"hashespersec\": n (numeric) The hashes per second of the generation, or 0 if no generation.\n" " \"pooledtx\": n (numeric) The size of the mem pool\n" " \"testnet\": true|false (boolean) If using testnet or not\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" @@ -247,7 +242,10 @@ Value getmininginfo(const Array& params, bool fHelp) + HelpExampleRpc("getmininginfo", "") ); - Object obj; + + LOCK(cs_main); + + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize)); obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx)); @@ -258,16 +256,13 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("chain", Params().NetworkIDString())); -#ifdef ENABLE_WALLET obj.push_back(Pair("generate", getgenerate(params, false))); - obj.push_back(Pair("hashespersec", gethashespersec(params, false))); -#endif return obj; } // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts -Value prioritisetransaction(const Array& params, bool fHelp) +UniValue prioritisetransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 3) throw runtime_error( @@ -288,9 +283,9 @@ Value prioritisetransaction(const Array& params, bool fHelp) + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000") ); - uint256 hash; - hash.SetHex(params[0].get_str()); + LOCK(cs_main); + uint256 hash = ParseHashStr(params[0].get_str(), "txid"); CAmount nAmount = params[2].get_int64(); mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount); @@ -299,10 +294,10 @@ Value prioritisetransaction(const Array& params, bool fHelp) // NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller -static Value BIP22ValidationResult(const CValidationState& state) +static UniValue BIP22ValidationResult(const CValidationState& state) { if (state.IsValid()) - return Value::null; + return NullUniValue; std::string strRejectReason = state.GetRejectReason(); if (state.IsError()) @@ -317,7 +312,7 @@ static Value BIP22ValidationResult(const CValidationState& state) return "valid?"; } -Value getblocktemplate(const Array& params, bool fHelp) +UniValue getblocktemplate(const UniValue& params, bool fHelp) { if (fHelp || params.size() > 1) throw runtime_error( @@ -379,15 +374,17 @@ Value getblocktemplate(const Array& params, bool fHelp) + HelpExampleRpc("getblocktemplate", "") ); + LOCK(cs_main); + std::string strMode = "template"; - Value lpval = Value::null; + UniValue lpval = NullUniValue; if (params.size() > 0) { - const Object& oparam = params[0].get_obj(); - const Value& modeval = find_value(oparam, "mode"); - if (modeval.type() == str_type) + const UniValue& oparam = params[0].get_obj(); + const UniValue& modeval = find_value(oparam, "mode"); + if (modeval.isStr()) strMode = modeval.get_str(); - else if (modeval.type() == null_type) + else if (modeval.isNull()) { /* Do nothing */ } @@ -397,8 +394,8 @@ Value getblocktemplate(const Array& params, bool fHelp) if (strMode == "proposal") { - const Value& dataval = find_value(oparam, "data"); - if (dataval.type() != str_type) + const UniValue& dataval = find_value(oparam, "data"); + if (!dataval.isStr()) throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal"); CBlock block; @@ -437,14 +434,14 @@ Value getblocktemplate(const Array& params, bool fHelp) static unsigned int nTransactionsUpdatedLast; - if (lpval.type() != null_type) + if (!lpval.isNull()) { // Wait to respond until either the best block changes, OR a minute has passed and there are more transactions uint256 hashWatchedChain; boost::system_time checktxtime; unsigned int nTransactionsUpdatedLastLP; - if (lpval.type() == str_type) + if (lpval.isStr()) { // Format: <hashBestChain><nTransactionsUpdatedLast> std::string lpstr = lpval.get_str(); @@ -460,10 +457,6 @@ Value getblocktemplate(const Array& params, bool fHelp) } // Release the wallet and main lock while waiting -#ifdef ENABLE_WALLET - if(pwalletMain) - LEAVE_CRITICAL_SECTION(pwalletMain->cs_wallet); -#endif LEAVE_CRITICAL_SECTION(cs_main); { checktxtime = boost::get_system_time() + boost::posix_time::minutes(1); @@ -481,10 +474,6 @@ Value getblocktemplate(const Array& params, bool fHelp) } } ENTER_CRITICAL_SECTION(cs_main); -#ifdef ENABLE_WALLET - if(pwalletMain) - ENTER_CRITICAL_SECTION(pwalletMain->cs_wallet); -#endif if (!IsRPCRunning()) throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down"); @@ -523,29 +512,28 @@ Value getblocktemplate(const Array& params, bool fHelp) CBlock* pblock = &pblocktemplate->block; // pointer for convenience // Update nTime - UpdateTime(pblock, pindexPrev); + UpdateTime(pblock, Params().GetConsensus(), pindexPrev); pblock->nNonce = 0; - static const Array aCaps = boost::assign::list_of("proposal"); + UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal"); - Array transactions; + UniValue transactions(UniValue::VARR); map<uint256, int64_t> setTxIndex; int i = 0; - BOOST_FOREACH (CTransaction& tx, pblock->vtx) - { + BOOST_FOREACH (const CTransaction& tx, pblock->vtx) { uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; if (tx.IsCoinBase()) continue; - Object entry; + UniValue entry(UniValue::VOBJ); entry.push_back(Pair("data", EncodeHexTx(tx))); entry.push_back(Pair("hash", txHash.GetHex())); - Array deps; + UniValue deps(UniValue::VARR); BOOST_FOREACH (const CTxIn &in, tx.vin) { if (setTxIndex.count(in.prevout.hash)) @@ -560,12 +548,12 @@ Value getblocktemplate(const Array& params, bool fHelp) transactions.push_back(entry); } - Object aux; + UniValue aux(UniValue::VOBJ); aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end()))); - uint256 hashTarget = uint256().SetCompact(pblock->nBits); + arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); - static Array aMutable; + static UniValue aMutable(UniValue::VARR); if (aMutable.empty()) { aMutable.push_back("time"); @@ -573,7 +561,7 @@ Value getblocktemplate(const Array& params, bool fHelp) aMutable.push_back("prevblock"); } - Object result; + UniValue result(UniValue::VOBJ); result.push_back(Pair("capabilities", aCaps)); result.push_back(Pair("version", pblock->nVersion)); result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); @@ -612,7 +600,7 @@ protected: }; }; -Value submitblock(const Array& params, bool fHelp) +UniValue submitblock(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( @@ -638,22 +626,27 @@ Value submitblock(const Array& params, bool fHelp) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); uint256 hash = block.GetHash(); - BlockMap::iterator mi = mapBlockIndex.find(hash); - if (mi != mapBlockIndex.end()) { - CBlockIndex *pindex = mi->second; - if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) - return "duplicate"; - if (pindex->nStatus & BLOCK_FAILED_MASK) - return "duplicate-invalid"; - // Otherwise, we might only have the header - process the block before returning + bool fBlockPresent = false; + { + LOCK(cs_main); + BlockMap::iterator mi = mapBlockIndex.find(hash); + if (mi != mapBlockIndex.end()) { + CBlockIndex *pindex = mi->second; + if (pindex->IsValid(BLOCK_VALID_SCRIPTS)) + return "duplicate"; + if (pindex->nStatus & BLOCK_FAILED_MASK) + return "duplicate-invalid"; + // Otherwise, we might only have the header - process the block before returning + fBlockPresent = true; + } } CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, NULL, &block); + bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL); UnregisterValidationInterface(&sc); - if (mi != mapBlockIndex.end()) + if (fBlockPresent) { if (fAccepted && !sc.found) return "duplicate-inconclusive"; @@ -668,7 +661,7 @@ Value submitblock(const Array& params, bool fHelp) return BIP22ValidationResult(state); } -Value estimatefee(const Array& params, bool fHelp) +UniValue estimatefee(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -687,7 +680,7 @@ Value estimatefee(const Array& params, bool fHelp) + HelpExampleCli("estimatefee", "6") ); - RPCTypeCheck(params, boost::assign::list_of(int_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); int nBlocks = params[0].get_int(); if (nBlocks < 1) @@ -700,7 +693,7 @@ Value estimatefee(const Array& params, bool fHelp) return ValueFromAmount(feeRate.GetFeePerK()); } -Value estimatepriority(const Array& params, bool fHelp) +UniValue estimatepriority(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 1) throw runtime_error( @@ -719,7 +712,7 @@ Value estimatepriority(const Array& params, bool fHelp) + HelpExampleCli("estimatepriority", "6") ); - RPCTypeCheck(params, boost::assign::list_of(int_type)); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)); int nBlocks = params[0].get_int(); if (nBlocks < 1) |