Skip to content

Commit

Permalink
Merge #2296: [RPC] Provider-Register transactions
Browse files Browse the repository at this point in the history
e754732 [RPC][Tests] Include proTx data in json formatted transactions (random-zebra)
431693f Missing lock for Masternode::SetSpent() method. (furszy)
fb60da4 [Refactoring][RPC] protx send: avoid extra serializing/unserializing (random-zebra)
4c50f7a [Refactoring][RPC] Decouple atmp/relay functions in sendrawtransaction (random-zebra)
86dcf69 [Consensus] Make masternode collateral amount a consensus param (random-zebra)
503e7da [Consensus] Prevent usage of same collateral for MN and DMN instance (random-zebra)
f218357 [RPC] Add DMN support to listmasternodes (random-zebra)
716e7ed [RPC] Deprecate startmasternode when SPORK_21 is active (random-zebra)
70fe350 [MN] Stop processing legacy masternodes after SPORK_21 is active (random-zebra)
a718654 [RPC] Block EVO rpcs before V6 enforcement (random-zebra)
214dc7f [RPC] Implement protx_list (random-zebra)
cad0f0e [RPC] Implement protx_register RPC functions (random-zebra)

Pull request description:

  Extracted from #2267. Based on top of
  - [x] #2273

  Implement `protx_register` and `protx_list` RPC commands.
  Add DMN support to `listmasternodes`.
  Deprecate `startmasternode` after SPORK_21 activation.

ACKs for top commit:
  furszy:
    code ACK e754732 after cherry-pick.
  Fuzzbawls:
    Code ACK e754732

Tree-SHA512: 92fdb8e9056bcba0dad04db39048147e2650d306c85319a9825fb3d2b50a81bb58686412a3a406bf43809186eb97fa97b449e877757ba2ac5fec7926d198116e
  • Loading branch information
random-zebra committed May 6, 2021
2 parents 6d62386 + e754732 commit ddef43d
Show file tree
Hide file tree
Showing 20 changed files with 1,018 additions and 96 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ set(SERVER_SOURCES
./src/rpc/misc.cpp
./src/rpc/net.cpp
./src/rpc/rawtransaction.cpp
./src/rpc/rpcevo.cpp
./src/rpc/server.cpp
./src/script/sigcache.cpp
./src/script/ismine.cpp
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ libbitcoin_server_a_SOURCES = \
rpc/misc.cpp \
rpc/net.cpp \
rpc/rawtransaction.cpp \
rpc/rpcevo.cpp \
rpc/server.cpp \
script/sigcache.cpp \
script/ismine.cpp \
Expand Down
13 changes: 11 additions & 2 deletions src/activemasternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,17 @@ void CActiveMasternode::ManageStatus()

LogPrint(BCLog::MASTERNODE, "CActiveMasternode::ManageStatus() - Begin\n");

// If a DMN has been registered with same collateral, disable me.
CMasternode* pmn;
pmn = mnodeman.Find(pubKeyMasternode);
if (pmn && deterministicMNManager->GetListAtChainTip().HasMNByCollateral(pmn->vin.prevout)) {
LogPrintf("%s: Disabling active legacy Masternode %s as the collateral is now registered with a DMN\n",
__func__, pmn->vin.prevout.ToString());
status = ACTIVE_MASTERNODE_NOT_CAPABLE;
notCapableReason = "Collateral registered with DMN";
return;
}

//need correct blocks to send ping
if (!Params().IsRegTestNet() && !masternodeSync.IsBlockchainSynced()) {
status = ACTIVE_MASTERNODE_SYNC_IN_PROCESS;
Expand All @@ -272,8 +283,6 @@ void CActiveMasternode::ManageStatus()
if (status == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) status = ACTIVE_MASTERNODE_INITIAL;

if (status == ACTIVE_MASTERNODE_INITIAL) {
CMasternode* pmn;
pmn = mnodeman.Find(pubKeyMasternode);
if (pmn != nullptr) {
if (pmn->IsEnabled() && pmn->protocolVersion == PROTOCOL_VERSION)
EnableHotColdMasterNode(pmn->vin, pmn->addr);
Expand Down
3 changes: 3 additions & 0 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class CMainParams : public CChainParams
consensus.nFutureTimeDriftPoW = 7200;
consensus.nFutureTimeDriftPoS = 180;
consensus.nMaxMoneyOut = 21000000 * COIN;
consensus.nMNCollateralAmt = 10000 * COIN;
consensus.nPoolMaxTransactions = 3;
consensus.nProposalEstablishmentTime = 60 * 60 * 24; // must be at least a day old to make it into a budget
consensus.nStakeMinAge = 60 * 60;
Expand Down Expand Up @@ -283,6 +284,7 @@ class CTestNetParams : public CChainParams
consensus.nFutureTimeDriftPoW = 7200;
consensus.nFutureTimeDriftPoS = 180;
consensus.nMaxMoneyOut = 21000000 * COIN;
consensus.nMNCollateralAmt = 10000 * COIN;
consensus.nPoolMaxTransactions = 3;
consensus.nProposalEstablishmentTime = 60 * 5; // at least 5 min old to make it into a budget
consensus.nStakeMinAge = 60 * 60;
Expand Down Expand Up @@ -406,6 +408,7 @@ class CRegTestParams : public CChainParams
consensus.nFutureTimeDriftPoW = 7200;
consensus.nFutureTimeDriftPoS = 180;
consensus.nMaxMoneyOut = 43199500 * COIN;
consensus.nMNCollateralAmt = 100 * COIN;
consensus.nPoolMaxTransactions = 2;
consensus.nProposalEstablishmentTime = 60 * 5; // at least 5 min old to make it into a budget
consensus.nStakeMinAge = 0;
Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ struct Params {
int nFutureTimeDriftPoW;
int nFutureTimeDriftPoS;
CAmount nMaxMoneyOut;
CAmount nMNCollateralAmt;
int nPoolMaxTransactions;
int64_t nProposalEstablishmentTime;
int nStakeMinAge;
Expand Down
19 changes: 15 additions & 4 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
#include "core_io.h"
#include "evo/specialtx.h"
#include "guiinterface.h"
#include "masternode.h" // for MN_COLL_AMT, MasternodeCollateralMinConf
#include "masternode.h" // for MasternodeCollateralMinConf
#include "masternodeman.h" // for mnodeman (!TODO: remove)
#include "script/standard.h"
#include "spork.h"
#include "sync.h"
Expand Down Expand Up @@ -90,14 +91,15 @@ void CDeterministicMN::ToJson(UniValue& obj) const
obj.pushKV("collateralHash", collateralOutpoint.hash.ToString());
obj.pushKV("collateralIndex", (int)collateralOutpoint.n);

std::string collateralAddressStr = "";
Coin coin;
if (GetUTXOCoin(collateralOutpoint, coin)) {
CTxDestination dest;
if (ExtractDestination(coin.out.scriptPubKey, dest)) {
obj.pushKV("collateralAddress", EncodeDestination(dest));
collateralAddressStr = EncodeDestination(dest);
}
}

obj.pushKV("collateralAddress", collateralAddressStr);
obj.pushKV("operatorReward", (double)nOperatorReward / 100);
obj.pushKV("dmnstate", stateObj);
}
Expand Down Expand Up @@ -651,8 +653,17 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
dmn->collateralOutpoint = pl.collateralOutpoint.hash.IsNull() ? COutPoint(tx.GetHash(), pl.collateralOutpoint.n)
: pl.collateralOutpoint;

// if the collateral outpoint appears in the legacy masternode list, remove the old node
// !TODO: remove this when the transition to DMN is complete
CMasternode* old_mn = mnodeman.Find(dmn->collateralOutpoint);
if (old_mn) {
old_mn->SetSpent();
mnodeman.CheckAndRemove();
}

Coin coin;
if (!pl.collateralOutpoint.hash.IsNull() && (!GetUTXOCoin(pl.collateralOutpoint, coin) || coin.out.nValue != MN_COLL_AMT)) {
const CAmount collAmt = Params().GetConsensus().nMNCollateralAmt;
if (!pl.collateralOutpoint.hash.IsNull() && (!GetUTXOCoin(pl.collateralOutpoint, coin) || coin.out.nValue != collAmt)) {
// should actually never get to this point as CheckProRegTx should have handled this case.
// We do this additional check nevertheless to be 100% sure
return _state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral");
Expand Down
5 changes: 2 additions & 3 deletions src/evo/providertx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ static bool CheckStringSig(const Payload& pl, const CKeyID& keyID, CValidationSt
template <typename Payload>
static bool CheckInputsHash(const CTransaction& tx, const Payload& pl, CValidationState& state)
{
uint256 inputsHash = CalcTxInputsHash(tx);
if (inputsHash != pl.inputsHash) {
if (CalcTxInputsHash(tx) != pl.inputsHash) {
return state.DoS(100, false, REJECT_INVALID, "bad-protx-inputs-hash");
}

Expand All @@ -78,7 +77,7 @@ static bool CheckCollateralOut(const CTxOut& out, const ProRegPL& pl, CValidatio
return state.DoS(10, false, REJECT_INVALID, "bad-protx-collateral-reuse");
}
// check collateral amount
if (out.nValue != MN_COLL_AMT) {
if (out.nValue != Params().GetConsensus().nMNCollateralAmt) {
return state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral-amount");
}
return true;
Expand Down
4 changes: 3 additions & 1 deletion src/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ bool CMasternode::IsInputAssociatedWithPubkey() const
uint256 hash;
if(GetTransaction(vin.prevout.hash, txVin, hash, true)) {
for (const CTxOut& out : txVin->vout) {
if (out.nValue == MN_COLL_AMT && out.scriptPubKey == payee) return true;
if (out.nValue == Params().GetConsensus().nMNCollateralAmt &&
out.scriptPubKey == payee)
return true;
}
}

Expand Down
10 changes: 5 additions & 5 deletions src/masternode.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
/* Depth of the block pinged by masternodes */
static const unsigned int MNPING_DEPTH = 12;

/* Masternode collateral amount */
static const CAmount MN_COLL_AMT = 10000 * COIN;


class CMasternode;
class CMasternodeBroadcast;
class CMasternodePing;
Expand Down Expand Up @@ -193,7 +189,11 @@ class CMasternode : public CSignedMessage
return lastPing.IsNull() ? false : now - lastPing.sigTime < seconds;
}

void SetSpent() { fCollateralSpent = true; }
void SetSpent()
{
LOCK(cs);
fCollateralSpent = true;
}

void Disable()
{
Expand Down
57 changes: 54 additions & 3 deletions src/masternodeman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "masternodeman.h"

#include "addrman.h"
#include "evo/deterministicmns.h"
#include "fs.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
Expand Down Expand Up @@ -175,6 +176,17 @@ CMasternodeMan::CMasternodeMan():

bool CMasternodeMan::Add(CMasternode& mn)
{
// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
return false;
}

if (deterministicMNManager->GetListAtChainTip().HasMNByCollateral(mn.vin.prevout)) {
LogPrint(BCLog::MASTERNODE, "ERROR: Not Adding Masternode %s as the collateral is already registered with a DMN\n",
mn.vin.prevout.ToString());
return false;
}

LOCK(cs);

if (!mn.IsAvailableState())
Expand All @@ -193,6 +205,11 @@ bool CMasternodeMan::Add(CMasternode& mn)

void CMasternodeMan::AskForMN(CNode* pnode, const CTxIn& vin)
{
// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
return;
}

std::map<COutPoint, int64_t>::iterator i = mWeAskedForMasternodeListEntry.find(vin.prevout);
if (i != mWeAskedForMasternodeListEntry.end()) {
int64_t t = (*i).second;
Expand All @@ -211,7 +228,14 @@ int CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval)
{
LOCK(cs);

//remove inactive and outdated
// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
LogPrint(BCLog::MASTERNODE, "Removing all legacy mn due to SPORK 21\n");
Clear();
return 0;
}

//remove inactive and outdated (or replaced by DMN)
auto it = mapMasternodes.begin();
while (it != mapMasternodes.end()) {
MasternodeRef& mn = it->second;
Expand All @@ -220,8 +244,7 @@ int CMasternodeMan::CheckAndRemove(bool forceExpiredRemoval)
activeState == CMasternode::MASTERNODE_VIN_SPENT ||
(forceExpiredRemoval && activeState == CMasternode::MASTERNODE_EXPIRED) ||
mn->protocolVersion < ActiveProtocol()) {
LogPrint(BCLog::MASTERNODE, "Removing inactive Masternode %s\n", it->first.ToString());

LogPrint(BCLog::MASTERNODE, "Removing inactive (legacy) Masternode %s\n", it->first.ToString());
//erase all of the broadcasts we've seen from this vin
// -- if we missed a few pings and the node was removed, this will allow is to get it back without them
// sending a brand new mnb
Expand Down Expand Up @@ -386,6 +409,11 @@ int CMasternodeMan::CountNetworks(int& ipv4, int& ipv6, int& onion) const

void CMasternodeMan::DsegUpdate(CNode* pnode)
{
// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
return;
}

LOCK(cs);

if (Params().NetworkIDString() == CBaseChainParams::MAIN) {
Expand Down Expand Up @@ -433,6 +461,11 @@ CMasternode* CMasternodeMan::Find(const CPubKey& pubKeyMasternode)

void CMasternodeMan::CheckSpentCollaterals(const std::vector<CTransactionRef>& vtx)
{
// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
return;
}

LOCK(cs);
for (const auto& tx : vtx) {
for (const auto& in : tx->vin) {
Expand Down Expand Up @@ -687,6 +720,12 @@ int CMasternodeMan::ProcessMNPing(CNode* pfrom, CMasternodePing& mnp)

int CMasternodeMan::ProcessGetMNList(CNode* pfrom, CTxIn& vin)
{
// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
LogPrint(BCLog::MASTERNODE, "dseg - skip obsolete message\n");
return 0;
}

if (vin.IsNull()) { //only should ask for this once
//local network
bool isLocal = (pfrom->addr.IsRFC1918() || pfrom->addr.IsLocal());
Expand Down Expand Up @@ -754,6 +793,12 @@ int CMasternodeMan::ProcessMessageInner(CNode* pfrom, std::string& strCommand, C
if (fLiteMode) return 0; //disable all Masternode related functionality
if (!masternodeSync.IsBlockchainSynced()) return 0;

// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
LogPrint(BCLog::MASTERNODE, "%s: skip obsolete message %s\n", __func__, strCommand);
return 0;
}

LOCK(cs_process_message);

if (strCommand == NetMsgType::MNBROADCAST) {
Expand Down Expand Up @@ -789,6 +834,12 @@ void CMasternodeMan::Remove(const COutPoint& collateralOut)

void CMasternodeMan::UpdateMasternodeList(CMasternodeBroadcast& mnb)
{
// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
LogPrint(BCLog::MASTERNODE, "Removing all legacy mn due to SPORK 21\n");
return;
}

mapSeenMasternodePing.emplace(mnb.lastPing.GetHash(), mnb.lastPing);
mapSeenMasternodeBroadcast.emplace(mnb.GetHash(), mnb);
masternodeSync.AddedMasternodeList(mnb.GetHash());
Expand Down
2 changes: 1 addition & 1 deletion src/qt/pivx/masternodewizarddialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ bool MasterNodeWizardDialog::createMN()
int indexOut = -1;
for (int i=0; i < (int)walletTx->vout.size(); i++) {
const CTxOut& out = walletTx->vout[i];
if (out.nValue == MN_COLL_AMT) {
if (out.nValue == Params().GetConsensus().nMNCollateralAmt) {
indexOut = i;
break;
}
Expand Down
46 changes: 42 additions & 4 deletions src/rpc/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "activemasternode.h"
#include "db.h"
#include "evo/deterministicmns.h"
#include "init.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
Expand Down Expand Up @@ -99,12 +100,25 @@ UniValue getcachedblockhashes(const JSONRPCRequest& request)
return ret;
}

UniValue listmasternodes(const JSONRPCRequest& request)
static inline bool filter(const std::string& str, const std::string& strFilter)
{
std::string strFilter = "";
return str.find(strFilter) != std::string::npos;
}

if (request.params.size() == 1) strFilter = request.params[0].get_str();
static inline bool filterMasternode(const UniValue& dmno, const std::string& strFilter, bool fEnabled)
{
return strFilter.empty() || (filter("ENABLED", strFilter) && fEnabled)
|| (filter("POSE_BANNED", strFilter) && !fEnabled)
|| (filter(dmno["proTxHash"].get_str(), strFilter))
|| (filter(dmno["collateralHash"].get_str(), strFilter))
|| (filter(dmno["collateralAddress"].get_str(), strFilter))
|| (filter(dmno["dmnstate"]["ownerAddress"].get_str(), strFilter))
|| (filter(dmno["dmnstate"]["operatorAddress"].get_str(), strFilter))
|| (filter(dmno["dmnstate"]["votingAddress"].get_str(), strFilter));
}

UniValue listmasternodes(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() > 1))
throw std::runtime_error(
"listmasternodes ( \"filter\" )\n"
Expand All @@ -113,6 +127,7 @@ UniValue listmasternodes(const JSONRPCRequest& request)
"\nArguments:\n"
"1. \"filter\" (string, optional) Filter search text. Partial match by txhash, status, or addr.\n"

// !TODO: update for DMNs
"\nResult:\n"
"[\n"
" {\n"
Expand All @@ -133,7 +148,25 @@ UniValue listmasternodes(const JSONRPCRequest& request)
"\nExamples:\n" +
HelpExampleCli("listmasternodes", "") + HelpExampleRpc("listmasternodes", ""));


const std::string& strFilter = request.params.size() > 0 ? request.params[0].get_str() : "";
UniValue ret(UniValue::VARR);

auto mnList = deterministicMNManager->GetListAtChainTip();
mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
UniValue obj(UniValue::VOBJ);
dmn->ToJson(obj);
bool fEnabled = dmn->pdmnState->nPoSeBanHeight == -1;
if (filterMasternode(obj, strFilter, fEnabled)) {
// Added for backward compatibility. can be removed later.
obj.pushKV("txhash", obj["proTxHash"].get_str());

obj.pushKV("status", fEnabled ? "ENABLED" : "POSE_BANNED");
ret.push_back(obj);
}
});

// Legacy masternodes (!TODO: remove when transition to dmn is complete)
const CBlockIndex* chainTip = GetChainTip();
if (!chainTip) return "[]";
int nHeight = chainTip->nHeight;
Expand Down Expand Up @@ -315,8 +348,13 @@ void SerializeMNB(UniValue& statusObjRet, const CMasternodeBroadcast& mnb, const
return SerializeMNB(statusObjRet, mnb, fSuccess, successful, failed);
}

UniValue startmasternode (const JSONRPCRequest& request)
UniValue startmasternode(const JSONRPCRequest& request)
{
// Skip after legacy obsolete. !TODO: remove when transition to DMN is complete
if (deterministicMNManager->LegacyMNObsolete()) {
throw JSONRPCError(RPC_MISC_ERROR, "startmasternode is not supported when deterministic masternode list is active (DIP3)");
}

std::string strCommand;
if (request.params.size() >= 1) {
strCommand = request.params[0].get_str();
Expand Down
Loading

0 comments on commit ddef43d

Please sign in to comment.