code.vegaprotocol.io/vega@v0.79.0/core/delegation/snapshot.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 delegation
    17  
    18  import (
    19  	"context"
    20  	"strconv"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/core/types"
    24  	"code.vegaprotocol.io/vega/libs/proto"
    25  	"code.vegaprotocol.io/vega/logging"
    26  )
    27  
    28  var hashKeys = []string{
    29  	activeKey,
    30  	pendingKey,
    31  	autoKey,
    32  	lastReconKey,
    33  }
    34  
    35  type delegationSnapshotState struct {
    36  	serialisedActive    []byte
    37  	serialisedPending   []byte
    38  	serialisedAuto      []byte
    39  	serialisedLastRecon []byte
    40  }
    41  
    42  func (e *Engine) Namespace() types.SnapshotNamespace {
    43  	return types.DelegationSnapshot
    44  }
    45  
    46  func (e *Engine) Keys() []string {
    47  	return hashKeys
    48  }
    49  
    50  func (e *Engine) Stopped() bool {
    51  	return false
    52  }
    53  
    54  func (e *Engine) serialiseLastReconTime() ([]byte, error) {
    55  	payload := types.Payload{
    56  		Data: &types.PayloadDelegationLastReconTime{
    57  			LastReconcilicationTime: e.lastReconciliation,
    58  		},
    59  	}
    60  	return proto.Marshal(payload.IntoProto())
    61  }
    62  
    63  func (e *Engine) serialiseActive() ([]byte, error) {
    64  	active := e.getActive()
    65  	delegations := make([]*types.Delegation, 0, len(active))
    66  	for _, a := range active {
    67  		delegations = append(delegations, &types.Delegation{
    68  			Party:    a.Party,
    69  			NodeID:   a.Node,
    70  			EpochSeq: strconv.FormatUint(a.EpochSeq, 10),
    71  			Amount:   a.Amount.Clone(),
    72  		})
    73  	}
    74  
    75  	payload := types.Payload{
    76  		Data: &types.PayloadDelegationActive{
    77  			DelegationActive: &types.DelegationActive{
    78  				Delegations: delegations,
    79  			},
    80  		},
    81  	}
    82  	return proto.Marshal(payload.IntoProto())
    83  }
    84  
    85  func (e *Engine) serialisePending() ([]byte, error) {
    86  	pending := e.getPendingNew()
    87  	pendingDelegations := make([]*types.Delegation, 0, len(pending))
    88  	pendingUndelegations := make([]*types.Delegation, 0, len(pending))
    89  	for _, a := range pending {
    90  		entry := &types.Delegation{
    91  			Party:    a.Party,
    92  			NodeID:   a.Node,
    93  			EpochSeq: strconv.FormatUint(a.EpochSeq, 10),
    94  			Amount:   a.Amount.Clone(),
    95  		}
    96  		if a.Undelegate {
    97  			pendingUndelegations = append(pendingUndelegations, entry)
    98  		} else {
    99  			pendingDelegations = append(pendingDelegations, entry)
   100  		}
   101  	}
   102  	payload := types.Payload{
   103  		Data: &types.PayloadDelegationPending{
   104  			DelegationPending: &types.DelegationPending{
   105  				Delegations:  pendingDelegations,
   106  				Undelegation: pendingUndelegations,
   107  			},
   108  		},
   109  	}
   110  
   111  	return proto.Marshal(payload.IntoProto())
   112  }
   113  
   114  func (e *Engine) serialiseAuto() ([]byte, error) {
   115  	auto := e.getAuto()
   116  	payload := types.Payload{
   117  		Data: &types.PayloadDelegationAuto{
   118  			DelegationAuto: &types.DelegationAuto{Parties: auto},
   119  		},
   120  	}
   121  	return proto.Marshal(payload.IntoProto())
   122  }
   123  
   124  func (e *Engine) serialiseK(serialFunc func() ([]byte, error), dataField *[]byte) ([]byte, error) {
   125  	data, err := serialFunc()
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	*dataField = data
   130  	return data, nil
   131  }
   132  
   133  // get the serialised form and hash of the given key.
   134  func (e *Engine) serialise(k string) ([]byte, error) {
   135  	switch k {
   136  	case activeKey:
   137  		return e.serialiseK(e.serialiseActive, &e.dss.serialisedActive)
   138  	case pendingKey:
   139  		return e.serialiseK(e.serialisePending, &e.dss.serialisedPending)
   140  	case autoKey:
   141  		return e.serialiseK(e.serialiseAuto, &e.dss.serialisedAuto)
   142  	case lastReconKey:
   143  		return e.serialiseK(e.serialiseLastReconTime, &e.dss.serialisedLastRecon)
   144  	default:
   145  		return nil, types.ErrSnapshotKeyDoesNotExist
   146  	}
   147  }
   148  
   149  func (e *Engine) GetState(k string) ([]byte, []types.StateProvider, error) {
   150  	state, err := e.serialise(k)
   151  	return state, nil, err
   152  }
   153  
   154  func (e *Engine) LoadState(ctx context.Context, p *types.Payload) ([]types.StateProvider, error) {
   155  	if e.Namespace() != p.Data.Namespace() {
   156  		return nil, types.ErrInvalidSnapshotNamespace
   157  	}
   158  	// see what we're reloading
   159  	switch pl := p.Data.(type) {
   160  	case *types.PayloadDelegationActive:
   161  		return nil, e.restoreActive(ctx, pl.DelegationActive, p)
   162  	case *types.PayloadDelegationPending:
   163  		return nil, e.restorePending(ctx, pl.DelegationPending, p)
   164  	case *types.PayloadDelegationAuto:
   165  		return nil, e.restoreAuto(pl.DelegationAuto, p)
   166  	case *types.PayloadDelegationLastReconTime:
   167  		return nil, e.restoreLastReconTime(pl.LastReconcilicationTime, p)
   168  	default:
   169  		return nil, types.ErrUnknownSnapshotType
   170  	}
   171  }
   172  
   173  func (e *Engine) restoreLastReconTime(t time.Time, p *types.Payload) error {
   174  	var err error
   175  	e.lastReconciliation = t
   176  	e.dss.serialisedLastRecon, err = proto.Marshal(p.IntoProto())
   177  
   178  	return err
   179  }
   180  
   181  func (e *Engine) restoreActive(ctx context.Context, delegations *types.DelegationActive, p *types.Payload) error {
   182  	e.partyDelegationState = map[string]*partyDelegation{}
   183  	entries := make([]*types.DelegationEntry, 0, len(delegations.Delegations))
   184  	for _, d := range delegations.Delegations {
   185  		epoch, _ := strconv.ParseUint(d.EpochSeq, 10, 64)
   186  		entries = append(entries, &types.DelegationEntry{
   187  			Party:    d.Party,
   188  			Node:     d.NodeID,
   189  			Amount:   d.Amount,
   190  			EpochSeq: epoch,
   191  		})
   192  	}
   193  	e.setActive(ctx, entries)
   194  	var err error
   195  	e.dss.serialisedActive, err = proto.Marshal(p.IntoProto())
   196  	return err
   197  }
   198  
   199  func (e *Engine) restorePending(ctx context.Context, delegations *types.DelegationPending, p *types.Payload) error {
   200  	e.nextPartyDelegationState = map[string]*partyDelegation{}
   201  	entries := make([]*types.DelegationEntry, 0, len(delegations.Delegations))
   202  	for _, d := range delegations.Delegations {
   203  		epoch, _ := strconv.ParseUint(d.EpochSeq, 10, 64)
   204  		entries = append(entries, &types.DelegationEntry{
   205  			Party:    d.Party,
   206  			Node:     d.NodeID,
   207  			Amount:   d.Amount,
   208  			EpochSeq: epoch,
   209  		})
   210  	}
   211  	e.setPendingNew(ctx, entries)
   212  	var err error
   213  	e.dss.serialisedPending, err = proto.Marshal(p.IntoProto())
   214  	return err
   215  }
   216  
   217  func (e *Engine) restoreAuto(delegations *types.DelegationAuto, p *types.Payload) error {
   218  	e.autoDelegationMode = map[string]struct{}{}
   219  	e.setAuto(delegations.Parties)
   220  	var err error
   221  	e.dss.serialisedAuto, err = proto.Marshal(p.IntoProto())
   222  	return err
   223  }
   224  
   225  func (e *Engine) onEpochRestore(ctx context.Context, epoch types.Epoch) {
   226  	e.log.Debug("epoch restoration notification received", logging.String("epoch", epoch.String()))
   227  	e.currentEpoch = epoch
   228  }