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

Restore updatemasternode and combine setforcedrewardaddress / removeforcedaddress #934

Merged
merged 15 commits into from
May 19, 2022
Merged
32 changes: 16 additions & 16 deletions src/consensus/tx_verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,21 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, CValidationState& state, c
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().GreatWorldHeight && txType == CustomTxType::UpdateMasternode)) {
CCustomCSView discardCache(mnview);
CFutureSwapView futureSwapView(*pfutureSwapView);
CUndosView undosView(*pundosView);
auto res = ApplyCustomTx(discardCache, futureSwapView, undosView, inputs, tx, chainparams.GetConsensus(), nSpendHeight, 0, &canSpend);
if (!res.ok && (res.code & CustomTxErrCodes::Fatal) && txType != CustomTxType::UpdateMasternode) {
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 @@ -188,8 +203,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 @@ -216,20 +230,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(mnview);
CFutureSwapView futureSwapView(*pfutureSwapView);
CUndosView undosView(*pundosView);
auto res = ApplyCustomTx(discardCache, futureSwapView, undosView, 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
4 changes: 2 additions & 2 deletions src/masternodes/anchors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,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 Expand Up @@ -1117,7 +1117,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;
for (auto const & wallet : GetWallets()) {
if (wallet->GetKey(mnId.first, masternodeKey)) {
Expand Down
159 changes: 128 additions & 31 deletions src/masternodes/consensus/masternodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.

#include <masternodes/masternodes.h>

#include <coins.h>
#include <consensus/params.h>
#include <masternodes/consensus/masternodes.h>
#include <masternodes/masternodes.h>
#include <masternodes/customtx.h>
#include <primitives/transaction.h>

Res CMasternodesConsensus::operator()(const CCreateMasterNodeMessage& obj) const {
Expand Down Expand Up @@ -62,42 +65,136 @@ Res CMasternodesConsensus::operator()(const CCreateMasterNodeMessage& obj) const
}

Res CMasternodesConsensus::operator()(const CResignMasterNodeMessage& obj) const {
auto res = HasCollateralAuth(obj);
return !res ? res : mnview.ResignMasternode(obj, tx.GetHash(), height);
auto node = mnview.GetMasternode(obj);
if (!node) {
return Res::Err("node %s does not exists", obj.ToString());
}
auto res = HasCollateralAuth(node->collateralTx.IsNull() ? static_cast<uint256>(obj) : node->collateralTx);
return !res ? res : mnview.ResignMasternode(*node, obj, tx.GetHash(), height);
}

Res CMasternodesConsensus::operator()(const CSetForcedRewardAddressMessage& obj) const {
// Temporarily disabled for 2.2
return Res::Err("reward address change is disabled for Fort Canning");

auto 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 CMasternodesConsensus::operator()(const CUpdateMasterNodeMessage& obj) const {
if (obj.updates.empty()) {
return Res::Err("No update arguments provided");
}

Res CMasternodesConsensus::operator()(const CRemForcedRewardAddressMessage& obj) const {
// Temporarily disabled for 2.2
return Res::Err("reward address change is disabled for Fort Canning");
if (obj.updates.size() > 3) {
return Res::Err("Too many updates provided");
}

auto node = mnview.GetMasternode(obj.nodeId);
if (!node)
return Res::Err("masternode %s does not exist", obj.nodeId.ToString());
auto node = mnview.GetMasternode(obj.mnId);
if (!node) {
return Res::Err("masternode %s does not exists", obj.mnId.ToString());
}

if (!HasCollateralAuth(obj.nodeId))
return Res::Err("%s: %s", obj.nodeId.ToString(), "tx must have at least one input from masternode owner");
const auto collateralTx = node->collateralTx.IsNull() ? obj.mnId : node->collateralTx;
const auto res = HasCollateralAuth(collateralTx);
if (!res) {
return res;
}

return mnview.RemForcedRewardAddress(obj.nodeId, height);
}
auto state = node->GetState(height, mnview);
if (state != CMasternode::ENABLED) {
return Res::Err("Masternode %s is not in 'ENABLED' state", obj.mnId.ToString());
}

Res CMasternodesConsensus::operator()(const CUpdateMasterNodeMessage& obj) const {
// Temporarily disabled for 2.2
return Res::Err("updatemasternode is disabled for Fort Canning");
bool ownerType{false}, operatorType{false}, rewardType{false};
for (const auto& item : obj.updates) {
if (item.first == static_cast<uint8_t>(UpdateMasternodeType::OwnerAddress)) {
if (ownerType) {
return Res::Err("Multiple owner updates provided");
}
ownerType = true;
bool collateralFound{false};
for (const auto vin : tx.vin) {
if (vin.prevout.hash == collateralTx && vin.prevout.n == 1) {
collateralFound = true;
}
}
if (!collateralFound) {
return Res::Err("Missing previous collateral from transaction inputs");
}
if (tx.vout.size() == 1) {
return Res::Err("Missing new collateral output");
}
if (!HasAuth(tx.vout[1].scriptPubKey)) {
return Res::Err("Missing auth input for new masternode owner");
}

CTxDestination dest;
if (!ExtractDestination(tx.vout[1].scriptPubKey, dest) || (dest.index() != PKHashType && dest.index() != WitV0KeyHashType)) {
return Res::Err("Owner address must be P2PKH or P2WPKH type");
}

if (tx.vout[1].nValue != GetMnCollateralAmount(height)) {
return Res::Err("Incorrect collateral amount");
}

const auto keyID = dest.index() == PKHashType ? CKeyID(std::get<PKHash>(dest)) : CKeyID(std::get<WitnessV0KeyHash>(dest));
if (mnview.GetMasternodeIdByOwner(keyID) || mnview.GetMasternodeIdByOperator(keyID)) {
return Res::Err("Masternode with that owner address already exists");
}

bool duplicate{false};
mnview.ForEachNewCollateral([&](const uint256& key, CLazySerialize<MNNewOwnerHeightValue> valueKey) {
const auto& value = valueKey.get();
if (height > value.blockHeight) {
return true;
}
const auto& coin = coins.AccessCoin({key, 1});
assert(!coin.IsSpent());
CTxDestination pendingDest;
assert(ExtractDestination(coin.out.scriptPubKey, pendingDest));
const CKeyID storedID = pendingDest.index() == PKHashType ? CKeyID(std::get<PKHash>(pendingDest)) : CKeyID(std::get<WitnessV0KeyHash>(pendingDest));
if (storedID == keyID) {
duplicate = true;
return false;
}
return true;
});
if (duplicate) {
return Res::ErrCode(CustomTxErrCodes::Fatal, "Masternode exist with that owner address pending already");
}

mnview.UpdateMasternodeCollateral(obj.mnId, *node, tx.GetHash(), height);
} else if (item.first == static_cast<uint8_t>(UpdateMasternodeType::OperatorAddress)) {
if (operatorType) {
return Res::Err("Multiple operator updates provided");
}
operatorType = true;

if (item.second.first != 1 && item.second.first != 4) {
return Res::Err("Operator address must be P2PKH or P2WPKH type");
}

const auto keyID = CKeyID(uint160(item.second.second));
if (mnview.GetMasternodeIdByOwner(keyID) || mnview.GetMasternodeIdByOperator(keyID)) {
return Res::Err("Masternode with that operator address already exists");
}
mnview.UpdateMasternodeOperator(obj.mnId, *node, item.second.first, keyID, height);
} else if (item.first == static_cast<uint8_t>(UpdateMasternodeType::SetRewardAddress)) {
if (rewardType) {
return Res::Err("Multiple reward address updates provided");
}
rewardType = true;

if (item.second.first != 1 && item.second.first != 4) {
return Res::Err("Reward address must be P2PKH or P2WPKH type");
}

const auto keyID = CKeyID(uint160(item.second.second));
mnview.SetForcedRewardAddress(obj.mnId, *node, item.second.first, keyID, height);
} else if (item.first == static_cast<uint8_t>(UpdateMasternodeType::RemRewardAddress)) {
if (rewardType) {
return Res::Err("Multiple reward address updates provided");
}
rewardType = true;

mnview.RemForcedRewardAddress(obj.mnId, *node, height);
} else {
return Res::Err("Unknown update type provided");
}
}

auto res = HasCollateralAuth(obj.mnId);
return !res ? res : mnview.UpdateMasternode(obj.mnId, obj.operatorType, obj.operatorAuthAddress, height);
return Res::Ok();
}
4 changes: 0 additions & 4 deletions src/masternodes/consensus/masternodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,13 @@

struct CCreateMasterNodeMessage;
struct CResignMasterNodeMessage;
struct CSetForcedRewardAddressMessage;
struct CRemForcedRewardAddressMessage;
struct CUpdateMasterNodeMessage;

class CMasternodesConsensus : public CCustomTxVisitor {
public:
using CCustomTxVisitor::CCustomTxVisitor;
Res operator()(const CCreateMasterNodeMessage& obj) const;
Res operator()(const CResignMasterNodeMessage& obj) const;
Res operator()(const CSetForcedRewardAddressMessage& obj) const;
Res operator()(const CRemForcedRewardAddressMessage& obj) const;
Res operator()(const CUpdateMasterNodeMessage& obj) const;
};

Expand Down
4 changes: 0 additions & 4 deletions src/masternodes/customtx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ CustomTxType CustomTxCodeToType(uint8_t ch) {
switch (type) {
case CustomTxType::CreateMasternode:
case CustomTxType::ResignMasternode:
case CustomTxType::SetForcedRewardAddress:
case CustomTxType::RemForcedRewardAddress:
case CustomTxType::UpdateMasternode:
case CustomTxType::CreateToken:
case CustomTxType::MintToken:
Expand Down Expand Up @@ -78,8 +76,6 @@ std::string ToString(CustomTxType type) {
switch (type) {
CustomTxTypeString(CreateMasternode);
CustomTxTypeString(ResignMasternode);
CustomTxTypeString(SetForcedRewardAddress);
CustomTxTypeString(RemForcedRewardAddress);
CustomTxTypeString(UpdateMasternode);
CustomTxTypeString(CreateToken);
CustomTxTypeString(UpdateToken);
Expand Down
2 changes: 0 additions & 2 deletions src/masternodes/customtx.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ enum struct CustomTxType : uint8_t
CreateMasternode = 'C',
ResignMasternode = 'R',
UpdateMasternode = 'm',
SetForcedRewardAddress = 'F',
RemForcedRewardAddress = 'f',

// tokens
CreateToken = 'T',
Expand Down
Loading