code.vegaprotocol.io/vega@v0.79.0/core/collateral/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 collateral
    17  
    18  import (
    19  	"context"
    20  	"sort"
    21  	"time"
    22  
    23  	"code.vegaprotocol.io/vega/core/events"
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/libs/num"
    26  	"code.vegaprotocol.io/vega/libs/proto"
    27  	"code.vegaprotocol.io/vega/logging"
    28  
    29  	"github.com/pkg/errors"
    30  )
    31  
    32  type accState struct {
    33  	accPL              types.PayloadCollateralAccounts
    34  	assPL              types.PayloadCollateralAssets
    35  	assets             map[string]types.Asset
    36  	assetIDs           []string
    37  	serialisedAccounts []byte
    38  	serialisedAssets   []byte
    39  	hashKeys           []string
    40  	accountsKey        string
    41  	assetsKey          string
    42  }
    43  
    44  var (
    45  	ErrInvalidSnapshotNamespace = errors.New("invalid snapshot namespace")
    46  	ErrUnknownSnapshotType      = errors.New("snapshot data type not known")
    47  )
    48  
    49  func (e *Engine) Namespace() types.SnapshotNamespace {
    50  	return types.CollateralSnapshot
    51  }
    52  
    53  func (e *Engine) Keys() []string {
    54  	return e.state.hashKeys
    55  }
    56  
    57  func (e *Engine) Stopped() bool {
    58  	return false
    59  }
    60  
    61  func (e *Engine) GetState(k string) ([]byte, []types.StateProvider, error) {
    62  	state, err := e.state.getState(k)
    63  	return state, nil, err
    64  }
    65  
    66  func (e *Engine) LoadState(ctx context.Context, p *types.Payload) ([]types.StateProvider, error) {
    67  	if e.Namespace() != p.Data.Namespace() {
    68  		return nil, ErrInvalidSnapshotNamespace
    69  	}
    70  	// see what we're reloading
    71  	switch pl := p.Data.(type) {
    72  	case *types.PayloadCollateralAssets:
    73  		err := e.restoreAssets(pl.CollateralAssets, p)
    74  		return nil, err
    75  	case *types.PayloadCollateralAccounts:
    76  		err := e.restoreAccounts(ctx, pl.CollateralAccounts, p)
    77  		return nil, err
    78  	default:
    79  		return nil, ErrUnknownSnapshotType
    80  	}
    81  }
    82  
    83  func (e *Engine) restoreAccounts(ctx context.Context, accs *types.CollateralAccounts, p *types.Payload) error {
    84  	e.log.Debug("restoring accounts snapshot", logging.Int("n_accounts", len(accs.Accounts)))
    85  
    86  	evts := []events.Event{}
    87  	pevts := []events.Event{}
    88  	e.accs = make(map[string]*types.Account, len(accs.Accounts))
    89  	e.partiesAccs = map[string]map[string]*types.Account{}
    90  	e.hashableAccs = make([]*types.Account, 0, len(accs.Accounts))
    91  	assets := map[string]struct{}{}
    92  	for _, acc := range accs.Accounts {
    93  		e.accs[acc.ID] = acc
    94  		assets[acc.Asset] = struct{}{}
    95  		if _, ok := e.partiesAccs[acc.Owner]; !ok {
    96  			e.partiesAccs[acc.Owner] = map[string]*types.Account{}
    97  		}
    98  		e.partiesAccs[acc.Owner][acc.ID] = acc
    99  		e.hashableAccs = append(e.hashableAccs, acc)
   100  		e.addAccountToHashableSlice(acc)
   101  
   102  		evts = append(evts, events.NewAccountEvent(ctx, *acc))
   103  
   104  		if acc.Owner != systemOwner {
   105  			pevts = append(pevts, events.NewPartyEvent(ctx, types.Party{Id: acc.Owner}))
   106  		}
   107  	}
   108  	e.state.updateAccs(e.hashableAccs)
   109  	e.broker.SendBatch(evts)
   110  	e.broker.SendBatch(pevts)
   111  	var err error
   112  	e.state.serialisedAccounts, err = proto.Marshal(p.IntoProto())
   113  	e.updateNextBalanceSnapshot(accs.NextBalanceSnapshot)
   114  	e.snapshotBalances()
   115  	e.earmarkedBalance = accs.Earmarked
   116  	e.state.updateEarmarked(e.earmarkedBalance)
   117  	return err
   118  }
   119  
   120  func (e *Engine) restoreAssets(assets *types.CollateralAssets, p *types.Payload) error {
   121  	// @TODO the ID and name might not be the same, perhaps we need
   122  	// to wrap the asset details to preserve that data
   123  	e.log.Debug("restoring assets snapshot", logging.Int("n_assets", len(assets.Assets)))
   124  	e.enabledAssets = make(map[string]types.Asset, len(assets.Assets))
   125  	e.state.assetIDs = make([]string, 0, len(assets.Assets))
   126  	e.state.assets = make(map[string]types.Asset, len(assets.Assets))
   127  	for _, a := range assets.Assets {
   128  		ast := types.Asset{
   129  			ID:      a.ID,
   130  			Details: a.Details,
   131  			Status:  a.Status,
   132  		}
   133  		e.enabledAssets[a.ID] = ast
   134  		e.state.enableAsset(ast)
   135  	}
   136  	var err error
   137  	e.state.serialisedAssets, err = proto.Marshal(p.IntoProto())
   138  	e.snapshotBalances()
   139  	return err
   140  }
   141  
   142  func newAccState() *accState {
   143  	state := &accState{
   144  		accPL: types.PayloadCollateralAccounts{
   145  			CollateralAccounts: &types.CollateralAccounts{
   146  				NextBalanceSnapshot: time.Time{},
   147  			},
   148  		},
   149  		assPL: types.PayloadCollateralAssets{
   150  			CollateralAssets: &types.CollateralAssets{},
   151  		},
   152  		assets:   map[string]types.Asset{},
   153  		assetIDs: []string{},
   154  	}
   155  	state.accountsKey = state.accPL.Key()
   156  	state.assetsKey = state.assPL.Key()
   157  	state.hashKeys = []string{
   158  		state.assetsKey,
   159  		state.accountsKey,
   160  	}
   161  
   162  	return state
   163  }
   164  
   165  func (a *accState) enableAsset(asset types.Asset) {
   166  	a.assets[asset.ID] = asset
   167  	a.assetIDs = append(a.assetIDs, asset.ID)
   168  	sort.Strings(a.assetIDs)
   169  }
   170  
   171  func (a *accState) updateAsset(asset types.Asset) {
   172  	a.assets[asset.ID] = asset
   173  }
   174  
   175  func (a *accState) updateAccs(accs []*types.Account) {
   176  	a.accPL.CollateralAccounts.Accounts = accs[:]
   177  }
   178  
   179  func (a *accState) updateEarmarked(earmarked map[string]*num.Uint) {
   180  	a.accPL.CollateralAccounts.Earmarked = earmarked
   181  }
   182  
   183  func (a *accState) updateBalanceSnapshotTime(t time.Time) {
   184  	a.accPL.CollateralAccounts.NextBalanceSnapshot = t
   185  }
   186  
   187  func (a *accState) hashAssets() ([]byte, error) {
   188  	assets := make([]*types.Asset, 0, len(a.assetIDs))
   189  	for _, id := range a.assetIDs {
   190  		ast := a.assets[id]
   191  		assets = append(assets, &ast)
   192  	}
   193  	a.assPL.CollateralAssets.Assets = assets
   194  	pl := types.Payload{
   195  		Data: &a.assPL,
   196  	}
   197  	data, err := proto.Marshal(pl.IntoProto())
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	a.serialisedAssets = data
   202  	return data, nil
   203  }
   204  
   205  func (a *accState) hashAccounts() ([]byte, error) {
   206  	// the account slice is already set, sorted and all
   207  	pl := types.Payload{
   208  		Data: &a.accPL,
   209  	}
   210  	data, err := proto.Marshal(pl.IntoProto())
   211  	if err != nil {
   212  		return nil, err
   213  	}
   214  	a.serialisedAccounts = data
   215  	return data, nil
   216  }
   217  
   218  func (a *accState) serialiseK(serialFunc func() ([]byte, error), dataField *[]byte) ([]byte, error) {
   219  	data, err := serialFunc()
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	*dataField = data
   224  	return data, nil
   225  }
   226  
   227  // get the serialised form and hash of the given key.
   228  func (a *accState) getState(k string) ([]byte, error) {
   229  	switch k {
   230  	case a.accountsKey:
   231  		return a.serialiseK(a.hashAccounts, &a.serialisedAccounts)
   232  	case a.assetsKey:
   233  		return a.serialiseK(a.hashAssets, &a.serialisedAssets)
   234  	default:
   235  		return nil, types.ErrSnapshotKeyDoesNotExist
   236  	}
   237  }