Skip to content

Commit

Permalink
Add updating of owner to updatemasternode
Browse files Browse the repository at this point in the history
  • Loading branch information
Bushstar committed Dec 7, 2021
1 parent 802fa59 commit 67e8359
Show file tree
Hide file tree
Showing 11 changed files with 549 additions and 113 deletions.
5 changes: 2 additions & 3 deletions src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ 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, const CCustomCSView * mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams, uint256 canSpend)
{
// are the actual inputs available?
if (!inputs.HaveInputs(tx)) {
Expand All @@ -187,8 +187,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 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, const CCustomCSView * mnview, int nSpendHeight, CAmount& txfee, const CChainParams& chainparams, uint256 canSpend);
} // namespace Consensus

/** Auxiliary functions for transaction validation (ideally should not be exposed) */
Expand Down
99 changes: 73 additions & 26 deletions src/masternodes/masternodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,28 @@ CMasternode::CMasternode()
, resignHeight(-1)
, version(-1)
, resignTx()
, banTx()
, collateralTx()
{
}

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

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

if (!collateralTx.IsNull()) {
auto idHeight = mnview.GetNewCollateral(collateralTx);
assert(idHeight);
if (height < idHeight->blockHeight) {
return State::TRANSFERRING;
} else if (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 @@ -115,7 +125,7 @@ CMasternode::State CMasternode::GetState(int height) const

bool CMasternode::IsActive(int height) const
{
State state = GetState(height);
State state = GetState(height, *pcustomcsview);
if (height >= Params().GetConsensus().EunosPayaHeight) {
return state == ENABLED;
}
Expand All @@ -133,6 +143,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 @@ -160,7 +172,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 @@ -289,14 +301,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, CCustomCSView& mnview)
{
// 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, mnview);
if (height >= Params().GetConsensus().EunosPayaHeight) {
if (state != CMasternode::ENABLED) {
return Res::Err("node %s state is not 'ENABLED'", nodeId.ToString());
Expand All @@ -305,14 +312,14 @@ 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();
}
Expand All @@ -337,7 +344,7 @@ void CMasternodesView::RemForcedRewardAddress(uint256 const & nodeId, CMasternod
WriteBy<ID>(nodeId, node);
}

void CMasternodesView::UpdateMasternode(uint256 const & nodeId, CMasternode& node, char operatorType, const CKeyID& operatorAuthAddress, int height)
void CMasternodesView::UpdateMasternodeOperator(uint256 const & nodeId, CMasternode& node, const char operatorType, const CKeyID& operatorAuthAddress, int height)
{
// Remove old record
EraseBy<Operator>(node.operatorAuthAddress);
Expand All @@ -350,6 +357,42 @@ void CMasternodesView::UpdateMasternode(uint256 const & nodeId, CMasternode& nod
WriteBy<Operator>(node.operatorAuthAddress, nodeId);
}

void CMasternodesView::UpdateMasternodeOwner(uint256 const & nodeId, CMasternode& node, const char ownerType, const CKeyID& ownerAuthAddress)
{
// Remove old record
EraseBy<Owner>(node.ownerAuthAddress);

node.ownerType = ownerType;
node.ownerAuthAddress = ownerAuthAddress;

// Overwrite and create new record
WriteBy<ID>(nodeId, node);
WriteBy<Owner>(node.ownerAuthAddress, nodeId);
}

void CMasternodesView::UpdateMasternodeCollateral(uint256 const & nodeId, CMasternode& node, const uint256& newCollateralTx, const int height)
{
// Remove old record, allows spending of previous collateral in this TX.
EraseBy<NewCollateral>(node.collateralTx);

// Store new collateral. Used by HasCollateralAuth.
node.collateralTx = newCollateralTx;
WriteBy<ID>(nodeId, node);

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

std::optional<MNNewOwnerHeightValue> CMasternodesView::GetNewCollateral(const uint256& txid) const
{
return ReadBy<NewCollateral, MNNewOwnerHeightValue>(txid);
}

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)
{
auto nodeId = GetMasternodeIdByOperator(minter);
Expand Down Expand Up @@ -452,16 +495,12 @@ Res CMasternodesView::UnCreateMasternode(const uint256 & nodeId)
return Res::Err("No such masternode %s", nodeId.GetHex());
}

Res CMasternodesView::UnResignMasternode(const uint256 & nodeId, const uint256 & resignTx)
Res CMasternodesView::UnResignMasternode(CMasternode& node, const uint256 & nodeId)
{
auto node = GetMasternode(nodeId);
if (node && node->resignTx == resignTx) {
node->resignHeight = -1;
node->resignTx = {};
WriteBy<ID>(nodeId, *node);
return Res::Ok();
}
return Res::Err("No such masternode %s, resignTx: %s", nodeId.GetHex(), resignTx.GetHex());
node.resignHeight = -1;
node.resignTx = {};
WriteBy<ID>(nodeId, node);
return Res::Ok();
}

uint16_t CMasternodesView::GetTimelock(const uint256& nodeId, const CMasternode& node, const uint64_t height) const
Expand Down Expand Up @@ -815,9 +854,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
36 changes: 29 additions & 7 deletions src/masternodes/masternodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class CMasternode
ENABLED,
PRE_RESIGNED,
RESIGNED,
TRANSFERRING,
UNKNOWN // unreachable
};

Expand Down Expand Up @@ -88,12 +89,12 @@ class CMasternode

//! This fields are for transaction rollback (by disconnecting block)
uint256 resignTx;
uint256 banTx;
uint256 collateralTx;

//! empty constructor
CMasternode();

State GetState(int height) const;
State GetState(int height, const CCustomCSView& mnview) const;
bool IsActive(int height) const;

static std::string GetHumanReadableState(State state);
Expand All @@ -115,7 +116,7 @@ class CMasternode
READWRITE(version);

READWRITE(resignTx);
READWRITE(banTx);
READWRITE(collateralTx);

// Only available after FortCanning
if (version > PRE_FORT_CANNING) {
Expand Down Expand Up @@ -174,6 +175,20 @@ struct SubNodeBlockTimeKey
}
};

struct MNNewOwnerHeightValue
{
uint32_t blockHeight;
uint256 masternodeID;

ADD_SERIALIZE_METHODS;

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

class CMasternodesView : public virtual CStorageView
{
std::map<CKeyID, std::pair<uint32_t, int64_t>> minterTimeCache;
Expand All @@ -196,12 +211,18 @@ class CMasternodesView : public virtual CStorageView
std::set<std::pair<CKeyID, uint256>> GetOperatorsMulti() const;

Res CreateMasternode(uint256 const & nodeId, CMasternode const & node, uint16_t timelock);
Res ResignMasternode(uint256 const & nodeId, uint256 const & txid, int height);
Res ResignMasternode(CMasternode& node, uint256 const & nodeId, uint256 const & txid, int height, CCustomCSView& mnview);
Res UnCreateMasternode(uint256 const & nodeId);
Res UnResignMasternode(uint256 const & nodeId, uint256 const & resignTx);
Res UnResignMasternode(CMasternode& node, uint256 const & nodeId);

// Masternode updates
void SetForcedRewardAddress(uint256 const & nodeId, CMasternode& node, const char rewardAddressType, CKeyID const & rewardAddress, int height);
void RemForcedRewardAddress(uint256 const & nodeId, CMasternode& node, int height);
void UpdateMasternode(uint256 const & nodeId, CMasternode& node, char operatorType, const CKeyID& operatorAuthAddress, int height);
void UpdateMasternodeOperator(uint256 const & nodeId, CMasternode& node, const char operatorType, const CKeyID& operatorAuthAddress, int height);
void UpdateMasternodeOwner(uint256 const & nodeId, CMasternode& node, const char ownerType, const CKeyID& ownerAuthAddress);
void UpdateMasternodeCollateral(uint256 const & nodeId, CMasternode& node, const uint256& newCollateralTx, const int height);
std::optional<MNNewOwnerHeightValue> GetNewCollateral(const uint256& txid) const;
void ForEachNewCollateral(std::function<bool(const uint256&, CLazySerialize<MNNewOwnerHeightValue>)> callback);

// 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 All @@ -224,6 +245,7 @@ class CMasternodesView : public virtual CStorageView
struct ID { static constexpr uint8_t prefix() { return 'M'; } };
struct Operator { static constexpr uint8_t prefix() { return 'o'; } };
struct Owner { static constexpr uint8_t prefix() { return 'w'; } };
struct NewCollateral { static constexpr uint8_t prefix() { return 's'; } };

// For storing last staked block time
struct Staker { static constexpr uint8_t prefix() { return 'X'; } };
Expand Down Expand Up @@ -355,7 +377,7 @@ class CCustomCSView
void CheckPrefixes()
{
CheckPrefix<
CMasternodesView :: ID, Operator, Owner, Staker, SubNode, Timelock,
CMasternodesView :: ID, NewCollateral, Operator, Owner, Staker, SubNode, Timelock,
CLastHeightView :: Height,
CTeamView :: AuthTeam, ConfirmTeam, CurrentTeam,
CFoundationsDebtView :: Debt,
Expand Down
Loading

0 comments on commit 67e8359

Please sign in to comment.