Skip to content

Commit

Permalink
Feature masternode rewardaddress (#642)
Browse files Browse the repository at this point in the history
* added rewardAddress in masternode class

* setforcedrewardaddress rpc

* setforcedrewardaddress apply

* RemoveForcedRewardAddress rpc and apply

* coinbase script from mn reward address

* SetForecedrewardAddress tx code to type and make scriptPubKey

* functional test and isMine check

* fix typo and functional test for -gen param

* linter fix

* mn messages refactoring

* FUpgradeHeight hardfork

* fuheight check for tx

* Optimize code and address comments

* Enable parallel builds on docker containers (#659)

* Refactor code

* Refactor code

* RFix redundant code duing rebasing

* Using enum instead of number

* Remove redundant check

Co-authored-by: DefiDev <[email protected]>
Co-authored-by: Prasanna Loganathar <[email protected]>
Co-authored-by: Peter John Bushnell <[email protected]>
  • Loading branch information
4 people authored Oct 20, 2021
1 parent 8e9f812 commit 28c93c4
Show file tree
Hide file tree
Showing 13 changed files with 567 additions and 36 deletions.
12 changes: 1 addition & 11 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,17 +915,7 @@ void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
consensus.EunosKampungHeight = static_cast<int>(eunosHeight.get());
}
UpdateHeightValidation("Eunos Paya", "-eunospayaheight", consensus.EunosPayaHeight);

if (gArgs.IsArgSet("-fortcanningheight")) {
int64_t height = gArgs.GetArg("-fortcanningheight", consensus.FortCanningHeight);
if (height < -1 || height >= std::numeric_limits<int>::max()) {
throw std::runtime_error(strprintf("Activation height %ld for Fort Canning is out of valid range. Use -1 to disable Fort Canning features.", height));
} else if (height == -1) {
LogPrintf("Fort Canning disabled for testing\n");
height = std::numeric_limits<int>::max();
}
consensus.FortCanningHeight = static_cast<int>(height);
}
UpdateHeightValidation("Fork canning", "-fortcanningheight", consensus.FortCanningHeight);

if (!args.IsArgSet("-vbparams")) return;

Expand Down
55 changes: 34 additions & 21 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1997,30 +1997,43 @@ bool AppInitMain(InitInterfaces& interfaces)
continue;
}

auto const rewardAddressStr = gArgs.GetArg("-rewardaddress", "");
CTxDestination const rewardAddress = rewardAddressStr.empty() ? CNoDestination{} :
DecodeDestination(rewardAddressStr, chainparams);
if (IsValidDestination(rewardAddress)) {
coinbaseScript = GetScriptForDestination(rewardAddress);
LogPrintf("Default minting address was overlapped by -rewardaddress=%s\n", rewardAddressStr);
} else {
// determine coinbase script for minting thread
CTxDestination ownerDest;
auto optMasternodeID = pcustomcsview->GetMasternodeIdByOperator(operatorId);
if (optMasternodeID) {
auto nodePtr = pcustomcsview->GetMasternode(*optMasternodeID);
assert(nodePtr); // this should not happen if MN was found by operator's id
ownerDest = nodePtr->ownerType == 1 ? CTxDestination(PKHash(nodePtr->ownerAuthAddress)) :
CTxDestination(WitnessV0KeyHash(nodePtr->ownerAuthAddress));
}
if (IsValidDestination(ownerDest)) {
coinbaseScript = GetScriptForDestination(ownerDest);
LogPrintf("Minting thread will start with default address %s\n", EncodeDestination(ownerDest));
} else {
LogPrintf("Minting thread will start with empty coinbase address cause masternode does not exist yet. Correct address will be resolved later.\n");
// determine coinbase script for minting thread
auto const customRewardAddressStr = gArgs.GetArg("-rewardaddress", "");
CTxDestination const customRewardDest = customRewardAddressStr.empty() ?
CNoDestination{} :
DecodeDestination(customRewardAddressStr, chainparams);

CTxDestination ownerDest;
CTxDestination rewardDest;
auto optMasternodeID = pcustomcsview->GetMasternodeIdByOperator(operatorId);
if (optMasternodeID) {
auto nodePtr = pcustomcsview->GetMasternode(*optMasternodeID);
assert(nodePtr); // this should not happen if MN was found by operator's id
ownerDest = nodePtr->ownerType == PKHashType ?
CTxDestination(PKHash(nodePtr->ownerAuthAddress)) :
CTxDestination(WitnessV0KeyHash(nodePtr->ownerAuthAddress));
if (nodePtr->rewardAddressType != 0) {
rewardDest = nodePtr->rewardAddressType == PKHashType ?
CTxDestination(PKHash(nodePtr->rewardAddress)) :
CTxDestination(WitnessV0KeyHash(nodePtr->rewardAddress));
}
}

if (IsValidDestination(rewardDest)) {
coinbaseScript = GetScriptForDestination(rewardDest);
LogPrintf("Minting thread will start with reward address %s\n", EncodeDestination(rewardDest));
}
else if (IsValidDestination(customRewardDest)) {
coinbaseScript = GetScriptForDestination(customRewardDest);
LogPrintf("Default minting address was overlapped by -rewardaddress=%s\n", customRewardAddressStr);
}
else if (IsValidDestination(ownerDest)) {
coinbaseScript = GetScriptForDestination(ownerDest);
LogPrintf("Minting thread will start with default address %s\n", EncodeDestination(ownerDest));
}
else {
LogPrintf("Minting thread will start with empty coinbase address cause masternode does not exist yet. Correct address will be resolved later.\n");
}
stakersParams.push_back(std::move(stakerParams));
atLeastOneRunningOperator = true;
}
Expand Down
40 changes: 40 additions & 0 deletions src/masternodes/masternodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ CMasternode::CMasternode()
, ownerType(0)
, operatorAuthAddress()
, operatorType(0)
, rewardAddress()
, rewardAddressType(0)
, creationHeight(0)
, resignHeight(-1)
, unusedVariable(-1)
Expand Down Expand Up @@ -158,6 +160,8 @@ bool operator==(CMasternode const & a, CMasternode const & b)
a.ownerAuthAddress == b.ownerAuthAddress &&
a.operatorType == b.operatorType &&
a.operatorAuthAddress == b.operatorAuthAddress &&
a.rewardAddress == b.rewardAddress &&
a.rewardAddressType == b.rewardAddressType &&
a.creationHeight == b.creationHeight &&
a.resignHeight == b.resignHeight &&
a.unusedVariable == b.unusedVariable &&
Expand Down Expand Up @@ -323,6 +327,42 @@ Res CMasternodesView::ResignMasternode(const uint256 & nodeId, const uint256 & t
return Res::Ok();
}

Res CMasternodesView::SetForcedRewardAddress(uint256 const & nodeId, const char rewardAddressType, CKeyID const & rewardAddress, int height)
{
auto node = GetMasternode(nodeId);
if (!node) {
return Res::Err("masternode %s does not exists", nodeId.ToString());
}
auto state = node->GetState(height);
if ((state != CMasternode::PRE_ENABLED && state != CMasternode::ENABLED)) {
return Res::Err("masternode %s state is not 'PRE_ENABLED' or 'ENABLED'", nodeId.ToString());
}

node->rewardAddressType = rewardAddressType;
node->rewardAddress = rewardAddress;
WriteBy<ID>(nodeId, *node);

return Res::Ok();
}

Res CMasternodesView::RemForcedRewardAddress(uint256 const & nodeId, int height)
{
auto node = GetMasternode(nodeId);
if (!node) {
return Res::Err("masternode %s does not exists", nodeId.ToString());
}
auto state = node->GetState(height);
if ((state != CMasternode::PRE_ENABLED && state != CMasternode::ENABLED)) {
return Res::Err("masternode %s state is not 'PRE_ENABLED' or 'ENABLED'", nodeId.ToString());
}

node->rewardAddressType = 0;
node->rewardAddress.SetNull();
WriteBy<ID>(nodeId, *node);

return Res::Ok();
}

void CMasternodesView::SetMasternodeLastBlockTime(const CKeyID & minter, const uint32_t &blockHeight, const int64_t& time)
{
auto nodeId = GetMasternodeIdByOperator(minter);
Expand Down
8 changes: 8 additions & 0 deletions src/masternodes/masternodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ class CMasternode
CKeyID operatorAuthAddress;
char operatorType;

//! Consensus-enforced address for operator rewards.
CKeyID rewardAddress;
char rewardAddressType;

//! MN creation block height
int32_t creationHeight;
//! Resign height
Expand Down Expand Up @@ -104,6 +108,8 @@ class CMasternode
READWRITE(ownerType);
READWRITE(operatorAuthAddress);
READWRITE(operatorType);
READWRITE(rewardAddress);
READWRITE(rewardAddressType);

READWRITE(creationHeight);
READWRITE(resignHeight);
Expand Down Expand Up @@ -188,6 +194,8 @@ class CMasternodesView : public virtual CStorageView
Res ResignMasternode(uint256 const & nodeId, uint256 const & txid, int height);
Res UnCreateMasternode(uint256 const & nodeId);
Res UnResignMasternode(uint256 const & nodeId, uint256 const & resignTx);
Res SetForcedRewardAddress(uint256 const & nodeId, const char rewardAddressType, CKeyID const & rewardAddress, int height);
Res RemForcedRewardAddress(uint256 const & nodeId, int height);

// Get blocktimes for non-subnode and subnode with fork logic
std::vector<int64_t> GetBlockTimes(const CKeyID& keyID, const uint32_t blockHeight, const int32_t creationHeight, const uint16_t timelock);
Expand Down
38 changes: 38 additions & 0 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ std::string ToString(CustomTxType type) {
{
case CustomTxType::CreateMasternode: return "CreateMasternode";
case CustomTxType::ResignMasternode: return "ResignMasternode";
case CustomTxType::SetForcedRewardAddress: return "SetForcedRewardAddress";
case CustomTxType::RemForcedRewardAddress: return "RemForcedRewardAddress";
case CustomTxType::CreateToken: return "CreateToken";
case CustomTxType::UpdateToken: return "UpdateToken";
case CustomTxType::UpdateTokenAny: return "UpdateTokenAny";
Expand Down Expand Up @@ -120,6 +122,8 @@ CCustomTxMessage customTypeToMessage(CustomTxType txType) {
{
case CustomTxType::CreateMasternode: return CCreateMasterNodeMessage{};
case CustomTxType::ResignMasternode: return CResignMasterNodeMessage{};
case CustomTxType::SetForcedRewardAddress: return CSetForcedRewardAddressMessage{};
case CustomTxType::RemForcedRewardAddress: return CRemForcedRewardAddressMessage{};
case CustomTxType::CreateToken: return CCreateTokenMessage{};
case CustomTxType::UpdateToken: return CUpdateTokenPreAMKMessage{};
case CustomTxType::UpdateTokenAny: return CUpdateTokenMessage{};
Expand Down Expand Up @@ -245,6 +249,16 @@ class CCustomMetadataParseVisitor : public boost::static_visitor<Res>
return serialize(obj);
}

Res operator()(CSetForcedRewardAddressMessage& obj) const {
auto res = isPostFortCanningFork();
return !res ? res : serialize(obj);
}

Res operator()(CRemForcedRewardAddressMessage& obj) const {
auto res = isPostFortCanningFork();
return !res ? res : serialize(obj);
}

Res operator()(CCreateTokenMessage& obj) const {
auto res = isPostAMKFork();
return !res ? res : serialize(obj);
Expand Down Expand Up @@ -872,6 +886,30 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
return !res ? res : mnview.ResignMasternode(obj, tx.GetHash(), height);
}

Res operator()(const CSetForcedRewardAddressMessage& obj) const {
auto const node = mnview.GetMasternode(obj.nodeId);
if (!node) {
return Res::Err("masternode %s does not exist", obj.nodeId.ToString());
}
if (!HasCollateralAuth(obj.nodeId)) {
return Res::Err("%s: %s", obj.nodeId.ToString(), "tx must have at least one input from masternode owner");
}

return mnview.SetForcedRewardAddress(obj.nodeId, obj.rewardAddressType, obj.rewardAddress, height);
}

Res operator()(const CRemForcedRewardAddressMessage& obj) const {
auto const node = mnview.GetMasternode(obj.nodeId);
if (!node) {
return Res::Err("masternode %s does not exist", obj.nodeId.ToString());
}
if (!HasCollateralAuth(obj.nodeId)) {
return Res::Err("%s: %s", obj.nodeId.ToString(), "tx must have at least one input from masternode owner");
}

return mnview.RemForcedRewardAddress(obj.nodeId, height);
}

Res operator()(const CCreateTokenMessage& obj) const {
auto res = CheckTokenCreationTx();
if (!res) {
Expand Down
38 changes: 36 additions & 2 deletions src/masternodes/mn_checks.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ enum class CustomTxType : uint8_t
Reject = 1, // Invalid TX type. Returned by GuessCustomTxType on invalid custom TX.

// masternodes:
CreateMasternode = 'C',
ResignMasternode = 'R',
CreateMasternode = 'C',
ResignMasternode = 'R',
SetForcedRewardAddress = 'F',
RemForcedRewardAddress = 'f',
// custom tokens:
CreateToken = 'T',
MintToken = 'M',
Expand Down Expand Up @@ -100,6 +102,8 @@ inline CustomTxType CustomTxCodeToType(uint8_t ch) {
switch(type) {
case CustomTxType::CreateMasternode:
case CustomTxType::ResignMasternode:
case CustomTxType::SetForcedRewardAddress:
case CustomTxType::RemForcedRewardAddress:
case CustomTxType::CreateToken:
case CustomTxType::MintToken:
case CustomTxType::UpdateToken:
Expand Down Expand Up @@ -198,6 +202,34 @@ struct CResignMasterNodeMessage : public uint256 {
}
};

struct CSetForcedRewardAddressMessage {
uint256 nodeId;
char rewardAddressType;
CKeyID rewardAddress;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(nodeId);
READWRITE(rewardAddressType);
READWRITE(rewardAddress);
}
};

struct CRemForcedRewardAddressMessage {
uint256 nodeId;

ADD_SERIALIZE_METHODS;

template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action)
{
READWRITE(nodeId);
}
};

struct CCreateTokenMessage : public CToken {
using CToken::CToken;

Expand Down Expand Up @@ -271,6 +303,8 @@ typedef boost::variant<
CCustomTxMessageNone,
CCreateMasterNodeMessage,
CResignMasterNodeMessage,
CSetForcedRewardAddressMessage,
CRemForcedRewardAddressMessage,
CCreateTokenMessage,
CUpdateTokenPreAMKMessage,
CUpdateTokenMessage,
Expand Down
13 changes: 13 additions & 0 deletions src/masternodes/rpc_customtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ class CCustomTxRpcVisitor : public boost::static_visitor<void>
rpcInfo.pushKV("id", obj.GetHex());
}

void operator()(const CSetForcedRewardAddressMessage& obj) const {
rpcInfo.pushKV("mc_id", obj.nodeId.GetHex());
rpcInfo.pushKV("rewardAddress", EncodeDestination(
obj.rewardAddressType == 1 ?
CTxDestination(PKHash(obj.rewardAddress)) :
CTxDestination(WitnessV0KeyHash(obj.rewardAddress)))
);
}

void operator()(const CRemForcedRewardAddressMessage& obj) const {
rpcInfo.pushKV("mc_id", obj.nodeId.GetHex());
}

void operator()(const CCreateTokenMessage& obj) const {
rpcInfo.pushKV("creationTx", tx.GetHash().GetHex());
tokenInfo(obj);
Expand Down
Loading

0 comments on commit 28c93c4

Please sign in to comment.