rpcmining.cpp remove CBigNum from code
[novacoin.git] / src / rpcmining.cpp
index 8f02836..03b13be 100644 (file)
 #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)
 {
@@ -27,7 +29,7 @@ Value getsubsidy(const Array& params, bool fHelp)
 
     if (params.size() != 0)
     {
-        CBigNum bnTarget(uint256(params[0].get_str()));
+        uint256 bnTarget(params[0].get_str());
         nBits = bnTarget.GetCompact();
     }
     else
@@ -45,10 +47,7 @@ Value getmininginfo(const Array& params, bool fHelp)
             "getmininginfo\n"
             "Returns an object containing mining-related information.");
 
-    float nKernelsRate = 0, nCoinDaysRate = 0;
-    pwalletMain->GetStakeStats(nKernelsRate, nCoinDaysRate);
-
-    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));
@@ -59,67 +58,173 @@ Value getmininginfo(const Array& params, bool fHelp)
     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()));
 
-    weight.push_back(Pair("kernelsrate",   nKernelsRate));
-    weight.push_back(Pair("cdaysrate",   nCoinDaysRate));
-    obj.push_back(Pair("stakestats", weight));
+    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("stakeinterest",    (uint64_t)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() > 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();
+
+    const Value& txid_v = find_value(scanParams, "txid");
+    if (txid_v.type() != str_type)
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing txid key");
 
-    uint256 hash;
-    hash.SetHex(params[0].get_str());
+    auto txid = txid_v.get_str();
+    if (!IsHex(txid))
+        throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
 
-    uint32_t nOut = params[1].get_int(), nBits = GetNextTargetRequired(pindexBest, true), nDays = 365;
+    uint256 hash(txid);
+    int32_t nDays = 90;
+    auto nBits = GetNextTargetRequired(pindexBest, true);
 
-    if (params.size() > 2)
+    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))
     {
-        std::pair<uint256, uint32_t> solution;
-        if (ScanInputForStakeKernelHash(tx, nOut, nBits, nDays * 86400, solution))
+        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
         {
-            Object r;
-            r.push_back(Pair("hash", solution.first.GetHex()));
-            r.push_back(Pair("time", DateTimeStrFormat(solution.second)));
+            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");
+
+        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;
 
-            return r;
+        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;
+            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)
@@ -155,7 +260,7 @@ 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();
             }
@@ -179,7 +284,7 @@ Value getworkex(const Array& params, bool fHelp)
         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];
@@ -187,14 +292,14 @@ Value getworkex(const Array& params, bool fHelp)
         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;
@@ -202,8 +307,8 @@ Value getworkex(const Array& params, bool fHelp)
 
         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));
@@ -286,7 +391,7 @@ Value getwork(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();
             }
@@ -318,7 +423,7 @@ Value getwork(const Array& params, bool fHelp)
         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];
@@ -326,13 +431,13 @@ Value getwork(const Array& params, bool fHelp)
         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
@@ -384,7 +489,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
             "  \"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();
@@ -448,9 +553,9 @@ Value getblocktemplate(const Array& params, bool fHelp)
     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())
@@ -472,7 +577,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
             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]);
@@ -490,7 +595,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
     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())
@@ -534,7 +639,7 @@ Value submitblock(const Array& params, bool fHelp)
     try {
         ssBlock >> block;
     }
-    catch (std::exception &e) {
+    catch (const exception&) {
         throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
     }