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

Using Data Transfer Objects in Update Provider SmartContract Calls #2577

Merged
merged 3 commits into from Jul 4, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 61 additions & 0 deletions code/go/0chain.net/smartcontract/dto/minerdto.go
@@ -0,0 +1,61 @@
package dto

import (
"0chain.net/core/common"
"0chain.net/smartcontract/provider"
"github.com/0chain/common/core/currency"
)

// NodeType used in pools statistic.
type NodeType int

// MinerDtoNode struct that holds information about the registering miner.
// swagger:model MinerDtoNode
type MinerDtoNode struct {
*SimpleDtoNode `json:"simple_miner,omitempty"`
*StakePool `json:"stake_pool,omitempty"`
}

// swagger:model SimpleDtoNode
type SimpleDtoNode struct {
provider.Provider
N2NHost string `json:"n2n_host"`
Host string `json:"host"`
Port int `json:"port"`
Geolocation SimpleNodeGeolocation `json:"geolocation"`
Path string `json:"path"`
PublicKey string `json:"public_key"`
ShortName string `json:"short_name"`
BuildTag string `json:"build_tag"`
TotalStaked currency.Coin `json:"total_stake"`
Delete bool `json:"delete"`

// settings and statistic

// NodeType used for delegate pools statistic.
NodeType NodeType `json:"node_type,omitempty"`

// LastHealthCheck used to check for active node
LastHealthCheck common.Timestamp `json:"last_health_check"`

// Status will be set either node.NodeStatusActive or node.NodeStatusInactive
Status int `json:"-" msg:"-"`

//LastSettingUpdateRound will be set to round number when settings were updated
LastSettingUpdateRound int64 `json:"last_setting_update_round"`
}

// swagger:model SimpleNodeGeolocation
type SimpleNodeGeolocation struct {
Latitude *float64 `json:"latitude,omitempty"`
Longitude *float64 `json:"longitude,omitempty"`
}

func NewMinerDtoNode() *MinerDtoNode {
return &MinerDtoNode{
SimpleDtoNode: &SimpleDtoNode{
Provider: provider.Provider{},
},
StakePool: NewStakePool(),
}
}
39 changes: 39 additions & 0 deletions code/go/0chain.net/smartcontract/dto/stakepooldto.go
@@ -0,0 +1,39 @@
package dto

import (
cstate "0chain.net/chaincore/chain/state"
"0chain.net/core/common"
"github.com/0chain/common/core/currency"
)

type PoolStatus int

// StakePool holds delegate information for an 0chain providers
type StakePool struct {
Pools map[string]*DelegatePool `json:"pools"`
Reward currency.Coin `json:"rewards"`
StakePoolSettings Settings `json:"settings"`
Minter cstate.ApprovedMinter `json:"minter"`
HasBeenKilled bool `json:"is_dead"`
}

type DelegatePool struct {
Balance currency.Coin `json:"balance"`
Reward currency.Coin `json:"reward"`
Status *PoolStatus `json:"status"`
RoundCreated *int64 `json:"round_created"` // used for cool down
DelegateID *string `json:"delegate_id"`
StakedAt common.Timestamp `json:"staked_at"`
}

type Settings struct {
DelegateWallet *string `json:"delegate_wallet,omitempty"`
MaxNumDelegates *int `json:"num_delegates,omitempty"`
ServiceChargeRatio *float64 `json:"service_charge,omitempty"`
}

func NewStakePool() *StakePool {
return &StakePool{
Pools: make(map[string]*DelegatePool),
}
}
54 changes: 47 additions & 7 deletions code/go/0chain.net/smartcontract/minersc/miner.go
@@ -1,6 +1,8 @@
package minersc

import (
"0chain.net/smartcontract/dto"
"encoding/json"
"fmt"

"0chain.net/smartcontract/stakepool/spenum"
Expand Down Expand Up @@ -252,24 +254,24 @@ func (msc *MinerSmartContract) UpdateMinerSettings(t *transaction.Transaction,
inputData []byte, gn *GlobalNode, balances cstate.StateContextI) (
resp string, err error) {

var update = NewMinerNode()
if err = update.Decode(inputData); err != nil {
requiredUpdateInMinerNode := dto.NewMinerDtoNode()
if err = json.Unmarshal(inputData, &requiredUpdateInMinerNode); err != nil {
return "", common.NewErrorf("update_miner_settings",
"decoding request: %v", err)
}

err = validateNodeSettings(update, gn, "update_miner_settings")
err = validateNodeUpdateSettings(requiredUpdateInMinerNode, gn, "update_miner_settings")
if err != nil {
return "", err
}

var mn *MinerNode
mn, err = getMinerNode(update.ID, balances)
mn, err = getMinerNode(requiredUpdateInMinerNode.ID, balances)
switch err {
case nil:
case util.ErrValueNotPresent:
mn = NewMinerNode()
mn.ID = update.ID
mn.ID = requiredUpdateInMinerNode.ID
default:
return "", common.NewError("update_miner_settings", err.Error())
}
Expand All @@ -287,8 +289,14 @@ func (msc *MinerSmartContract) UpdateMinerSettings(t *transaction.Transaction,
return "", common.NewError("update_miner_settings", "access denied")
}

mn.Settings.ServiceChargeRatio = update.Settings.ServiceChargeRatio
mn.Settings.MaxNumDelegates = update.Settings.MaxNumDelegates
// only update when there were values sent
if requiredUpdateInMinerNode.StakePool.StakePoolSettings.ServiceChargeRatio != nil {
mn.Settings.ServiceChargeRatio = *requiredUpdateInMinerNode.StakePoolSettings.ServiceChargeRatio
}

if requiredUpdateInMinerNode.StakePool.StakePoolSettings.MaxNumDelegates != nil {
mn.Settings.MaxNumDelegates = *requiredUpdateInMinerNode.StakePoolSettings.MaxNumDelegates
}

if err = mn.save(balances); err != nil {
return "", common.NewErrorf("update_miner_settings", "saving: %v", err)
Expand Down Expand Up @@ -349,3 +357,35 @@ func validateNodeSettings(node *MinerNode, gn *GlobalNode, opcode string) error

return nil
}

func validateNodeUpdateSettings(update *dto.MinerDtoNode, gn *GlobalNode, opcode string) error {
if update.StakePoolSettings.ServiceChargeRatio != nil {
serviceChargeValue := *update.StakePoolSettings.ServiceChargeRatio
if serviceChargeValue < 0 {
return common.NewErrorf(opcode,
"invalid negative service charge: %v", serviceChargeValue)
}

if serviceChargeValue > gn.MaxCharge {
return common.NewErrorf(opcode,
"max_charge is greater than allowed by SC: %v > %v",
serviceChargeValue, gn.MaxCharge)
}
}

if update.StakePoolSettings.MaxNumDelegates != nil {
maxDelegateValue := *update.StakePoolSettings.MaxNumDelegates
if maxDelegateValue <= 0 {
return common.NewErrorf(opcode,
"invalid non-positive number_of_delegates: %v", maxDelegateValue)
}

if maxDelegateValue > gn.MaxDelegates {
return common.NewErrorf(opcode,
"number_of_delegates greater than max_delegates of SC: %v > %v",
maxDelegateValue, gn.MaxDelegates)
}
}

return nil
}
20 changes: 14 additions & 6 deletions code/go/0chain.net/smartcontract/minersc/sharder.go
@@ -1,6 +1,8 @@
package minersc

import (
"0chain.net/smartcontract/dto"
"encoding/json"
"errors"
"fmt"

Expand All @@ -21,19 +23,19 @@ func (msc *MinerSmartContract) UpdateSharderSettings(t *transaction.Transaction,
inputData []byte, gn *GlobalNode, balances cstate.StateContextI) (
resp string, err error) {

var update = NewMinerNode()
if err = update.Decode(inputData); err != nil {
requiredUpdateInSharderNode := dto.NewMinerDtoNode()
if err = json.Unmarshal(inputData, &requiredUpdateInSharderNode); err != nil {
return "", common.NewErrorf("update_sharder_settings",
"decoding request: %v", err)
}

err = validateNodeSettings(update, gn, "update_sharder_settings")
err = validateNodeUpdateSettings(requiredUpdateInSharderNode, gn, "update_sharder_settings")
if err != nil {
return "", err
}

var sn *MinerNode
sn, err = msc.getSharderNode(update.ID, balances)
sn, err = msc.getSharderNode(requiredUpdateInSharderNode.ID, balances)
if err != nil {
return "", common.NewError("update_sharder_settings", err.Error())
}
Expand All @@ -49,8 +51,14 @@ func (msc *MinerSmartContract) UpdateSharderSettings(t *transaction.Transaction,
return "", common.NewError("update_sharder_settings", "access denied")
}

sn.Settings.ServiceChargeRatio = update.Settings.ServiceChargeRatio
sn.Settings.MaxNumDelegates = update.Settings.MaxNumDelegates
// only update when there were values sent
if requiredUpdateInSharderNode.StakePool.StakePoolSettings.ServiceChargeRatio != nil {
sn.Settings.ServiceChargeRatio = *requiredUpdateInSharderNode.StakePoolSettings.ServiceChargeRatio
}

if requiredUpdateInSharderNode.StakePool.StakePoolSettings.MaxNumDelegates != nil {
sn.Settings.MaxNumDelegates = *requiredUpdateInSharderNode.StakePoolSettings.MaxNumDelegates
}

if err = sn.save(balances); err != nil {
return "", common.NewErrorf("update_sharder_settings", "saving: %v", err)
Expand Down