#include "kernel.h"
#include "bitcoinrpc.h"
+
using namespace json_spirit;
using namespace std;
if (params.size() != 0)
{
- CBigNum bnTarget(uint256(params[0].get_str()));
+ uint256 bnTarget(params[0].get_str());
nBits = bnTarget.GetCompact();
}
else
"getmininginfo\n"
"Returns an object containing mining-related information.");
- Object obj, diff, weight;
+ 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));
return obj;
}
+// scaninput '{"txid":"95d640426fe66de866a8cf2d0601d2c8cf3ec598109b4d4ffa7fd03dad6d35ce","difficulty":0.01, "days":10}'
Value scaninput(const Array& params, bool fHelp)
{
- if (fHelp || params.size() > 4 || params.size() < 2)
+ if (fHelp || params.size() != 1)
throw runtime_error(
- "scaninput <txid> <nout> [difficulty] [days]\n"
- "Scan specified input for suitable kernel solutions.\n"
- " [difficulty] - upper limit for difficulty, current difficulty by default;\n"
- " [days] - time window, 365 days by default.\n"
+ "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 });
+
+ auto scanParams = params[0].get_obj();
- uint256 hash;
- hash.SetHex(params[0].get_str());
+ const Value& txid_v = find_value(scanParams, "txid");
+ if (txid_v.type() != str_type)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
- uint32_t nOut = params[1].get_int(), nBits = GetNextTargetRequired(pindexBest, true), nDays = 365;
+ auto txid = txid_v.get_str();
+ if (!IsHex(txid))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
- if (params.size() > 2)
+ uint256 hash(txid);
+ int32_t nDays = 90;
+ auto nBits = GetNextTargetRequired(pindexBest, true);
+
+ const Value& diff_v = find_value(scanParams, "difficulty");
+ if (diff_v.type() == real_type || diff_v.type() == int_type)
{
- CBigNum bnTarget(nPoWBase);
+ double dDiff = diff_v.get_real();
+ if (dDiff <= 0)
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, diff must be greater than zero");
+
+ uint256 bnTarget(nPoWBase);
bnTarget *= 1000;
- bnTarget /= (int) (params[2].get_real() * 1000);
+ bnTarget /= (int) (dDiff * 1000);
nBits = bnTarget.GetCompact();
}
- if (params.size() > 3)
+ const Value& days_v = find_value(scanParams, "days");
+ if (days_v.type() == int_type)
{
- nDays = params[3].get_int();
+ 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 (nOut > tx.vout.size())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Incorrect output number");
-
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)
+ {
+ auto 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;
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;
+ 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 * 86400;
-
- SHA256_CTX ctx;
- GetKernelMidstate(nStakeModifier, block.nTime, txindex.pos.nTxPos - txindex.pos.nBlockPos, tx.nTime, nOut, ctx);
+ interval.second = interval.first + nDays * nOneDay;
- std::pair<uint256, uint32_t> solution;
- if (ScanMidstateForward(ctx, nBits, tx.nTime, tx.vout[nOut].nValue, interval, solution))
+ Array results;
+ for(const int &nOut : vInputs)
{
- Object r;
- r.push_back(Pair("hash", solution.first.GetHex()));
- r.push_back(Pair("time", DateTimeStrFormat(solution.second)));
-
- return r;
+ // 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;
+ auto itK = ssKernel.begin();
+
+ vector<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");
-
- return Value::null;
}
Value getworkex(const Array& params, bool fHelp)
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
- BOOST_FOREACH(CBlock* pblock, vNewBlock)
+ for(CBlock* pblock : vNewBlock)
delete pblock;
vNewBlock.clear();
}
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
// Save
- mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
+ mapNewBlock[pblock->hashMerkleRoot] = { pblock, pblock->vtx[0].vin[0].scriptSig };
// Prebuild hash buffers
char pmidstate[32];
char phash1[64];
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
- uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
+ auto hashTarget = uint256().SetCompact(pblock->nBits);
- CTransaction coinbaseTx = pblock->vtx[0];
- std::vector<uint256> merkle = pblock->GetMerkleBranch(0);
+ auto coinbaseTx = pblock->vtx[0];
+ auto merkle = pblock->GetMerkleBranch(0);
Object result;
- result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
- result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
+ result.push_back(Pair("data", HexStr(begin(pdata), end(pdata))));
+ result.push_back(Pair("target", HexStr(hashTarget.begin(), hashTarget.end())));
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << coinbaseTx;
Array merkle_arr;
- BOOST_FOREACH(uint256 merkleh, merkle) {
- merkle_arr.push_back(HexStr(BEGIN(merkleh), END(merkleh)));
+ for(uint256 merkleh : merkle) {
+ merkle_arr.push_back(HexStr(merkleh.begin(), merkleh.end()));
}
result.push_back(Pair("merkle", merkle_arr));
{
// Deallocate old blocks since they're obsolete now
mapNewBlock.clear();
- BOOST_FOREACH(CBlock* pblock, vNewBlock)
+ for(CBlock* pblock : vNewBlock)
delete pblock;
vNewBlock.clear();
}
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
// Save
- mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, pblock->vtx[0].vin[0].scriptSig);
+ mapNewBlock[pblock->hashMerkleRoot] = { pblock, pblock->vtx[0].vin[0].scriptSig };
// Pre-build hash buffers
char pmidstate[32];
char phash1[64];
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
- uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
+ auto hashTarget = uint256().SetCompact(pblock->nBits);
Object result;
- result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); // deprecated
- result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata))));
- result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); // deprecated
- result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget))));
+ result.push_back(Pair("midstate", HexStr(begin(pmidstate), end(pmidstate)))); // deprecated
+ result.push_back(Pair("data", HexStr(begin(pdata), end(pdata))));
+ result.push_back(Pair("hash1", HexStr(begin(phash1), end(phash1)))); // deprecated
+ result.push_back(Pair("target", HexStr(hashTarget.begin(), hashTarget.end())));
return result;
}
else
" \"height\" : height of the next block\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.");
- std::string strMode = "template";
+ string strMode = "template";
if (params.size() > 0)
{
const Object& oparam = params[0].get_obj();
map<uint256, int64_t> setTxIndex;
int i = 0;
CTxDB txdb("r");
- BOOST_FOREACH (CTransaction& tx, pblock->vtx)
+ for(auto& tx : pblock->vtx)
{
- uint256 txHash = tx.GetHash();
+ auto txHash = tx.GetHash();
setTxIndex[txHash] = i++;
if (tx.IsCoinBase() || tx.IsCoinStake())
entry.push_back(Pair("fee", (int64_t)(tx.GetValueIn(mapInputs) - tx.GetValueOut())));
Array deps;
- BOOST_FOREACH (MapPrevTx::value_type& inp, mapInputs)
+ for(auto& inp : mapInputs)
{
if (setTxIndex.count(inp.first))
deps.push_back(setTxIndex[inp.first]);
Object aux;
aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
- uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
+ auto hashTarget = uint256().SetCompact(pblock->nBits);
static Array aMutable;
if (aMutable.empty())
try {
ssBlock >> block;
}
- catch (const std::exception&) {
+ catch (const exception&) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
}