Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RPC updatemasternode call #1437

Merged
merged 3 commits into from
Sep 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,27 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
return nSigOps;
}

bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, const CCustomCSView * mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams)
bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, CCustomCSView& mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams)
{
// are the actual inputs available?
if (!inputs.HaveInputs(tx)) {
return state.Invalid(ValidationInvalidReason::TX_MISSING_INPUTS, false, REJECT_INVALID, "bad-txns-inputs-missingorspent",
strprintf("%s: inputs missing/spent", __func__));
}

// check for tokens values
uint256 canSpend;
std::vector<unsigned char> dummy;
const auto txType = GuessCustomTxType(tx, dummy);

if (NotAllowedToFail(txType, nSpendHeight) || (nSpendHeight >= chainparams.GetConsensus().GrandCentralHeight && txType == CustomTxType::UpdateMasternode)) {
CCustomCSView discardCache(mnview);
auto res = ApplyCustomTx(discardCache, inputs, tx, chainparams.GetConsensus(), nSpendHeight, 0, &canSpend);
if (!res.ok && (res.code & CustomTxErrCodes::Fatal)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-customtx", res.msg);
}
}

TAmounts nValuesIn;
for (unsigned int i = 0; i < tx.vin.size(); ++i) {
const COutPoint &prevout = tx.vin[i].prevout;
Expand All @@ -187,8 +200,7 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
}
/// @todo tokens: later match the range with TotalSupply

if (prevout.n == 1 && !mnview->CanSpend(prevout.hash, nSpendHeight)) {
if (canSpend != prevout.hash && prevout.n == 1 && !mnview.CanSpend(prevout.hash, nSpendHeight)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-collateral-locked",
strprintf("tried to spend locked collateral for %s", prevout.hash.ToString())); /// @todo may be somehow place the height of unlocking?
}
Expand All @@ -215,18 +227,6 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-tokens-in-old-version-tx");
}

// check for tokens values
std::vector<unsigned char> dummy;
const auto txType = GuessCustomTxType(tx, dummy);

if (NotAllowedToFail(txType, nSpendHeight)) {
CCustomCSView discardCache(const_cast<CCustomCSView&>(*mnview));
auto res = ApplyCustomTx(discardCache, inputs, tx, chainparams.GetConsensus(), nSpendHeight);
if (!res.ok && (res.code & CustomTxErrCodes::Fatal)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-txns-customtx", res.msg);
}
}

for (auto const & kv : non_minted_values_out) {
DCT_ID const & tokenId = kv.first;

Expand Down
2 changes: 1 addition & 1 deletion src/consensus/tx_verify.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace Consensus {
* @param[out] txfee Set to the transaction fee if successful.
* Preconditions: tx.IsCoinBase() is false.
*/
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, const CCustomCSView * mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams);
bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, CCustomCSView& mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams);
} // namespace Consensus

/** Auxiliary functions for transaction validation (ideally should not be exposed) */
Expand Down
2 changes: 1 addition & 1 deletion src/masternodes/anchors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,7 @@ bool CAnchorAwaitingConfirms::Validate(CAnchorConfirmMessage const &confirmMessa
}

auto it = pcustomcsview->GetMasternodeIdByOperator(signer);
if (!it || !pcustomcsview->GetMasternode(*it)->IsActive(height)) {
if (!it || !pcustomcsview->GetMasternode(*it)->IsActive(height, *pcustomcsview)) {
LogPrint(BCLog::ANCHORING, "%s: Warning! Masternode with operator key %s does not exist or not active!\n", __func__, signer.ToString());
return false;
}
Expand Down
163 changes: 84 additions & 79 deletions src/masternodes/masternodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.

#include <masternodes/masternodes.h>

#include <masternodes/accountshistory.h>
#include <masternodes/anchors.h>
#include <masternodes/govvariables/attributes.h>
Expand Down Expand Up @@ -87,18 +88,28 @@ CMasternode::CMasternode()
, resignHeight(-1)
, version(-1)
, resignTx()
, banTx()
, collateralTx()
{
}

CMasternode::State CMasternode::GetState(int height) const
CMasternode::State CMasternode::GetState(int height, const CMasternodesView& mnview) const
{
int EunosPayaHeight = Params().GetConsensus().EunosPayaHeight;

if (height < creationHeight) {
return State::UNKNOWN;
}

if (!collateralTx.IsNull()) {
auto idHeight = mnview.GetNewCollateral(collateralTx);
assert(idHeight);
if (static_cast<uint32_t>(height) < idHeight->blockHeight) {
return State::TRANSFERRING;
} else if (static_cast<uint32_t>(height) < idHeight->blockHeight + GetMnActivationDelay(idHeight->blockHeight)) {
return State::PRE_ENABLED;
}
}

if (resignHeight == -1 || height < resignHeight) { // enabled or pre-enabled
// Special case for genesis block
int activationDelay = height < EunosPayaHeight ? GetMnActivationDelay(height) : GetMnActivationDelay(creationHeight);
Expand All @@ -118,9 +129,9 @@ CMasternode::State CMasternode::GetState(int height) const
return State::UNKNOWN;
}

bool CMasternode::IsActive(int height) const
bool CMasternode::IsActive(int height, const CMasternodesView& mnview) const
{
State state = GetState(height);
State state = GetState(height, mnview);
if (height >= Params().GetConsensus().EunosPayaHeight) {
return state == ENABLED;
}
Expand All @@ -138,6 +149,8 @@ std::string CMasternode::GetHumanReadableState(State state)
return "PRE_RESIGNED";
case RESIGNED:
return "RESIGNED";
case TRANSFERRING:
return "TRANSFERRING";
default:
return "UNKNOWN";
}
Expand Down Expand Up @@ -165,7 +178,7 @@ bool operator==(CMasternode const & a, CMasternode const & b)
a.resignHeight == b.resignHeight &&
a.version == b.version &&
a.resignTx == b.resignTx &&
a.banTx == b.banTx
a.collateralTx == b.collateralTx
);
}

Expand Down Expand Up @@ -294,14 +307,9 @@ Res CMasternodesView::CreateMasternode(const uint256 & nodeId, const CMasternode
return Res::Ok();
}

Res CMasternodesView::ResignMasternode(const uint256 & nodeId, const uint256 & txid, int height)
Res CMasternodesView::ResignMasternode(CMasternode& node, const uint256 & nodeId, const uint256 & txid, int height)
{
// auth already checked!
auto node = GetMasternode(nodeId);
if (!node) {
return Res::Err("node %s does not exists", nodeId.ToString());
}
auto state = node->GetState(height);
auto state = node.GetState(height, *this);
if (height >= Params().GetConsensus().EunosPayaHeight) {
if (state != CMasternode::ENABLED) {
return Res::Err("node %s state is not 'ENABLED'", nodeId.ToString());
Expand All @@ -310,96 +318,85 @@ Res CMasternodesView::ResignMasternode(const uint256 & nodeId, const uint256 & t
return Res::Err("node %s state is not 'PRE_ENABLED' or 'ENABLED'", nodeId.ToString());
}

const auto timelock = GetTimelock(nodeId, *node, height);
const auto timelock = GetTimelock(nodeId, node, height);
if (timelock) {
return Res::Err("Trying to resign masternode before timelock expiration.");
}

node->resignTx = txid;
node->resignHeight = height;
WriteBy<ID>(nodeId, *node);
node.resignTx = txid;
node.resignHeight = height;
WriteBy<ID>(nodeId, node);

return Res::Ok();
}

Res CMasternodesView::SetForcedRewardAddress(uint256 const & nodeId, const char rewardAddressType, CKeyID const & rewardAddress, int height)
void CMasternodesView::SetForcedRewardAddress(uint256 const & nodeId, CMasternode& node, const char rewardAddressType, CKeyID const & rewardAddress, int height)
{
// Temporarily disabled for 2.2
return Res::Err("reward address change is disabled for Fort Canning");

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());
}

// If old masternode update foor new serialisatioono
if (node->version < CMasternode::VERSION0) {
node->version = CMasternode::VERSION0;
// If old masternode update for new serialisation
if (node.version < CMasternode::VERSION0) {
node.version = CMasternode::VERSION0;
}

// Set new reward address
node->rewardAddressType = rewardAddressType;
node->rewardAddress = rewardAddress;
WriteBy<ID>(nodeId, *node);

return Res::Ok();
node.rewardAddressType = rewardAddressType;
node.rewardAddress = rewardAddress;
WriteBy<ID>(nodeId, node);
}

Res CMasternodesView::RemForcedRewardAddress(uint256 const & nodeId, int height)
void CMasternodesView::RemForcedRewardAddress(uint256 const & nodeId, CMasternode& node, int height)
{
// Temporarily disabled for 2.2
return Res::Err("reward address change is disabled for Fort Canning");
node.rewardAddressType = 0;
node.rewardAddress.SetNull();
WriteBy<ID>(nodeId, node);
}

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());
}
void CMasternodesView::UpdateMasternodeOperator(uint256 const & nodeId, CMasternode& node, const char operatorType, const CKeyID& operatorAuthAddress, int height)
{
// Remove old record
EraseBy<Operator>(node.operatorAuthAddress);

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

return Res::Ok();
// Overwrite and create new record
WriteBy<ID>(nodeId, node);
WriteBy<Operator>(node.operatorAuthAddress, nodeId);
}

Res CMasternodesView::UpdateMasternode(uint256 const & nodeId, char operatorType, const CKeyID& operatorAuthAddress, int height) {
// Temporarily disabled for 2.2
return Res::Err("updatemasternode is disabled for Fort Canning");
void CMasternodesView::UpdateMasternodeOwner(uint256 const & nodeId, CMasternode& node, const char ownerType, const CKeyID& ownerAuthAddress)
{
// Remove old record
EraseBy<Owner>(node.ownerAuthAddress);

// auth already checked!
auto node = GetMasternode(nodeId);
if (!node) {
return Res::Err("node %s does not exists", nodeId.ToString());
}
node.ownerType = ownerType;
node.ownerAuthAddress = ownerAuthAddress;

const auto state = node->GetState(height);
if (state != CMasternode::ENABLED) {
return Res::Err("node %s state is not 'ENABLED'", nodeId.ToString());
}
// Overwrite and create new record
WriteBy<ID>(nodeId, node);
WriteBy<Owner>(node.ownerAuthAddress, nodeId);
}

if (operatorType == node->operatorType && operatorAuthAddress == node->operatorAuthAddress) {
return Res::Err("The new operator is same as existing operator");
}
void CMasternodesView::UpdateMasternodeCollateral(uint256 const & nodeId, CMasternode& node, const uint256& newCollateralTx, const int height)
{
// Remove old record.
EraseBy<NewCollateral>(node.collateralTx);

// Remove old record
EraseBy<Operator>(node->operatorAuthAddress);
// Store new collateral. Used by HasCollateralAuth.
node.collateralTx = newCollateralTx;
WriteBy<ID>(nodeId, node);

node->operatorType = operatorType;
node->operatorAuthAddress = operatorAuthAddress;
// Prioritise fast lookup in CanSpend() and GetState()
WriteBy<NewCollateral>(newCollateralTx, MNNewOwnerHeightValue{static_cast<uint32_t>(height + GetMnResignDelay(height)), nodeId});
}

// Overwrite and create new record
WriteBy<ID>(nodeId, *node);
WriteBy<Operator>(node->operatorAuthAddress, nodeId);
std::optional<MNNewOwnerHeightValue> CMasternodesView::GetNewCollateral(const uint256& txid) const
{
return ReadBy<NewCollateral, MNNewOwnerHeightValue>(txid);
}

return Res::Ok();
void CMasternodesView::ForEachNewCollateral(std::function<bool(const uint256&, CLazySerialize<MNNewOwnerHeightValue>)> callback)
{
ForEach<NewCollateral, uint256, MNNewOwnerHeightValue>(callback);
}

void CMasternodesView::SetMasternodeLastBlockTime(const CKeyID & minter, const uint32_t &blockHeight, const int64_t& time)
Expand Down Expand Up @@ -770,7 +767,7 @@ CTeamView::CTeam CCustomCSView::CalcNextTeam(int height, const uint256 & stakeMo

std::map<arith_uint256, CKeyID, std::less<arith_uint256>> priorityMN;
ForEachMasternode([&] (uint256 const & id, CMasternode node) {
if(!node.IsActive(height))
if(!node.IsActive(height, *this))
return true;

CDataStream ss{SER_GETHASH, PROTOCOL_VERSION};
Expand Down Expand Up @@ -810,7 +807,7 @@ void CCustomCSView::CalcAnchoringTeams(const uint256 & stakeModifier, const CBlo
std::map<arith_uint256, CKeyID, std::less<arith_uint256>> authMN;
std::map<arith_uint256, CKeyID, std::less<arith_uint256>> confirmMN;
ForEachMasternode([&] (uint256 const & id, CMasternode node) {
if(!node.IsActive(pindexNew->nHeight))
if(!node.IsActive(pindexNew->nHeight, *this))
return true;

// Not in our list of MNs from last week, skip.
Expand Down Expand Up @@ -887,9 +884,17 @@ bool CCustomCSView::CanSpend(const uint256 & txId, int height) const
auto node = GetMasternode(txId);
// check if it was mn collateral and mn was resigned or banned
if (node) {
auto state = node->GetState(height);
auto state = node->GetState(height, *this);
return state == CMasternode::RESIGNED;
}

if (auto mn = GetNewCollateral(txId)) {
auto node = GetMasternode(mn->masternodeID);
assert(node);
auto state = node->GetState(height, *this);
return state == CMasternode::RESIGNED;
}

// check if it was token collateral and token already destroyed
/// @todo token check for total supply/limit when implemented
auto pair = GetTokenByCreationTx(txId);
Expand Down Expand Up @@ -1169,7 +1174,7 @@ std::map<CKeyID, CKey> AmISignerNow(int height, CAnchorData::CTeam const & team)
continue;
}

if (node->IsActive(height) && team.find(mnId.first) != team.end()) {
if (node->IsActive(height, *pcustomcsview) && team.find(mnId.first) != team.end()) {
CKey masternodeKey;
std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
for (auto const & wallet : wallets) {
Expand Down
Loading