Skip to content

Commit

Permalink
Feature/getmininginfo (#297)
Browse files Browse the repository at this point in the history
* Added getmininginfo RPC method

* Updated the help text and formated the response.

* Added lastBlockCreationAttemptTs member variable to CMasternode class

* Added "lastblockcreationattempt" key-value to  getmininginfo RPC response

* Added mapMNLastBlockCreationAttemptTs  map to store last block creation attempt timestamp by masternodes

* Added functional test GetMiningInfoRPCTest

* Added a deprication notice for getmintinginfo

* Updated code with a critical section optimization.
  • Loading branch information
surangap authored Mar 31, 2021
1 parent 1b90af4 commit 7413fec
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
if (!nodePtr || !nodePtr->IsActive())
return nullptr;

// update last block creation attempt ts for the master node
{
CLockFreeGuard lock(pos::cs_MNLastBlockCreationAttemptTs);
pos::mapMNLastBlockCreationAttemptTs[myIDs->second] = GetTime();
}

CBlockIndex* pindexPrev = ::ChainActive().Tip();
assert(pindexPrev != nullptr);
nHeight = pindexPrev->nHeight + 1;
Expand Down
5 changes: 5 additions & 0 deletions src/miner.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ namespace pos {
template <typename F>
bool withSearchInterval(F&& f);
};

// Map to store [master node id : last block creation attempt timestamp] for local master nodes
static std::map<uint256, int64_t> mapMNLastBlockCreationAttemptTs;
static std::atomic_bool cs_MNLastBlockCreationAttemptTs(false);

}

#endif // DEFI_MINER_H
74 changes: 73 additions & 1 deletion src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,11 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
return generateBlocks(coinbase_script, minterKey, myIDs->first, nGenerate, nMaxTries);
}

/// @deprecated version of getmininginfo. prefer using getmininginfo
static UniValue getmintinginfo(const JSONRPCRequest& request)
{
RPCHelpMan{"getmintinginfo",
"\nReturns a json object containing mining-related information.",
"\nDEPRECATED. Prefer using getmininginfo.\nReturns a json object containing mining-related information.",
{},
RPCResult{
"{\n"
Expand Down Expand Up @@ -267,6 +268,76 @@ static UniValue getmintinginfo(const JSONRPCRequest& request)
return obj;
}

// Returns the mining information of all local masternodes
static UniValue getmininginfo(const JSONRPCRequest& request)
{
RPCHelpMan{"getmininginfo",
"\nReturns a json object containing mining-related information for all local masternodes",
{},
RPCResult{
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
" \"currentblockweight\": nnn, (numeric, optional) The block weight of the last assembled block (only present if a block was ever assembled)\n"
" \"currentblocktx\": nnn, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
" \"networkhashps\": nnn, (numeric) The network hashes per second\n"
" \"pooledtx\": n (numeric) The size of the mempool\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"isoperator\": true|false (boolean) Local master nodes are available or not \n"
" \"masternodes\": [] (array) an array of objects which includes each master node information\n"
" \"warnings\": \"...\" (string) any network and blockchain warnings\n"
"}\n"
},
RPCExamples{
HelpExampleCli("getmininginfo", "")
+ HelpExampleRpc("getmininginfo", "")
},
}.Check(request);

LOCK(cs_main);

UniValue obj(UniValue::VOBJ);
obj.pushKV("blocks", (int)::ChainActive().Height());
if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
obj.pushKV("difficulty", (double)GetDifficulty(::ChainActive().Tip()));
obj.pushKV("networkhashps", getnetworkhashps(request));
obj.pushKV("pooledtx", (uint64_t)mempool.size());
obj.pushKV("chain", Params().NetworkIDString());

// get all masternode operators
auto mnIds = pcustomcsview->GetOperatorsMulti();
obj.pushKV("isoperator", !mnIds.empty());

UniValue mnArr(UniValue::UniValue::VARR); // masternodes array
for (const auto& mnId : mnIds) {
UniValue subObj(UniValue::VOBJ);

subObj.pushKV("masternodeid", mnId.second.GetHex());
CMasternode const & node = *pcustomcsview->GetMasternode(mnId.second);
auto state = node.GetState();
subObj.pushKV("masternodeoperator", node.operatorAuthAddress.GetHex());// NOTE(sp) : Should this also be encoded? not the HEX
subObj.pushKV("masternodestate", CMasternode::GetHumanReadableState(state));
auto generate = node.IsActive() && gArgs.GetBoolArg("-gen", DEFAULT_GENERATE);
subObj.pushKV("generate", generate);
subObj.pushKV("mintedblocks", (uint64_t)node.mintedBlocks);

if (!generate) {
subObj.pushKV("lastblockcreationattempt", "0");
} else {
// get the last block creation attempt by the master node
CLockFreeGuard lock(pos::cs_MNLastBlockCreationAttemptTs);
auto lastBlockCreationAttemptTs = pos::mapMNLastBlockCreationAttemptTs[mnId.second];
subObj.pushKV("lastblockcreationattempt", (lastBlockCreationAttemptTs != 0) ? FormatISO8601DateTime(lastBlockCreationAttemptTs) : "0");
}

mnArr.push_back(subObj);
}

obj.pushKV("masternodes", mnArr);
obj.pushKV("warnings", GetWarnings("statusbar"));
return obj;
}

// NOTE: Unlike wallet RPC (which use DFI values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
static UniValue prioritisetransaction(const JSONRPCRequest& request)
Expand Down Expand Up @@ -1011,6 +1082,7 @@ static const CRPCCommand commands[] =
{ "mining", "getblocktemplate", &getblocktemplate, {"template_request"} },
{ "mining", "submitblock", &submitblock, {"hexdata","dummy"} },
{ "mining", "submitheader", &submitheader, {"hexdata"} },
{ "mining", "getmininginfo", &getmininginfo, {} },


{ "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} },
Expand Down
56 changes: 56 additions & 0 deletions test/functional/rpc_getmininginfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# Copyright (c) 2021 The DeFi Blockchain developers
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.

from test_framework.test_framework import DefiTestFramework
from test_framework.util import (
assert_equal,
connect_nodes_bi,
)

class GetMiningInfoRPCTest(DefiTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.setup_clean_chain = True

def skip_test_if_missing_module(self):
self.skip_if_no_wallet()

def run_test(self):
node0_keys = self.nodes[0].get_genesis_keys()
node1_keys = self.nodes[1].get_genesis_keys()

self.log.info("Import private keys...")
# node[0] has only one master node
self.nodes[0].importprivkey(node0_keys.operatorPrivKey)

# node[1] has two master nodes
self.nodes[1].importprivkey(node0_keys.operatorPrivKey)
self.nodes[1].importprivkey(node1_keys.operatorPrivKey)

operators = [node0_keys.operatorAuthAddress, node1_keys.operatorAuthAddress]

self.log.info("Restart nodes...")
self.restart_node(0, ['-gen', '-masternode_operator=' + operators[0]])
self.restart_node(1, ['-gen', '-rewardaddress=' + operators[1]] +
['-masternode_operator=' + x for x in operators])

connect_nodes_bi(self.nodes, 0, 1)

self.log.info("Mining blocks ...")
self.nodes[0].generate(10)
self.sync_all()
self.nodes[1].generate(10)
self.sync_all()

# getmininginfo() on node[0], should only return one master node in the response array
resp0 = self.nodes[0].getmininginfo()
assert_equal(len(resp0['masternodes']), 1)

# getmininginfo() on node[1], should return two master nodes in the response array
resp1 = self.nodes[1].getmininginfo()
assert_equal(len(resp1['masternodes']), 2)

if __name__ == '__main__':
GetMiningInfoRPCTest().main()
1 change: 1 addition & 0 deletions test/functional/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
'rpc_help.py',
'feature_help.py',
'feature_shutdown.py',
'rpc_getmininginfo.py',
# Don't append tests at the end to avoid merge conflicts
# Put them in a random line within the section that fits their approximate run-time
]
Expand Down

0 comments on commit 7413fec

Please sign in to comment.