code.vegaprotocol.io/vega@v0.79.0/datanode/entities/node.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package entities
    17  
    18  import (
    19  	"encoding/json"
    20  	"fmt"
    21  	"strconv"
    22  	"time"
    23  
    24  	v2 "code.vegaprotocol.io/vega/protos/data-node/api/v2"
    25  	"code.vegaprotocol.io/vega/protos/vega"
    26  	eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1"
    27  
    28  	"github.com/shopspring/decimal"
    29  	"google.golang.org/protobuf/encoding/protojson"
    30  )
    31  
    32  type _Node struct{}
    33  
    34  type NodeID = ID[_Node]
    35  
    36  type Node struct {
    37  	ID                NodeID
    38  	PubKey            VegaPublicKey       `db:"vega_pub_key"`
    39  	TmPubKey          TendermintPublicKey `db:"tendermint_pub_key"`
    40  	EthereumAddress   EthereumAddress
    41  	InfoURL           string
    42  	Location          string
    43  	Status            NodeStatus
    44  	Name              string
    45  	AvatarURL         string
    46  	TxHash            TxHash
    47  	VegaTime          time.Time
    48  	StakedByOperator  decimal.Decimal
    49  	StakedByDelegates decimal.Decimal
    50  	StakedTotal       decimal.Decimal
    51  	MaxIntendedStake  decimal.Decimal
    52  	PendingStake      decimal.Decimal
    53  	EpochData         EpochData
    54  	Delegations       []Delegation  `json:""`
    55  	RewardScore       *RewardScore  `json:""`
    56  	RankingScore      *RankingScore `json:""`
    57  }
    58  
    59  type ValidatorUpdateAux struct {
    60  	Added           bool
    61  	EpochSeq        uint64
    62  	VegaPubKeyIndex uint32
    63  	TxHash          TxHash
    64  }
    65  
    66  type EpochData struct {
    67  	*vega.EpochData
    68  }
    69  
    70  type RewardScore struct {
    71  	RawValidatorScore   decimal.Decimal     `json:"raw_validator_score"`
    72  	PerformanceScore    decimal.Decimal     `json:"performance_score"`
    73  	MultisigScore       decimal.Decimal     `json:"multisig_score"`
    74  	ValidatorScore      decimal.Decimal     `json:"validator_score"`
    75  	NormalisedScore     decimal.Decimal     `json:"normalised_score"`
    76  	ValidatorNodeStatus ValidatorNodeStatus `json:"validator_node_status,string"`
    77  	TxHash              TxHash              `json:"tx_hash"`
    78  	VegaTime            time.Time           `json:"vega_time"`
    79  	EpochSeq            uint64
    80  }
    81  
    82  type RewardScoreAux struct {
    83  	NodeID   NodeID
    84  	EpochSeq uint64
    85  }
    86  
    87  type RankingScore struct {
    88  	StakeScore       decimal.Decimal     `json:"stake_score"`
    89  	PerformanceScore decimal.Decimal     `json:"performance_score"`
    90  	PreviousStatus   ValidatorNodeStatus `json:"previous_status,string"`
    91  	Status           ValidatorNodeStatus `json:",string"`
    92  	VotingPower      uint32              `json:"voting_power"`
    93  	RankingScore     decimal.Decimal     `json:"ranking_score"`
    94  	TxHash           TxHash              `json:"tx_hash"`
    95  	VegaTime         time.Time           `json:"vega_time"`
    96  	EpochSeq         uint64
    97  }
    98  
    99  type RankingScoreAux struct {
   100  	NodeID   NodeID
   101  	EpochSeq uint64
   102  }
   103  
   104  type NodeSet struct {
   105  	Total    uint32
   106  	Inactive uint32
   107  	Promoted []string
   108  	Demoted  []string
   109  	Maximum  uint32
   110  }
   111  
   112  type NodeData struct {
   113  	StakedTotal     decimal.Decimal
   114  	TotalNodes      uint32
   115  	InactiveNodes   uint32
   116  	TendermintNodes NodeSet
   117  	ErsatzNodes     NodeSet
   118  	PendingNodes    NodeSet
   119  	Uptime          float64
   120  	VegaTime        time.Time
   121  }
   122  
   123  func NodeFromValidatorUpdateEvent(evt eventspb.ValidatorUpdate, txHash TxHash, vegaTime time.Time) (Node, ValidatorUpdateAux, error) {
   124  	return Node{
   125  			ID:              NodeID(evt.NodeId),
   126  			PubKey:          VegaPublicKey(evt.VegaPubKey),
   127  			TmPubKey:        TendermintPublicKey(evt.TmPubKey),
   128  			EthereumAddress: EthereumAddress(evt.EthereumAddress),
   129  			InfoURL:         evt.InfoUrl,
   130  			Location:        evt.Country,
   131  			Name:            evt.Name,
   132  			AvatarURL:       evt.AvatarUrl,
   133  			TxHash:          txHash,
   134  			VegaTime:        vegaTime,
   135  
   136  			// Not present in the event
   137  			Status:            NodeStatusValidator, // This was the default value in the legacy store code
   138  			StakedByOperator:  decimal.Zero,
   139  			StakedByDelegates: decimal.Zero,
   140  			StakedTotal:       decimal.Zero,
   141  			MaxIntendedStake:  decimal.Zero,
   142  			PendingStake:      decimal.Zero,
   143  			EpochData:         EpochData{},
   144  			Delegations:       []Delegation{},
   145  			RewardScore:       nil,
   146  			RankingScore:      nil,
   147  		}, ValidatorUpdateAux{
   148  			Added:           evt.Added,
   149  			EpochSeq:        evt.EpochSeq,
   150  			VegaPubKeyIndex: evt.VegaPubKeyIndex,
   151  			TxHash:          txHash,
   152  		}, nil
   153  }
   154  
   155  func ValidatorNodeStatusFromString(status string) ValidatorNodeStatus {
   156  	switch status {
   157  	case "tendermint":
   158  		return ValidatorNodeStatusTendermint
   159  	case "ersatz":
   160  		return ValidatorNodeStatusErsatz
   161  	case "pending":
   162  		return ValidatorNodeStatusPending
   163  	case "unspecified":
   164  		fallthrough
   165  	default: // Is this appropriate behavior? Should we error on the default case?
   166  		return ValidatorNodeStatusUnspecified
   167  	}
   168  }
   169  
   170  func RankingScoreFromRankingEvent(evt eventspb.ValidatorRankingEvent, txHash TxHash, vegaTime time.Time) (RankingScore, RankingScoreAux, error) {
   171  	stakeScore, err := decimal.NewFromString(evt.StakeScore)
   172  	if err != nil {
   173  		return RankingScore{}, RankingScoreAux{}, err
   174  	}
   175  
   176  	performanceScore, err := decimal.NewFromString(evt.PerformanceScore)
   177  	if err != nil {
   178  		return RankingScore{}, RankingScoreAux{}, err
   179  	}
   180  
   181  	rankingScore, err := decimal.NewFromString(evt.RankingScore)
   182  	if err != nil {
   183  		return RankingScore{}, RankingScoreAux{}, err
   184  	}
   185  
   186  	epochSeq, err := strconv.ParseUint(evt.EpochSeq, 10, 64)
   187  	if err != nil {
   188  		return RankingScore{}, RankingScoreAux{}, err
   189  	}
   190  
   191  	return RankingScore{
   192  			StakeScore:       stakeScore,
   193  			PerformanceScore: performanceScore,
   194  			PreviousStatus:   ValidatorNodeStatusFromString(evt.PreviousStatus),
   195  			Status:           ValidatorNodeStatusFromString(evt.NextStatus),
   196  			VotingPower:      evt.TmVotingPower,
   197  			RankingScore:     rankingScore,
   198  			TxHash:           txHash,
   199  			VegaTime:         vegaTime,
   200  			EpochSeq:         epochSeq,
   201  		}, RankingScoreAux{
   202  			NodeID:   NodeID(evt.NodeId),
   203  			EpochSeq: epochSeq,
   204  		}, nil
   205  }
   206  
   207  func (rs *RankingScore) ToProto() *vega.RankingScore {
   208  	return &vega.RankingScore{
   209  		StakeScore:       rs.StakeScore.String(),
   210  		PerformanceScore: rs.PerformanceScore.String(),
   211  		PreviousStatus:   vega.ValidatorNodeStatus(rs.PreviousStatus),
   212  		Status:           vega.ValidatorNodeStatus(rs.Status),
   213  		VotingPower:      rs.VotingPower,
   214  		RankingScore:     rs.RankingScore.String(),
   215  	}
   216  }
   217  
   218  func RewardScoreFromScoreEvent(evt eventspb.ValidatorScoreEvent, txHash TxHash, vegaTime time.Time) (RewardScore, RewardScoreAux, error) {
   219  	rawValidatorScore, err := decimal.NewFromString(evt.RawValidatorScore)
   220  	if err != nil {
   221  		return RewardScore{}, RewardScoreAux{}, err
   222  	}
   223  
   224  	performanceScore, err := decimal.NewFromString(evt.ValidatorPerformance)
   225  	if err != nil {
   226  		return RewardScore{}, RewardScoreAux{}, err
   227  	}
   228  
   229  	multisigScore, err := decimal.NewFromString(evt.MultisigScore)
   230  	if err != nil {
   231  		return RewardScore{}, RewardScoreAux{}, err
   232  	}
   233  
   234  	validatorScore, err := decimal.NewFromString(evt.ValidatorScore)
   235  	if err != nil {
   236  		return RewardScore{}, RewardScoreAux{}, err
   237  	}
   238  
   239  	normalisedScore, err := decimal.NewFromString(evt.NormalisedScore)
   240  	if err != nil {
   241  		return RewardScore{}, RewardScoreAux{}, err
   242  	}
   243  
   244  	epochSeq, err := strconv.ParseUint(evt.EpochSeq, 10, 64)
   245  	if err != nil {
   246  		return RewardScore{}, RewardScoreAux{}, err
   247  	}
   248  
   249  	return RewardScore{
   250  			RawValidatorScore:   rawValidatorScore,
   251  			PerformanceScore:    performanceScore,
   252  			MultisigScore:       multisigScore,
   253  			ValidatorScore:      validatorScore,
   254  			NormalisedScore:     normalisedScore,
   255  			ValidatorNodeStatus: ValidatorNodeStatusFromString(evt.ValidatorStatus),
   256  			TxHash:              txHash,
   257  			VegaTime:            vegaTime,
   258  			EpochSeq:            epochSeq,
   259  		}, RewardScoreAux{
   260  			NodeID:   NodeID(evt.NodeId),
   261  			EpochSeq: epochSeq,
   262  		}, nil
   263  }
   264  
   265  func (rs *RewardScore) ToProto() *vega.RewardScore {
   266  	return &vega.RewardScore{
   267  		RawValidatorScore: rs.RawValidatorScore.String(),
   268  		PerformanceScore:  rs.PerformanceScore.String(),
   269  		MultisigScore:     rs.MultisigScore.String(),
   270  		ValidatorScore:    rs.ValidatorScore.String(),
   271  		NormalisedScore:   rs.NormalisedScore.String(),
   272  		ValidatorStatus:   vega.ValidatorNodeStatus(rs.ValidatorNodeStatus),
   273  	}
   274  }
   275  
   276  func NodeFromProto(node *vega.Node, txHash TxHash, vegaTime time.Time) (Node, error) {
   277  	stakedByOperator, err := decimal.NewFromString(node.StakedByOperator)
   278  	if err != nil {
   279  		return Node{}, err
   280  	}
   281  
   282  	stakedByDelegates, err := decimal.NewFromString(node.StakedByDelegates)
   283  	if err != nil {
   284  		return Node{}, err
   285  	}
   286  
   287  	stakedTotal, err := decimal.NewFromString(node.StakedTotal)
   288  	if err != nil {
   289  		return Node{}, err
   290  	}
   291  
   292  	maxIntendedStake, err := decimal.NewFromString(node.MaxIntendedStake)
   293  	if err != nil {
   294  		return Node{}, err
   295  	}
   296  
   297  	pendingStake, err := decimal.NewFromString(node.PendingStake)
   298  	if err != nil {
   299  		return Node{}, err
   300  	}
   301  
   302  	delegations := make([]Delegation, len(node.Delegations))
   303  	for i, delegation := range node.Delegations {
   304  		delegations[i], err = DelegationFromProto(delegation, txHash)
   305  		if err != nil {
   306  			return Node{}, err
   307  		}
   308  	}
   309  
   310  	return Node{
   311  		ID:                NodeID(node.Id),
   312  		PubKey:            VegaPublicKey(node.PubKey),
   313  		TmPubKey:          TendermintPublicKey(node.TmPubKey),
   314  		EthereumAddress:   EthereumAddress(node.EthereumAddress),
   315  		InfoURL:           node.InfoUrl,
   316  		Location:          node.Location,
   317  		StakedByOperator:  stakedByOperator,
   318  		StakedByDelegates: stakedByDelegates,
   319  		StakedTotal:       stakedTotal,
   320  		MaxIntendedStake:  maxIntendedStake,
   321  		PendingStake:      pendingStake,
   322  		EpochData:         EpochData{node.EpochData},
   323  		Status:            NodeStatus(node.Status),
   324  		Delegations:       delegations,
   325  		// RewardScore:       RewardScore{node.RewardScore},
   326  		// RankingScore:      RankingScore{node.RankingScore},
   327  		Name:      node.Name,
   328  		AvatarURL: node.AvatarUrl,
   329  		TxHash:    txHash,
   330  		VegaTime:  vegaTime,
   331  	}, nil
   332  }
   333  
   334  func (node *Node) ToProto() *vega.Node {
   335  	protoDelegations := make([]*vega.Delegation, len(node.Delegations))
   336  	for i, delegation := range node.Delegations {
   337  		protoDelegations[i] = delegation.ToProto()
   338  	}
   339  
   340  	res := &vega.Node{
   341  		Id:                node.ID.String(),
   342  		PubKey:            node.PubKey.String(),
   343  		TmPubKey:          node.TmPubKey.String(),
   344  		EthereumAddress:   node.EthereumAddress.String(),
   345  		InfoUrl:           node.InfoURL,
   346  		Location:          node.Location,
   347  		StakedByOperator:  node.StakedByOperator.String(),
   348  		StakedByDelegates: node.StakedByDelegates.String(),
   349  		StakedTotal:       node.StakedTotal.String(),
   350  		MaxIntendedStake:  node.MaxIntendedStake.String(),
   351  		PendingStake:      node.PendingStake.String(),
   352  		EpochData:         node.EpochData.EpochData,
   353  		Status:            vega.NodeStatus(node.Status),
   354  		Delegations:       protoDelegations,
   355  		Name:              node.Name,
   356  		AvatarUrl:         node.AvatarURL,
   357  	}
   358  
   359  	if node.RewardScore != nil {
   360  		res.RewardScore = node.RewardScore.ToProto()
   361  	}
   362  
   363  	if node.RankingScore != nil {
   364  		res.RankingScore = node.RankingScore.ToProto()
   365  	}
   366  
   367  	return res
   368  }
   369  
   370  func (node Node) Cursor() *Cursor {
   371  	return NewCursor(NodeCursor{ID: node.ID}.String())
   372  }
   373  
   374  func (node Node) ToProtoEdge(_ ...any) (*v2.NodeEdge, error) {
   375  	return &v2.NodeEdge{
   376  		Node:   node.ToProto(),
   377  		Cursor: node.Cursor().Encode(),
   378  	}, nil
   379  }
   380  
   381  func (ed EpochData) MarshalJSON() ([]byte, error) {
   382  	return protojson.Marshal(ed)
   383  }
   384  
   385  func (ed *EpochData) UnmarshalJSON(b []byte) error {
   386  	ed.EpochData = &vega.EpochData{}
   387  	return protojson.Unmarshal(b, ed)
   388  }
   389  
   390  func (n *NodeSet) ToProto() *vega.NodeSet {
   391  	return &vega.NodeSet{
   392  		Total:    n.Total,
   393  		Demoted:  n.Demoted,
   394  		Promoted: n.Promoted,
   395  		Inactive: n.Inactive,
   396  	}
   397  }
   398  
   399  func (n *NodeData) ToProto() *vega.NodeData {
   400  	return &vega.NodeData{
   401  		StakedTotal:     n.StakedTotal.String(),
   402  		TotalNodes:      n.TotalNodes,
   403  		InactiveNodes:   n.InactiveNodes,
   404  		Uptime:          float32(n.Uptime),
   405  		TendermintNodes: n.TendermintNodes.ToProto(),
   406  		ErsatzNodes:     n.ErsatzNodes.ToProto(),
   407  		PendingNodes:    n.PendingNodes.ToProto(),
   408  	}
   409  }
   410  
   411  type NodeCursor struct {
   412  	ID NodeID `json:"id"`
   413  }
   414  
   415  func (nc NodeCursor) String() string {
   416  	bs, err := json.Marshal(nc)
   417  	if err != nil {
   418  		panic(fmt.Errorf("could not marshal node cursor: %w", err))
   419  	}
   420  	return string(bs)
   421  }
   422  
   423  func (nc *NodeCursor) Parse(cursorString string) error {
   424  	if cursorString == "" {
   425  		return nil
   426  	}
   427  	return json.Unmarshal([]byte(cursorString), nc)
   428  }