#include "main.h"
#include "db.h"
-#include "txdb.h"
+#include "txdb-leveldb.h"
#include "init.h"
#include "miner.h"
+#include "kernel.h"
#include "bitcoinrpc.h"
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)
"getmininginfo\n"
"Returns an object containing mining-related information.");
- Object obj;
+ 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));
- obj.push_back(Pair("difficulty", (double)GetDifficulty()));
+
+ 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));
+
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("netmhashps", GetPoWMHashPS()));
+ obj.push_back(Pair("netstakeweight",GetPoSKernelPS()));
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("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, { 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");
+ }
+
+
+ CTransaction tx;
+ uint256 hashBlock = 0;
+ if (GetTransaction(hash, tx, hashBlock))
+ {
+ if (hashBlock == 0)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to find transaction in the blockchain");
+
+ vector<int> vInputs(0);
+ const Value& inputs_v = find_value(scanParams, "vout");
+ if (inputs_v.type() == array_type)
+ {
+ Array inputs = inputs_v.get_array();
+ for (const Value &v_out : inputs)
+ {
+ int nOut = v_out.get_int();
+ if (nOut < 0 || nOut > (int)tx.vout.size() - 1)
+ {
+ stringstream strErrorMsg;
+ strErrorMsg << "Invalid parameter, input number " << to_string(nOut) << " is out of range";
+ 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 << "Invalid parameter, input number " << to_string(nOut) << " is out of range";
+ throw JSONRPCError(RPC_INVALID_PARAMETER, strErrorMsg.str());
+ }
+
+ vInputs.push_back(nOut);
+ }
+ else
+ {
+ for (size_t i = 0; i != tx.vout.size(); ++i) vInputs.push_back(i);
+ }
+
+ CTxDB txdb("r");
+
+ 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<uint32_t, uint32_t> 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;
+ for (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<std::pair<uint256, uint32_t> > result;
+ if (ScanKernelForward((unsigned char *)&itK[0], nBits, tx.nTime, tx.vout[nOut].nValue, interval, result))
+ {
+ for (const auto &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)
{
if (fHelp || params.size() > 2)
if (IsInitialBlockDownload())
throw JSONRPCError(-10, "NovaCoin is downloading blocks...");
- typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
+ typedef map<uint256, pair<shared_ptr<CBlock>, CScript> > mapNewBlock_t;
static mapNewBlock_t mapNewBlock;
- static vector<CBlock*> vNewBlock;
+ static vector<std::shared_ptr<CBlock>> vNewBlock;
static CReserveKey reservekey(pwalletMain);
if (params.size() == 0)
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
- static int64 nStart;
- static CBlock* pblock;
+ static int64_t nStart;
+ static shared_ptr<CBlock> pblock;
if (pindexPrev != pindexBest ||
(nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
{
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
- BOOST_FOREACH(CBlock* pblock, vNewBlock)
- delete pblock;
vNewBlock.clear();
}
nTransactionsUpdatedLast = nTransactionsUpdated;
Array merkle_arr;
- BOOST_FOREACH(uint256 merkleh, merkle) {
+ for (uint256 merkleh : merkle) {
merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
}
// Get saved block
if (!mapNewBlock.count(pdata->hashMerkleRoot))
return false;
- CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
+ std::shared_ptr<CBlock> pblock = mapNewBlock[pdata->hashMerkleRoot].first;
pblock->nTime = pdata->nTime;
pblock->nNonce = pdata->nNonce;
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);
}
}
if (IsInitialBlockDownload())
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "NovaCoin is downloading blocks...");
- typedef map<uint256, pair<CBlock*, CScript> > mapNewBlock_t;
+ typedef map<uint256, pair<shared_ptr<CBlock>, CScript> > mapNewBlock_t;
static mapNewBlock_t mapNewBlock; // FIXME: thread safety
- static vector<CBlock*> vNewBlock;
+ static vector<shared_ptr<CBlock>> vNewBlock;
static CReserveKey reservekey(pwalletMain);
if (params.size() == 0)
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
- static int64 nStart;
- static CBlock* pblock;
+ static int64_t nStart;
+ static shared_ptr<CBlock> pblock;
if (pindexPrev != pindexBest ||
(nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60))
{
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
- BOOST_FOREACH(CBlock* pblock, vNewBlock)
- delete pblock;
vNewBlock.clear();
}
// Get saved block
if (!mapNewBlock.count(pdata->hashMerkleRoot))
return false;
- CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first;
+ std::shared_ptr<CBlock> pblock = mapNewBlock[pdata->hashMerkleRoot].first;
pblock->nTime = pdata->nTime;
pblock->nNonce = pdata->nNonce;
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);
}
}
// Update block
static unsigned int nTransactionsUpdatedLast;
static CBlockIndex* pindexPrev;
- static int64 nStart;
- static CBlock* pblock;
+ static int64_t nStart;
+ static std::shared_ptr<CBlock> pblock;
if (pindexPrev != pindexBest ||
(nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5))
{
// Create new block
if(pblock)
{
- delete pblock;
- pblock = NULL;
+ pblock.reset();
}
pblock = CreateNewBlock(pwalletMain);
if (!pblock)
map<uint256, int64_t> setTxIndex;
int i = 0;
CTxDB txdb("r");
- BOOST_FOREACH (CTransaction& tx, pblock->vtx)
+ for (CTransaction& tx : pblock->vtx)
{
uint256 txHash = tx.GetHash();
setTxIndex[txHash] = i++;
entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
Array deps;
- BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
+ for (MapPrevTx::value_type& inp : mapInputs)
{
if (setTxIndex.count(inp.first))
deps.push_back(setTxIndex[inp.first]);
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";