code.vegaprotocol.io/vega@v0.79.0/core/banking/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 banking
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  	"math/big"
    22  	"sort"
    23  	"time"
    24  
    25  	"code.vegaprotocol.io/vega/core/types"
    26  	vgcontext "code.vegaprotocol.io/vega/libs/context"
    27  	"code.vegaprotocol.io/vega/libs/num"
    28  	"code.vegaprotocol.io/vega/libs/proto"
    29  	"code.vegaprotocol.io/vega/logging"
    30  	checkpoint "code.vegaprotocol.io/vega/protos/vega/checkpoint/v1"
    31  	snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    32  
    33  	"github.com/emirpasic/gods/sets/treeset"
    34  )
    35  
    36  var (
    37  	withdrawalsKey           = (&types.PayloadBankingWithdrawals{}).Key()
    38  	depositsKey              = (&types.PayloadBankingDeposits{}).Key()
    39  	seenKey                  = (&types.PayloadBankingSeen{}).Key()
    40  	assetActionsKey          = (&types.PayloadBankingAssetActions{}).Key()
    41  	recurringTransfersKey    = (&types.PayloadBankingRecurringTransfers{}).Key()
    42  	scheduledTransfersKey    = (&types.PayloadBankingScheduledTransfers{}).Key()
    43  	primaryBridgeStateKey    = (&types.PayloadBankingPrimaryBridgeState{}).Key()
    44  	secondaryBridgeStateKey  = (&types.PayloadBankingEVMBridgeStates{}).Key()
    45  	recurringGovTransfersKey = (&types.PayloadBankingRecurringGovernanceTransfers{}).Key()
    46  	scheduledGovTransfersKey = (&types.PayloadBankingScheduledGovernanceTransfers{}).Key()
    47  	transferFeeDiscountsKey  = (&types.PayloadBankingTransferFeeDiscounts{}).Key()
    48  
    49  	hashKeys = []string{
    50  		withdrawalsKey,
    51  		depositsKey,
    52  		seenKey,
    53  		assetActionsKey,
    54  		recurringTransfersKey,
    55  		scheduledTransfersKey,
    56  		primaryBridgeStateKey,
    57  		secondaryBridgeStateKey,
    58  		recurringGovTransfersKey,
    59  		scheduledGovTransfersKey,
    60  		transferFeeDiscountsKey,
    61  	}
    62  )
    63  
    64  type bankingSnapshotState struct {
    65  	serialisedWithdrawals           []byte
    66  	serialisedDeposits              []byte
    67  	serialisedSeen                  []byte
    68  	serialisedAssetActions          []byte
    69  	serialisedRecurringTransfers    []byte
    70  	serialisedScheduledTransfers    []byte
    71  	serialisedPrimaryBridgeState    []byte
    72  	serialisedSecondaryBridgeState  []byte
    73  	serialisedGovRecurringTransfers []byte
    74  	serialisedGovScheduledTransfers []byte
    75  	serialisedTransferFeeDiscounts  []byte
    76  }
    77  
    78  func (e *Engine) Namespace() types.SnapshotNamespace {
    79  	return types.BankingSnapshot
    80  }
    81  
    82  func (e *Engine) Keys() []string {
    83  	return hashKeys
    84  }
    85  
    86  func (e *Engine) Stopped() bool {
    87  	return false
    88  }
    89  
    90  func (e *Engine) serialisePrimaryBridgeState() ([]byte, error) {
    91  	payload := types.Payload{
    92  		Data: &types.PayloadBankingPrimaryBridgeState{
    93  			BankingBridgeState: &types.BankingBridgeState{
    94  				Active:      e.primaryBridgeState.active,
    95  				BlockHeight: e.primaryBridgeState.block,
    96  				LogIndex:    e.primaryBridgeState.logIndex,
    97  				ChainID:     e.primaryEthChainID,
    98  			},
    99  		},
   100  	}
   101  	return proto.Marshal(payload.IntoProto())
   102  }
   103  
   104  func (e *Engine) serialiseSecondaryBridgeState() ([]byte, error) {
   105  	payload := types.Payload{
   106  		Data: &types.PayloadBankingEVMBridgeStates{
   107  			// we only have one bridge state atm, its easy
   108  			BankingBridgeStates: []*checkpoint.BridgeState{
   109  				{
   110  					Active:      e.secondaryBridgeState.active,
   111  					BlockHeight: e.secondaryBridgeState.block,
   112  					LogIndex:    e.secondaryBridgeState.logIndex,
   113  					ChainId:     e.secondaryEthChainID,
   114  				},
   115  			},
   116  		},
   117  	}
   118  	return proto.Marshal(payload.IntoProto())
   119  }
   120  
   121  func (e *Engine) serialiseRecurringTransfers() ([]byte, error) {
   122  	payload := types.Payload{
   123  		Data: &types.PayloadBankingRecurringTransfers{
   124  			BankingRecurringTransfers: e.getRecurringTransfers(),
   125  			NextMetricUpdate:          e.nextMetricUpdate,
   126  		},
   127  	}
   128  
   129  	return proto.Marshal(payload.IntoProto())
   130  }
   131  
   132  func (e *Engine) serialiseScheduledTransfers() ([]byte, error) {
   133  	payload := types.Payload{
   134  		Data: &types.PayloadBankingScheduledTransfers{
   135  			BankingScheduledTransfers: e.getScheduledTransfers(),
   136  		},
   137  	}
   138  
   139  	return proto.Marshal(payload.IntoProto())
   140  }
   141  
   142  func (e *Engine) serialiseRecurringGovernanceTransfers() ([]byte, error) {
   143  	payload := types.Payload{
   144  		Data: &types.PayloadBankingRecurringGovernanceTransfers{
   145  			BankingRecurringGovernanceTransfers: e.getRecurringGovernanceTransfers(),
   146  		},
   147  	}
   148  
   149  	return proto.Marshal(payload.IntoProto())
   150  }
   151  
   152  func (e *Engine) serialiseScheduledGovernanceTransfers() ([]byte, error) {
   153  	payload := types.Payload{
   154  		Data: &types.PayloadBankingScheduledGovernanceTransfers{
   155  			BankingScheduledGovernanceTransfers: e.getScheduledGovernanceTransfers(),
   156  		},
   157  	}
   158  
   159  	return proto.Marshal(payload.IntoProto())
   160  }
   161  
   162  func (e *Engine) serialisedTransferFeeDiscounts() ([]byte, error) {
   163  	partyAssetDiscounts := make([]*snapshot.PartyAssetAmount, 0, len(e.feeDiscountPerPartyAndAsset))
   164  
   165  	for k, v := range e.feeDiscountPerPartyAndAsset {
   166  		partyAssetDiscounts = append(partyAssetDiscounts, &snapshot.PartyAssetAmount{
   167  			Party:  k.party,
   168  			Asset:  k.asset,
   169  			Amount: v.String(),
   170  		})
   171  	}
   172  	sort.SliceStable(partyAssetDiscounts, func(i, j int) bool {
   173  		if partyAssetDiscounts[i].Party == partyAssetDiscounts[j].Party {
   174  			return partyAssetDiscounts[i].Asset < partyAssetDiscounts[j].Asset
   175  		}
   176  		return partyAssetDiscounts[i].Party < partyAssetDiscounts[j].Party
   177  	})
   178  
   179  	payload := types.Payload{
   180  		Data: &types.PayloadBankingTransferFeeDiscounts{
   181  			BankingTransferFeeDiscounts: &snapshot.BankingTransferFeeDiscounts{
   182  				PartyAssetDiscount: partyAssetDiscounts,
   183  			},
   184  		},
   185  	}
   186  
   187  	return proto.Marshal(payload.IntoProto())
   188  }
   189  
   190  func (e *Engine) serialiseAssetActions() ([]byte, error) {
   191  	payload := types.Payload{
   192  		Data: &types.PayloadBankingAssetActions{
   193  			BankingAssetActions: &types.BankingAssetActions{
   194  				AssetAction: e.getAssetActions(),
   195  			},
   196  		},
   197  	}
   198  	return proto.Marshal(payload.IntoProto())
   199  }
   200  
   201  func (e *Engine) serialiseWithdrawals() ([]byte, error) {
   202  	withdrawals := make([]*types.RWithdrawal, 0, len(e.withdrawals))
   203  	for _, v := range e.withdrawals {
   204  		withdrawals = append(withdrawals, &types.RWithdrawal{Ref: v.ref.String(), Withdrawal: v.w})
   205  	}
   206  
   207  	sort.SliceStable(withdrawals, func(i, j int) bool { return withdrawals[i].Ref < withdrawals[j].Ref })
   208  
   209  	payload := types.Payload{
   210  		Data: &types.PayloadBankingWithdrawals{
   211  			BankingWithdrawals: &types.BankingWithdrawals{
   212  				Withdrawals: withdrawals,
   213  			},
   214  		},
   215  	}
   216  	return proto.Marshal(payload.IntoProto())
   217  }
   218  
   219  func (e *Engine) serialiseSeen() ([]byte, error) {
   220  	seen := &types.PayloadBankingSeen{
   221  		BankingSeen: &types.BankingSeen{
   222  			LastSeenPrimaryEthBlock:   e.lastSeenPrimaryEthBlock,
   223  			LastSeenSecondaryEthBlock: e.lastSeenSecondaryEthBlock,
   224  		},
   225  	}
   226  	seen.BankingSeen.Refs = make([]string, 0, e.seenAssetActions.Size())
   227  	iter := e.seenAssetActions.Iterator()
   228  	for iter.Next() {
   229  		seen.BankingSeen.Refs = append(seen.BankingSeen.Refs, iter.Value().(string))
   230  	}
   231  	payload := types.Payload{Data: seen}
   232  	return proto.Marshal(payload.IntoProto())
   233  }
   234  
   235  func (e *Engine) serialiseDeposits() ([]byte, error) {
   236  	e.log.Debug("serialiseDeposits: called")
   237  	deposits := make([]*types.BDeposit, 0, len(e.deposits))
   238  	for _, v := range e.deposits {
   239  		deposits = append(deposits, &types.BDeposit{ID: v.ID, Deposit: v})
   240  	}
   241  
   242  	sort.SliceStable(deposits, func(i, j int) bool { return deposits[i].ID < deposits[j].ID })
   243  
   244  	if e.log.IsDebug() {
   245  		e.log.Info("serialiseDeposits: number of deposits:", logging.Int("len(deposits)", len(deposits)))
   246  		for i, d := range deposits {
   247  			e.log.Info("serialiseDeposits:", logging.Int("index", i), logging.String("ID", d.ID), logging.String("deposit", d.Deposit.String()))
   248  		}
   249  	}
   250  	payload := types.Payload{
   251  		Data: &types.PayloadBankingDeposits{
   252  			BankingDeposits: &types.BankingDeposits{
   253  				Deposit: deposits,
   254  			},
   255  		},
   256  	}
   257  
   258  	return proto.Marshal(payload.IntoProto())
   259  }
   260  
   261  func (e *Engine) serialiseK(serialFunc func() ([]byte, error), dataField *[]byte) ([]byte, error) {
   262  	data, err := serialFunc()
   263  	if err != nil {
   264  		return nil, err
   265  	}
   266  	*dataField = data
   267  	return data, nil
   268  }
   269  
   270  // get the serialised form and hash of the given key.
   271  func (e *Engine) serialise(k string) ([]byte, error) {
   272  	switch k {
   273  	case depositsKey:
   274  		return e.serialiseK(e.serialiseDeposits, &e.bss.serialisedDeposits)
   275  	case withdrawalsKey:
   276  		return e.serialiseK(e.serialiseWithdrawals, &e.bss.serialisedWithdrawals)
   277  	case seenKey:
   278  		return e.serialiseK(e.serialiseSeen, &e.bss.serialisedSeen)
   279  	case assetActionsKey:
   280  		return e.serialiseK(e.serialiseAssetActions, &e.bss.serialisedAssetActions)
   281  	case recurringTransfersKey:
   282  		return e.serialiseK(e.serialiseRecurringTransfers, &e.bss.serialisedRecurringTransfers)
   283  	case scheduledTransfersKey:
   284  		return e.serialiseK(e.serialiseScheduledTransfers, &e.bss.serialisedScheduledTransfers)
   285  	case recurringGovTransfersKey:
   286  		return e.serialiseK(e.serialiseRecurringGovernanceTransfers, &e.bss.serialisedGovRecurringTransfers)
   287  	case scheduledGovTransfersKey:
   288  		return e.serialiseK(e.serialiseScheduledGovernanceTransfers, &e.bss.serialisedGovScheduledTransfers)
   289  	case transferFeeDiscountsKey:
   290  		return e.serialiseK(e.serialisedTransferFeeDiscounts, &e.bss.serialisedTransferFeeDiscounts)
   291  	case primaryBridgeStateKey:
   292  		return e.serialiseK(e.serialisePrimaryBridgeState, &e.bss.serialisedPrimaryBridgeState)
   293  	case secondaryBridgeStateKey:
   294  		return e.serialiseK(e.serialiseSecondaryBridgeState, &e.bss.serialisedSecondaryBridgeState)
   295  	default:
   296  		return nil, types.ErrSnapshotKeyDoesNotExist
   297  	}
   298  }
   299  
   300  func (e *Engine) GetState(k string) ([]byte, []types.StateProvider, error) {
   301  	state, err := e.serialise(k)
   302  	return state, nil, err
   303  }
   304  
   305  func (e *Engine) LoadState(ctx context.Context, p *types.Payload) ([]types.StateProvider, error) {
   306  	if e.Namespace() != p.Data.Namespace() {
   307  		return nil, types.ErrInvalidSnapshotNamespace
   308  	}
   309  	// see what we're reloading
   310  	switch pl := p.Data.(type) {
   311  	case *types.PayloadBankingDeposits:
   312  		return nil, e.restoreDeposits(pl.BankingDeposits, p)
   313  	case *types.PayloadBankingWithdrawals:
   314  		return nil, e.restoreWithdrawals(pl.BankingWithdrawals, p)
   315  	case *types.PayloadBankingSeen:
   316  		return nil, e.restoreSeen(ctx, pl.BankingSeen, p)
   317  	case *types.PayloadBankingAssetActions:
   318  		return nil, e.restoreAssetActions(pl.BankingAssetActions, p)
   319  	case *types.PayloadBankingRecurringTransfers:
   320  		return nil, e.restoreRecurringTransfers(ctx, pl.BankingRecurringTransfers, pl.NextMetricUpdate, p)
   321  	case *types.PayloadBankingScheduledTransfers:
   322  		return nil, e.restoreScheduledTransfers(ctx, pl.BankingScheduledTransfers, p)
   323  	case *types.PayloadBankingRecurringGovernanceTransfers:
   324  		return nil, e.restoreRecurringGovernanceTransfers(ctx, pl.BankingRecurringGovernanceTransfers, p)
   325  	case *types.PayloadBankingScheduledGovernanceTransfers:
   326  		return nil, e.restoreScheduledGovernanceTransfers(ctx, pl.BankingScheduledGovernanceTransfers, p)
   327  	case *types.PayloadBankingPrimaryBridgeState:
   328  		return nil, e.restorePrimaryBridgeState(pl.BankingBridgeState, p)
   329  	case *types.PayloadBankingEVMBridgeStates:
   330  		return nil, e.restoreSecondaryBridgeState(pl.BankingBridgeStates, p)
   331  	case *types.PayloadBankingTransferFeeDiscounts:
   332  		return nil, e.restoreTransferFeeDiscounts(pl.BankingTransferFeeDiscounts, p)
   333  	default:
   334  		return nil, types.ErrUnknownSnapshotType
   335  	}
   336  }
   337  
   338  func (e *Engine) restoreRecurringTransfers(ctx context.Context, transfers *checkpoint.RecurringTransfers, nextMetricUpdate time.Time, p *types.Payload) error {
   339  	var err error
   340  	// ignore events here as we don't need to send them
   341  	_ = e.loadRecurringTransfers(ctx, transfers)
   342  	e.bss.serialisedRecurringTransfers, err = proto.Marshal(p.IntoProto())
   343  	e.nextMetricUpdate = nextMetricUpdate
   344  	return err
   345  }
   346  
   347  func (e *Engine) restoreRecurringGovernanceTransfers(ctx context.Context, transfers []*checkpoint.GovernanceTransfer, p *types.Payload) error {
   348  	var err error
   349  	_ = e.loadRecurringGovernanceTransfers(ctx, transfers)
   350  	e.bss.serialisedGovRecurringTransfers, err = proto.Marshal(p.IntoProto())
   351  	return err
   352  }
   353  
   354  func (e *Engine) restoreScheduledTransfers(ctx context.Context, transfers []*checkpoint.ScheduledTransferAtTime, p *types.Payload) error {
   355  	var err error
   356  
   357  	// ignore events
   358  	_, err = e.loadScheduledTransfers(ctx, transfers)
   359  	if err != nil {
   360  		return err
   361  	}
   362  	e.bss.serialisedScheduledTransfers, err = proto.Marshal(p.IntoProto())
   363  	return err
   364  }
   365  
   366  func (e *Engine) restoreScheduledGovernanceTransfers(ctx context.Context, transfers []*checkpoint.ScheduledGovernanceTransferAtTime, p *types.Payload) error {
   367  	var err error
   368  	e.loadScheduledGovernanceTransfers(ctx, transfers)
   369  	e.bss.serialisedGovScheduledTransfers, err = proto.Marshal(p.IntoProto())
   370  	return err
   371  }
   372  
   373  func (e *Engine) restorePrimaryBridgeState(state *types.BankingBridgeState, p *types.Payload) (err error) {
   374  	if state != nil {
   375  		e.primaryBridgeState = &bridgeState{
   376  			active:   state.Active,
   377  			block:    state.BlockHeight,
   378  			logIndex: state.LogIndex,
   379  		}
   380  	}
   381  
   382  	e.bss.serialisedPrimaryBridgeState, err = proto.Marshal(p.IntoProto())
   383  	return
   384  }
   385  
   386  func (e *Engine) restoreSecondaryBridgeState(state []*checkpoint.BridgeState, p *types.Payload) (err error) {
   387  	if state != nil {
   388  		e.secondaryBridgeState = &bridgeState{
   389  			active:   state[0].Active,
   390  			block:    state[0].BlockHeight,
   391  			logIndex: state[0].LogIndex,
   392  		}
   393  	}
   394  
   395  	e.bss.serialisedSecondaryBridgeState, err = proto.Marshal(p.IntoProto())
   396  	return
   397  }
   398  
   399  func (e *Engine) restoreDeposits(deposits *types.BankingDeposits, p *types.Payload) error {
   400  	var err error
   401  
   402  	for _, d := range deposits.Deposit {
   403  		e.deposits[d.ID] = d.Deposit
   404  	}
   405  
   406  	e.bss.serialisedDeposits, err = proto.Marshal(p.IntoProto())
   407  	return err
   408  }
   409  
   410  func (e *Engine) restoreWithdrawals(withdrawals *types.BankingWithdrawals, p *types.Payload) error {
   411  	var err error
   412  	for _, w := range withdrawals.Withdrawals {
   413  		ref := new(big.Int)
   414  		ref.SetString(w.Ref, 10)
   415  		e.withdrawalCnt.Add(e.withdrawalCnt, big.NewInt(1))
   416  		e.withdrawals[w.Withdrawal.ID] = withdrawalRef{
   417  			w:   w.Withdrawal,
   418  			ref: ref,
   419  		}
   420  	}
   421  
   422  	e.bss.serialisedWithdrawals, err = proto.Marshal(p.IntoProto())
   423  
   424  	return err
   425  }
   426  
   427  func (e *Engine) restoreSeen(ctx context.Context, seen *types.BankingSeen, p *types.Payload) error {
   428  	var err error
   429  	e.log.Info("restoring seen", logging.Int("n", len(seen.Refs)))
   430  	e.seenAssetActions = treeset.NewWithStringComparator()
   431  	for _, v := range seen.Refs {
   432  		e.seenAssetActions.Add(v)
   433  	}
   434  
   435  	if vgcontext.InProgressUpgradeFrom(ctx, "v0.76.8") {
   436  		e.log.Info("migration code updating primary bridge last seen",
   437  			logging.String("address", e.bridgeAddresses[e.primaryEthChainID]),
   438  			logging.Uint64("last-seen", seen.LastSeenPrimaryEthBlock),
   439  		)
   440  		e.ethEventSource.UpdateContractBlock(
   441  			e.bridgeAddresses[e.primaryEthChainID],
   442  			e.primaryEthChainID,
   443  			seen.LastSeenPrimaryEthBlock,
   444  		)
   445  		e.log.Info("migration code updating primary bridge last seen",
   446  			logging.String("address", e.bridgeAddresses[e.secondaryEthChainID]),
   447  			logging.Uint64("last-seen", seen.LastSeenSecondaryEthBlock),
   448  		)
   449  		e.ethEventSource.UpdateContractBlock(
   450  			e.bridgeAddresses[e.secondaryEthChainID],
   451  			e.secondaryEthChainID,
   452  			seen.LastSeenSecondaryEthBlock,
   453  		)
   454  	}
   455  
   456  	e.lastSeenPrimaryEthBlock = seen.LastSeenPrimaryEthBlock
   457  	e.lastSeenSecondaryEthBlock = seen.LastSeenSecondaryEthBlock
   458  	e.bss.serialisedSeen, err = proto.Marshal(p.IntoProto())
   459  	return err
   460  }
   461  
   462  func (e *Engine) restoreAssetActions(aa *types.BankingAssetActions, p *types.Payload) error {
   463  	var err error
   464  
   465  	if err := e.loadAssetActions(aa.AssetAction); err != nil {
   466  		return fmt.Errorf("could not load asset actions: %w", err)
   467  	}
   468  
   469  	for _, aa := range e.assetActions {
   470  		if err := e.witness.RestoreResource(aa, e.onCheckDone); err != nil {
   471  			e.log.Panic("unable to restore witness resource", logging.String("id", aa.id), logging.Error(err))
   472  		}
   473  	}
   474  
   475  	e.bss.serialisedAssetActions, err = proto.Marshal(p.IntoProto())
   476  	return err
   477  }
   478  
   479  func (e *Engine) restoreTransferFeeDiscounts(
   480  	state *snapshot.BankingTransferFeeDiscounts,
   481  	p *types.Payload,
   482  ) (err error) {
   483  	if state == nil {
   484  		return nil
   485  	}
   486  
   487  	e.feeDiscountPerPartyAndAsset = make(map[partyAssetKey]*num.Uint, len(state.PartyAssetDiscount))
   488  	for _, v := range state.PartyAssetDiscount {
   489  		discount, _ := num.UintFromString(v.Amount, 10)
   490  		e.feeDiscountPerPartyAndAsset[e.feeDiscountKey(v.Asset, v.Party)] = discount
   491  	}
   492  
   493  	e.bss.serialisedTransferFeeDiscounts, err = proto.Marshal(p.IntoProto())
   494  	return
   495  }
   496  
   497  func (e *Engine) OnEpochRestore(_ context.Context, ep types.Epoch) {
   498  	e.log.Debug("epoch restoration notification received", logging.String("epoch", ep.String()))
   499  	e.currentEpoch = ep.Seq
   500  }