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 }