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  }