code.vegaprotocol.io/vega@v0.79.0/core/datasource/external/ethverifier/l2_verifier_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 ethverifier
    17  
    18  import (
    19  	"context"
    20  	"slices"
    21  	"sort"
    22  
    23  	"code.vegaprotocol.io/vega/core/datasource/external/ethcall"
    24  	"code.vegaprotocol.io/vega/core/types"
    25  	"code.vegaprotocol.io/vega/libs/proto"
    26  	"code.vegaprotocol.io/vega/logging"
    27  	snapshotpb "code.vegaprotocol.io/vega/protos/vega/snapshot/v1"
    28  
    29  	"golang.org/x/exp/maps"
    30  )
    31  
    32  var (
    33  	l2StateKey = (&types.PayloadL2EthOracles{}).Key()
    34  	l2HashKeys = []string{
    35  		l2StateKey,
    36  	}
    37  )
    38  
    39  func (s *L2Verifiers) Namespace() types.SnapshotNamespace {
    40  	return types.L2EthereumOraclesSnapshot
    41  }
    42  
    43  func (s *L2Verifiers) Keys() []string {
    44  	return l2HashKeys
    45  }
    46  
    47  func (s *L2Verifiers) Stopped() bool {
    48  	return false
    49  }
    50  
    51  func (s *L2Verifiers) GetState(k string) ([]byte, []types.StateProvider, error) {
    52  	if k != s.Keys()[0] {
    53  		return nil, nil, types.ErrInvalidSnapshotNamespace
    54  	}
    55  
    56  	ethOracles := &types.PayloadL2EthOracles{
    57  		L2EthOracles: &snapshotpb.L2EthOracles{},
    58  	}
    59  
    60  	for k, v := range s.verifiers {
    61  		s.log.Debug("serialising state for evm verifier", logging.String("source-chain-id", k))
    62  
    63  		slice := make([]*snapshotpb.EthVerifierBucket, 0, v.ackedEvts.Size())
    64  		iter := v.ackedEvts.events.Iterator()
    65  		for iter.Next() {
    66  			v := (iter.Value().(*ackedEvtBucket))
    67  			hashes := maps.Keys(v.hashes)
    68  			slices.Sort(hashes)
    69  			slice = append(slice, &snapshotpb.EthVerifierBucket{
    70  				Ts:     v.ts,
    71  				Hashes: hashes,
    72  			})
    73  		}
    74  
    75  		ethOracles.L2EthOracles.ChainIdEthOracles = append(
    76  			ethOracles.L2EthOracles.ChainIdEthOracles,
    77  			&snapshotpb.ChainIdEthOracles{
    78  				SourceChainId: k,
    79  				LastBlock:     v.ethBlockPayloadData(v.lastBlock).IntoProto().EthOracleVerifierLastBlock,
    80  				CallResults:   v.pendingContractCallEventsPayloadData().IntoProto().EthContractCallResults,
    81  				Misc: &snapshotpb.EthOracleVerifierMisc{
    82  					Buckets:    slice,
    83  					PatchBlock: v.ethBlockPayloadData(v.patchBlock).IntoProto().EthOracleVerifierLastBlock,
    84  				},
    85  			},
    86  		)
    87  	}
    88  
    89  	sort.Slice(ethOracles.L2EthOracles.ChainIdEthOracles, func(i, j int) bool {
    90  		return ethOracles.L2EthOracles.ChainIdEthOracles[i].SourceChainId < ethOracles.L2EthOracles.ChainIdEthOracles[j].SourceChainId
    91  	})
    92  
    93  	pl := types.Payload{
    94  		Data: ethOracles,
    95  	}
    96  
    97  	data, err := proto.Marshal(pl.IntoProto())
    98  
    99  	return data, nil, err
   100  }
   101  
   102  func (s *L2Verifiers) LoadState(ctx context.Context, payload *types.Payload) ([]types.StateProvider, error) {
   103  	if s.Namespace() != payload.Data.Namespace() {
   104  		return nil, types.ErrInvalidSnapshotNamespace
   105  	}
   106  
   107  	switch pl := payload.Data.(type) {
   108  	case *types.PayloadL2EthOracles:
   109  		s.restoreState(ctx, pl.L2EthOracles)
   110  		return nil, nil
   111  	default:
   112  		return nil, types.ErrUnknownSnapshotType
   113  	}
   114  }
   115  
   116  func (s *L2Verifiers) restoreState(ctx context.Context, l2EthOracles *snapshotpb.L2EthOracles) {
   117  	for _, v := range l2EthOracles.ChainIdEthOracles {
   118  		verifier, ok := s.verifiers[v.SourceChainId]
   119  		if !ok {
   120  			s.log.Panic("evm verifier for chain in snapshot, but not instantiated by network-parameter", logging.String("source-chain-id", v.SourceChainId))
   121  		}
   122  
   123  		s.log.Info("restoring evm verifier", logging.String("source-chain-id", v.SourceChainId))
   124  		// might be nil so need proper check first here
   125  		var lastBlock *types.EthBlock
   126  		if v.LastBlock != nil {
   127  			lastBlock = &types.EthBlock{
   128  				Height: v.LastBlock.BlockHeight,
   129  				Time:   v.LastBlock.BlockTime,
   130  			}
   131  		}
   132  
   133  		// do it once always
   134  		verifier.restoreLastEthBlock(ctx, lastBlock)
   135  
   136  		// this is the block of the upgrade
   137  		// we only initialize this the patchBlock and lastBlock
   138  		if v.Misc == nil {
   139  			if lastBlock != nil {
   140  				// no patchBlock, set it to the last Block
   141  				verifier.restorePatchBlock(ctx, &types.EthBlock{
   142  					Height: lastBlock.Height,
   143  					Time:   lastBlock.Time,
   144  				})
   145  			}
   146  		} else if v.Misc != nil {
   147  			// only run this if the misc exists, which might
   148  			// not be the case on a new upgrade after it's
   149  			// introduced
   150  			var patchBlock *types.EthBlock
   151  			if v.Misc.PatchBlock != nil {
   152  				patchBlock = &types.EthBlock{
   153  					Height: v.Misc.PatchBlock.BlockHeight,
   154  					Time:   v.Misc.PatchBlock.BlockTime,
   155  				}
   156  			}
   157  
   158  			verifier.restorePatchBlock(ctx, patchBlock)
   159  			verifier.restoreSeen(ctx, v.Misc.Buckets)
   160  		}
   161  		pending := []*ethcall.ContractCallEvent{}
   162  
   163  		for _, pr := range v.CallResults.PendingContractCallResult {
   164  			pending = append(pending, &ethcall.ContractCallEvent{
   165  				BlockHeight:   pr.BlockHeight,
   166  				BlockTime:     pr.BlockTime,
   167  				SpecId:        pr.SpecId,
   168  				Result:        pr.Result,
   169  				Error:         pr.Error,
   170  				SourceChainID: pr.ChainId,
   171  			})
   172  		}
   173  		verifier.restorePendingCallEvents(ctx, pending)
   174  	}
   175  }
   176  
   177  func (s *L2Verifiers) OnStateLoaded(ctx context.Context) error {
   178  	ids := maps.Keys(s.verifiers)
   179  	sort.Strings(ids)
   180  
   181  	// restart ethCall engines
   182  	for _, v := range ids {
   183  		s.log.Info("calling OnStateLoaded for evm verifier", logging.String("source-chain-id", v))
   184  		s.verifiers[v].OnStateLoaded(ctx)
   185  	}
   186  
   187  	return nil
   188  }