X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Frpcmining.cpp;h=fa0244242940e693d2efb3716d3518f0d02260ba;hb=1ebe5b92ef18395cdae9b88fc38b0ed6166c3243;hp=fe8cf0b7cc7bc9b94945000fc8790c015047b2df;hpb=9d519fcff4e11f4e770c350fa69c302aed881b01;p=novacoin.git diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index fe8cf0b..fa02442 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -5,12 +5,44 @@ #include "main.h" #include "db.h" +#include "txdb.h" #include "init.h" +#include "miner.h" +#include "kernel.h" #include "bitcoinrpc.h" +#include +#include +#include + using namespace json_spirit; using namespace std; +extern uint256 nPoWBase; +extern uint64_t nStakeInputsMapSize; + +Value getsubsidy(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getsubsidy [nTarget]\n" + "Returns proof-of-work subsidy value for the specified value of target."); + + unsigned int nBits = 0; + + if (params.size() != 0) + { + CBigNum bnTarget(uint256(params[0].get_str())); + nBits = bnTarget.GetCompact(); + } + else + { + nBits = GetNextTargetRequired(pindexBest, false); + } + + return (uint64_t)GetProofOfWorkReward(nBits); +} + Value getmininginfo(const Array& params, bool fHelp) { if (fHelp || params.size() != 0) @@ -18,62 +50,184 @@ Value getmininginfo(const Array& params, bool fHelp) "getmininginfo\n" "Returns an object containing mining-related information."); - double dStakeKernelsTriedAvg = 0; - int nPoWInterval = 72, nPoSInterval = 72, nStakesHandled = 0, nStakesTime = 0; - int64 nTargetSpacingWorkMin = 30, nTargetSpacingWork = 30; + Object obj, diff; + obj.push_back(Pair("blocks", (int)nBestHeight)); + obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize)); + obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx)); - CBlockIndex* pindex = pindexGenesisBlock; - CBlockIndex* pindexPrevWork = pindexGenesisBlock; - CBlockIndex* pindexPrevStake = NULL; + diff.push_back(Pair("proof-of-work", GetDifficulty())); + diff.push_back(Pair("proof-of-stake", GetDifficulty(GetLastBlockIndex(pindexBest, true)))); + diff.push_back(Pair("search-interval", (int)nLastCoinStakeSearchInterval)); + obj.push_back(Pair("difficulty", diff)); - while (pindex) - { - if (pindex->IsProofOfWork()) - { - int64 nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime(); - nTargetSpacingWork = ((nPoWInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nPoWInterval + 1); - nTargetSpacingWork = max(nTargetSpacingWork, nTargetSpacingWorkMin); - pindexPrevWork = pindex; - } + obj.push_back(Pair("blockvalue", (uint64_t)GetProofOfWorkReward(GetLastBlockIndex(pindexBest, false)->nBits))); + obj.push_back(Pair("netmhashps", GetPoWMHashPS())); + obj.push_back(Pair("netstakeweight",GetPoSKernelPS())); + obj.push_back(Pair("errors", GetWarnings("statusbar"))); + obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - pindex = pindex->pnext; + obj.push_back(Pair("stakeinputs", (uint64_t)nStakeInputsMapSize)); + obj.push_back(Pair("stakeinterest", GetProofOfStakeReward(0, GetLastBlockIndex(pindexBest, true)->nBits, GetLastBlockIndex(pindexBest, true)->nTime, true))); + + obj.push_back(Pair("testnet", fTestNet)); + return obj; +} + +// scaninput '{"txid":"95d640426fe66de866a8cf2d0601d2c8cf3ec598109b4d4ffa7fd03dad6d35ce","difficulty":0.01, "days":10}' +Value scaninput(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "scaninput '{\"txid\":\"txid\", \"vout\":[vout1, vout2, ..., voutN], \"difficulty\":difficulty, \"days\":days}'\n" + "Scan specified transaction or input for suitable kernel solutions.\n" + " difficulty - upper limit for difficulty, current difficulty by default;\n" + " days - time window, 90 days by default.\n" + ); + + RPCTypeCheck(params, boost::assign::list_of(obj_type)); + + Object scanParams = params[0].get_obj(); + + const Value& txid_v = find_value(scanParams, "txid"); + if (txid_v.type() != str_type) + 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"); + + uint256 hash(txid); + int32_t nDays = 90; + uint32_t nBits = GetNextTargetRequired(pindexBest, true); + + const Value& diff_v = find_value(scanParams, "difficulty"); + if (diff_v.type() == real_type || diff_v.type() == int_type) + { + double dDiff = diff_v.get_real(); + if (dDiff <= 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, diff must be greater than zero"); + + CBigNum bnTarget(nPoWBase); + bnTarget *= 1000; + bnTarget /= (int) (dDiff * 1000); + nBits = bnTarget.GetCompact(); } + const Value& days_v = find_value(scanParams, "days"); + if (days_v.type() == int_type) + { + nDays = days_v.get_int(); + if (nDays <= 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, interval length must be greater than zero"); + } - pindex = pindexBest; - while (pindex && nStakesHandled < nPoSInterval) + CTransaction tx; + uint256 hashBlock = 0; + if (GetTransaction(hash, tx, hashBlock)) { - if (pindex->IsProofOfStake()) + if (hashBlock == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to find transaction in the blockchain"); + + vector vInputs(0); + const Value& inputs_v = find_value(scanParams, "vout"); + if (inputs_v.type() == array_type) { - dStakeKernelsTriedAvg += GetDifficulty(pindex) * 4294967296; - nStakesTime += pindexPrevStake ? (pindexPrevStake->nTime - pindex->nTime) : 0; - pindexPrevStake = pindex; - nStakesHandled++; + Array inputs = inputs_v.get_array(); + BOOST_FOREACH(const Value &v_out, inputs) + { + int nOut = v_out.get_int(); + if (nOut < 0 || nOut > (int)tx.vout.size() - 1) + { + stringstream strErrorMsg; + strErrorMsg << boost::format("Invalid parameter, input number %d is out of range") % nOut; + throw JSONRPCError(RPC_INVALID_PARAMETER, strErrorMsg.str()); + } + + vInputs.push_back(nOut); + } } + else if(inputs_v.type() == int_type) + { + int nOut = inputs_v.get_int(); + if (nOut < 0 || nOut > (int)tx.vout.size() - 1) + { + stringstream strErrorMsg; + strErrorMsg << boost::format("Invalid parameter, input number %d is out of range") % nOut; + throw JSONRPCError(RPC_INVALID_PARAMETER, strErrorMsg.str()); + } - pindex = pindex->pprev; - } + vInputs.push_back(nOut); + } + else + { + vInputs = vector(boost::counting_iterator( 0 ), boost::counting_iterator( tx.vout.size() )); + } - double dNetworkMhps = GetDifficulty() * 4294.967296 / nTargetSpacingWork; - double dNetworkWeight = dStakeKernelsTriedAvg / nStakesTime; + CTxDB txdb("r"); - Object obj; - obj.push_back(Pair("blocks", (int)nBestHeight)); - obj.push_back(Pair("currentblocksize",(uint64_t)nLastBlockSize)); - obj.push_back(Pair("currentblocktx",(uint64_t)nLastBlockTx)); - obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("blockvalue", (uint64_t)GetProofOfWorkReward(GetLastBlockIndex(pindexBest, false)->nBits))); - obj.push_back(Pair("netmhashps", dNetworkMhps)); - obj.push_back(Pair("netstakeweight", dNetworkWeight)); - obj.push_back(Pair("errors", GetWarnings("statusbar"))); - obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("stakeweight", (uint64_t)pwalletMain->GetStakeWeight(*pwalletMain, STAKE_NORMAL))); - obj.push_back(Pair("minweight", (uint64_t)pwalletMain->GetStakeWeight(*pwalletMain, STAKE_MINWEIGHT))); - obj.push_back(Pair("maxweight", (uint64_t)pwalletMain->GetStakeWeight(*pwalletMain, STAKE_MAXWEIGHT))); - obj.push_back(Pair("stakeinterest", (uint64_t)GetProofOfStakeReward(0, GetLastBlockIndex(pindexBest, true)->nBits, GetLastBlockIndex(pindexBest, true)->nTime, true))); - obj.push_back(Pair("testnet", fTestNet)); - return obj; + CBlock block; + CTxIndex txindex; + + // Load transaction index item + if (!txdb.ReadTxIndex(tx.GetHash(), txindex)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to read block index item"); + + // Read block header + if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "CBlock::ReadFromDisk() failed"); + + uint64_t nStakeModifier = 0; + if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No kernel stake modifier generated yet"); + + std::pair interval; + interval.first = GetTime(); + // Only count coins meeting min age requirement + if (nStakeMinAge + block.nTime > interval.first) + interval.first += (nStakeMinAge + block.nTime - interval.first); + interval.second = interval.first + nDays * nOneDay; + + Array results; + BOOST_FOREACH(const int &nOut, vInputs) + { + // Check for spent flag + // It doesn't make sense to scan spent inputs. + if (!txindex.vSpent[nOut].IsNull()) + continue; + + // Skip zero value outputs + if (tx.vout[nOut].nValue == 0) + continue; + + // Build static part of kernel + CDataStream ssKernel(SER_GETHASH, 0); + ssKernel << nStakeModifier; + ssKernel << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << tx.nTime << nOut; + CDataStream::const_iterator itK = ssKernel.begin(); + + std::vector > result; + if (ScanKernelForward((unsigned char *)&itK[0], nBits, tx.nTime, tx.vout[nOut].nValue, interval, result)) + { + BOOST_FOREACH(const PAIRTYPE(uint256, uint32_t) solution, result) + { + Object item; + item.push_back(Pair("nout", nOut)); + item.push_back(Pair("hash", solution.first.GetHex())); + item.push_back(Pair("time", DateTimeStrFormat(solution.second))); + + results.push_back(item); + } + } + } + + if (results.size() == 0) + return false; + + return results; + } + else + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); } Value getworkex(const Array& params, bool fHelp) @@ -100,7 +254,7 @@ Value getworkex(const Array& params, bool fHelp) // Update block static unsigned int nTransactionsUpdatedLast; static CBlockIndex* pindexPrev; - static int64 nStart; + static int64_t nStart; static CBlock* pblock; if (pindexPrev != pindexBest || (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) @@ -198,12 +352,6 @@ Value getworkex(const Array& params, bool fHelp) pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - if (!fTestNet && pblock->GetBlockTime() < CHAINCHECKS_SWITCH_TIME) - { - if (!pblock->SignBlock(*pwalletMain)) - throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); - } - return CheckWork(pblock, *pwalletMain, reservekey); } } @@ -237,7 +385,7 @@ Value getwork(const Array& params, bool fHelp) // Update block static unsigned int nTransactionsUpdatedLast; static CBlockIndex* pindexPrev; - static int64 nStart; + static int64_t nStart; static CBlock* pblock; if (pindexPrev != pindexBest || (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) @@ -317,12 +465,6 @@ Value getwork(const Array& params, bool fHelp) pblock->vtx[0].vin[0].scriptSig = mapNewBlock[pdata->hashMerkleRoot].second; pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - if (!fTestNet && pblock->GetBlockTime() < CHAINCHECKS_SWITCH_TIME) - { - if (!pblock->SignBlock(*pwalletMain)) - throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); - } - return CheckWork(pblock, *pwalletMain, reservekey); } } @@ -379,7 +521,7 @@ Value getblocktemplate(const Array& params, bool fHelp) // Update block static unsigned int nTransactionsUpdatedLast; static CBlockIndex* pindexPrev; - static int64 nStart; + static int64_t nStart; static CBlock* pblock; if (pindexPrev != pindexBest || (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5)) @@ -500,16 +642,10 @@ Value submitblock(const Array& params, bool fHelp) try { ssBlock >> block; } - catch (std::exception &e) { + catch (const std::exception&) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed"); } - if (!fTestNet && block.GetBlockTime() < CHAINCHECKS_SWITCH_TIME) - { - if (!block.SignBlock(*pwalletMain)) - throw JSONRPCError(-100, "Unable to sign block, wallet locked?"); - } - bool fAccepted = ProcessBlock(NULL, &block); if (!fAccepted) return "rejected";