code.vegaprotocol.io/vega@v0.79.0/core/types/checkpoint.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 types 17 18 import ( 19 "bytes" 20 "errors" 21 "time" 22 23 "code.vegaprotocol.io/vega/libs/crypto" 24 "code.vegaprotocol.io/vega/libs/num" 25 "code.vegaprotocol.io/vega/libs/proto" 26 "code.vegaprotocol.io/vega/protos/vega" 27 checkpoint "code.vegaprotocol.io/vega/protos/vega/checkpoint/v1" 28 ) 29 30 var ( 31 ErrCheckpointStateInvalid = errors.New("state contained in the snapshot is invalid") 32 ErrCheckpointHashIncorrect = errors.New("the hash and snapshot data do not match") 33 ErrCheckpointHasNoState = errors.New("there is no state set on the checkpoint") 34 ) 35 36 type CheckpointName string 37 38 const ( 39 GovernanceCheckpoint CheckpointName = "governance" 40 AssetsCheckpoint CheckpointName = "assets" 41 CollateralCheckpoint CheckpointName = "collateral" 42 NetParamsCheckpoint CheckpointName = "netparams" 43 DelegationCheckpoint CheckpointName = "delegation" 44 EpochCheckpoint CheckpointName = "epoch" 45 BlockCheckpoint CheckpointName = "block" // pseudo-checkpoint, really... 46 MarketActivityTrackerCheckpoint CheckpointName = "marketActivity" 47 PendingRewardsCheckpoint CheckpointName = "rewards" 48 BankingCheckpoint CheckpointName = "banking" 49 ValidatorsCheckpoint CheckpointName = "validators" 50 StakingCheckpoint CheckpointName = "staking" 51 MultisigControlCheckpoint CheckpointName = "multisigControl" 52 ExecutionCheckpoint CheckpointName = "execution" 53 ) 54 55 type Block struct { 56 Height int64 57 } 58 59 type CheckpointState struct { 60 State []byte 61 Hash []byte 62 } 63 64 type Checkpoint struct { 65 Governance []byte 66 Assets []byte 67 Collateral []byte 68 NetworkParameters []byte 69 Delegation []byte 70 Epoch []byte 71 Block []byte 72 Rewards []byte 73 Validators []byte 74 Banking []byte 75 Staking []byte 76 MultisigControl []byte 77 MarketActivityTracker []byte 78 Execution []byte 79 } 80 81 type DelegationEntry struct { 82 Party string 83 Node string 84 Amount *num.Uint 85 Undelegate bool 86 EpochSeq uint64 87 } 88 89 type DelegateCP struct { 90 Active []*DelegationEntry 91 Pending []*DelegationEntry 92 Auto []string 93 } 94 95 func NewCheckpointStateFromProto(ps *checkpoint.CheckpointState) *CheckpointState { 96 return &CheckpointState{ 97 State: ps.State, 98 Hash: ps.Hash, 99 } 100 } 101 102 func (s CheckpointState) IntoProto() *checkpoint.CheckpointState { 103 return &checkpoint.CheckpointState{ 104 Hash: s.Hash, 105 State: s.State, 106 } 107 } 108 109 func (s CheckpointState) GetCheckpoint() (*Checkpoint, error) { 110 pc := &checkpoint.Checkpoint{} 111 if err := proto.Unmarshal(s.State, pc); err != nil { 112 return nil, err 113 } 114 cp := NewCheckpointFromProto(pc) 115 return cp, nil 116 } 117 118 func (s *CheckpointState) SetState(state []byte) error { 119 cp := &checkpoint.Checkpoint{} 120 if err := proto.Unmarshal(state, cp); err != nil { 121 return err 122 } 123 c := NewCheckpointFromProto(cp) 124 s.State = state 125 s.Hash = crypto.HashBytesBuffer(c.HashBytes()) 126 return nil 127 } 128 129 func (s CheckpointState) GetBlockHeight() (int64, error) { 130 if len(s.State) == 0 { 131 return 0, ErrCheckpointHasNoState 132 } 133 cp := &checkpoint.Checkpoint{} 134 if err := proto.Unmarshal(s.State, cp); err != nil { 135 return 0, err 136 } 137 c := NewCheckpointFromProto(cp) 138 return c.GetBlockHeight() 139 } 140 141 func (s *CheckpointState) SetCheckpoint(cp *Checkpoint) error { 142 b, err := proto.Marshal(cp.IntoProto()) 143 if err != nil { 144 return err 145 } 146 s.Hash = crypto.HashBytesBuffer(cp.HashBytes()) 147 s.State = b 148 return nil 149 } 150 151 // Validate checks the hash, returns nil if valid. 152 func (s CheckpointState) Validate() error { 153 cp, err := s.GetCheckpoint() 154 if err != nil { 155 return ErrCheckpointStateInvalid 156 } 157 if !bytes.Equal(crypto.HashBytesBuffer(cp.HashBytes()), s.Hash) { 158 return ErrCheckpointHashIncorrect 159 } 160 return nil 161 } 162 163 func NewCheckpointFromProto(pc *checkpoint.Checkpoint) *Checkpoint { 164 return &Checkpoint{ 165 Governance: pc.Governance, 166 Assets: pc.Assets, 167 Collateral: pc.Collateral, 168 NetworkParameters: pc.NetworkParameters, 169 Delegation: pc.Delegation, 170 Epoch: pc.Epoch, 171 Block: pc.Block, 172 Rewards: pc.Rewards, 173 Validators: pc.Validators, 174 Banking: pc.Banking, 175 Staking: pc.Staking, 176 MultisigControl: pc.MultisigControl, 177 MarketActivityTracker: pc.MarketTracker, 178 Execution: pc.Execution, 179 } 180 } 181 182 func (c Checkpoint) IntoProto() *checkpoint.Checkpoint { 183 return &checkpoint.Checkpoint{ 184 Governance: c.Governance, 185 Assets: c.Assets, 186 Collateral: c.Collateral, 187 NetworkParameters: c.NetworkParameters, 188 Delegation: c.Delegation, 189 Epoch: c.Epoch, 190 Block: c.Block, 191 Rewards: c.Rewards, 192 Validators: c.Validators, 193 Banking: c.Banking, 194 Staking: c.Staking, 195 MultisigControl: c.MultisigControl, 196 MarketTracker: c.MarketActivityTracker, 197 Execution: c.Execution, 198 } 199 } 200 201 func (c *Checkpoint) SetBlockHeight(height int64) error { 202 b := Block{ 203 Height: height, 204 } 205 bb, err := proto.Marshal(b.IntoProto()) 206 if err != nil { 207 return err 208 } 209 c.Block = bb 210 return nil 211 } 212 213 // HashBytes returns the data contained in the checkpoint as a []byte for hashing 214 // the order in which the data is added to the slice matters. 215 func (c Checkpoint) HashBytes() bytes.Buffer { 216 var b bytes.Buffer 217 // the order in which we append is quite important 218 b.Write(c.NetworkParameters) 219 b.Write(c.Assets) 220 b.Write(c.Collateral) 221 b.Write(c.Delegation) 222 b.Write(c.Epoch) 223 b.Write(c.Block) 224 b.Write(c.Governance) 225 b.Write(c.Rewards) 226 b.Write(c.Banking) 227 b.Write(c.Validators) 228 b.Write(c.Staking) 229 b.Write(c.MarketActivityTracker) 230 b.Write(c.MultisigControl) 231 b.Write(c.Execution) 232 233 return b 234 } 235 236 // Set set a specific checkpoint value using the name the engine returns. 237 func (c *Checkpoint) Set(name CheckpointName, val []byte) { 238 switch name { 239 case GovernanceCheckpoint: 240 c.Governance = val 241 case AssetsCheckpoint: 242 c.Assets = val 243 case CollateralCheckpoint: 244 c.Collateral = val 245 case NetParamsCheckpoint: 246 c.NetworkParameters = val 247 case DelegationCheckpoint: 248 c.Delegation = val 249 case EpochCheckpoint: 250 c.Epoch = val 251 case BlockCheckpoint: 252 c.Block = val 253 case PendingRewardsCheckpoint: 254 c.Rewards = val 255 case ValidatorsCheckpoint: 256 c.Validators = val 257 case BankingCheckpoint: 258 c.Banking = val 259 case StakingCheckpoint: 260 c.Staking = val 261 case MultisigControlCheckpoint: 262 c.MultisigControl = val 263 case MarketActivityTrackerCheckpoint: 264 c.MarketActivityTracker = val 265 case ExecutionCheckpoint: 266 c.Execution = val 267 } 268 } 269 270 // Get as the name suggests gets the data by checkpoint name. 271 func (c Checkpoint) Get(name CheckpointName) []byte { 272 switch name { 273 case GovernanceCheckpoint: 274 return c.Governance 275 case AssetsCheckpoint: 276 return c.Assets 277 case CollateralCheckpoint: 278 return c.Collateral 279 case NetParamsCheckpoint: 280 return c.NetworkParameters 281 case DelegationCheckpoint: 282 return c.Delegation 283 case EpochCheckpoint: 284 return c.Epoch 285 case BlockCheckpoint: 286 return c.Block 287 case PendingRewardsCheckpoint: 288 return c.Rewards 289 case ValidatorsCheckpoint: 290 return c.Validators 291 case BankingCheckpoint: 292 return c.Banking 293 case StakingCheckpoint: 294 return c.Staking 295 case MultisigControlCheckpoint: 296 return c.MultisigControl 297 case MarketActivityTrackerCheckpoint: 298 return c.MarketActivityTracker 299 case ExecutionCheckpoint: 300 return c.Execution 301 } 302 return nil 303 } 304 305 func (c Checkpoint) GetBlockHeight() (int64, error) { 306 pb := &checkpoint.Block{} 307 if err := proto.Unmarshal(c.Block, pb); err != nil { 308 return 0, err 309 } 310 return pb.Height, nil 311 } 312 313 func NewDelegationEntryFromProto(de *checkpoint.DelegateEntry) *DelegationEntry { 314 amt, _ := num.UintFromString(de.Amount, 10) 315 return &DelegationEntry{ 316 Party: de.Party, 317 Node: de.Node, 318 Amount: amt, 319 Undelegate: de.Undelegate, 320 EpochSeq: de.EpochSeq, 321 } 322 } 323 324 func (d DelegationEntry) IntoProto() *checkpoint.DelegateEntry { 325 return &checkpoint.DelegateEntry{ 326 Party: d.Party, 327 Node: d.Node, 328 Amount: d.Amount.String(), 329 Undelegate: d.Undelegate, 330 EpochSeq: d.EpochSeq, 331 } 332 } 333 334 func NewDelegationCPFromProto(sd *checkpoint.Delegate) *DelegateCP { 335 r := &DelegateCP{ 336 Active: make([]*DelegationEntry, 0, len(sd.Active)), 337 Pending: make([]*DelegationEntry, 0, len(sd.Pending)), 338 Auto: sd.AutoDelegation[:], 339 } 340 for _, a := range sd.Active { 341 r.Active = append(r.Active, NewDelegationEntryFromProto(a)) 342 } 343 for _, p := range sd.Pending { 344 r.Pending = append(r.Pending, NewDelegationEntryFromProto(p)) 345 } 346 return r 347 } 348 349 func (d DelegateCP) IntoProto() *checkpoint.Delegate { 350 s := &checkpoint.Delegate{ 351 Active: make([]*checkpoint.DelegateEntry, 0, len(d.Active)), 352 Pending: make([]*checkpoint.DelegateEntry, 0, len(d.Pending)), 353 AutoDelegation: d.Auto[:], 354 } 355 for _, a := range d.Active { 356 s.Active = append(s.Active, a.IntoProto()) 357 } 358 for _, p := range d.Pending { 359 s.Pending = append(s.Pending, p.IntoProto()) 360 } 361 return s 362 } 363 364 func NewBlockFromProto(bp *checkpoint.Block) *Block { 365 return &Block{ 366 Height: bp.Height, 367 } 368 } 369 370 func (b Block) IntoProto() *checkpoint.Block { 371 return &checkpoint.Block{ 372 Height: b.Height, 373 } 374 } 375 376 type ELSShare struct { 377 PartyID string 378 Share num.Decimal 379 SuppliedStake num.Decimal 380 VStake num.Decimal 381 Avg num.Decimal 382 } 383 384 func NewELSShareFromProto(ELSs *checkpoint.ELSShare) *ELSShare { 385 return &ELSShare{ 386 PartyID: ELSs.PartyId, 387 Share: num.MustDecimalFromString(ELSs.Share), 388 SuppliedStake: num.MustDecimalFromString(ELSs.SuppliedStake), 389 VStake: num.MustDecimalFromString(ELSs.VirtualStake), 390 Avg: num.MustDecimalFromString(ELSs.Avg), 391 } 392 } 393 394 func (e *ELSShare) IntoProto() *checkpoint.ELSShare { 395 return &checkpoint.ELSShare{ 396 PartyId: e.PartyID, 397 Share: e.Share.String(), 398 SuppliedStake: e.SuppliedStake.String(), 399 VirtualStake: e.VStake.String(), 400 Avg: e.Avg.String(), 401 } 402 } 403 404 type CPMarketState struct { 405 ID string 406 Shares []*ELSShare 407 InsuranceBalance *num.Uint 408 LastTradeValue *num.Uint 409 LastTradeVolume *num.Uint 410 TTL time.Time 411 Market *Market // the full market object - needed in case the market has settled but a successor market is enacted during the successor window. 412 State MarketState // only used during OnTick, indicating the parent is still in opening auction 413 } 414 415 func NewMarketStateFromProto(ms *checkpoint.MarketState) *CPMarketState { 416 els := make([]*ELSShare, 0, len(ms.Shares)) 417 for _, s := range ms.Shares { 418 els = append(els, NewELSShareFromProto(s)) 419 } 420 var insBal, tVal, tVol *num.Uint 421 if len(ms.InsuranceBalance) > 0 { 422 insBal, _ = num.UintFromString(ms.InsuranceBalance, 10) 423 } 424 if len(ms.LastTradeValue) > 0 { 425 tVal, _ = num.UintFromString(ms.LastTradeValue, 10) 426 } 427 if len(ms.LastTradeVolume) > 0 { 428 tVol, _ = num.UintFromString(ms.LastTradeVolume, 10) 429 } 430 var mkt *Market 431 if ms.Market != nil { 432 mkt, _ = MarketFromProto(ms.Market) 433 } 434 return &CPMarketState{ 435 ID: ms.Id, 436 Shares: els, 437 InsuranceBalance: insBal, 438 LastTradeValue: tVal, 439 LastTradeVolume: tVol, 440 TTL: time.Unix(0, ms.SuccessionWindow), 441 Market: mkt, 442 } 443 } 444 445 func (m *CPMarketState) IntoProto() *checkpoint.MarketState { 446 els := make([]*checkpoint.ELSShare, 0, len(m.Shares)) 447 for _, s := range m.Shares { 448 els = append(els, s.IntoProto()) 449 } 450 var mkt *vega.Market 451 if m.Market != nil { 452 mkt = m.Market.IntoProto() 453 } 454 var insBal, ltVal, ltVol string 455 if m.InsuranceBalance != nil { 456 insBal = m.InsuranceBalance.String() 457 } 458 if m.LastTradeValue != nil { 459 ltVal = m.LastTradeValue.String() 460 } 461 if m.LastTradeVolume != nil { 462 ltVol = m.LastTradeVolume.String() 463 } 464 return &checkpoint.MarketState{ 465 Id: m.ID, 466 Shares: els, 467 InsuranceBalance: insBal, 468 LastTradeValue: ltVal, 469 LastTradeVolume: ltVol, 470 SuccessionWindow: m.TTL.UnixNano(), 471 Market: mkt, 472 } 473 } 474 475 type ExecutionState struct { 476 Data []*CPMarketState 477 } 478 479 func NewExecutionStateFromProto(es *checkpoint.ExecutionState) *ExecutionState { 480 d := make([]*CPMarketState, 0, len(es.Data)) 481 for _, m := range es.Data { 482 d = append(d, NewMarketStateFromProto(m)) 483 } 484 return &ExecutionState{ 485 Data: d, 486 } 487 } 488 489 func (e *ExecutionState) IntoProto() *checkpoint.ExecutionState { 490 d := make([]*checkpoint.MarketState, 0, len(e.Data)) 491 for _, m := range e.Data { 492 d = append(d, m.IntoProto()) 493 } 494 return &checkpoint.ExecutionState{ 495 Data: d, 496 } 497 }