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, ðcall.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 }