code.vegaprotocol.io/vega@v0.79.0/core/banking/deduplicate.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 "encoding/hex" 21 "errors" 22 "fmt" 23 24 vgcrypto "code.vegaprotocol.io/vega/libs/crypto" 25 vgproto "code.vegaprotocol.io/vega/libs/proto" 26 "code.vegaprotocol.io/vega/logging" 27 snapshot "code.vegaprotocol.io/vega/protos/vega/snapshot/v1" 28 ) 29 30 var ErrChainEventAlreadySeen = errors.New("chain event already processed") 31 32 // deduplicateAssetAction returns true if the action has been deduplicated, false 33 // if the action has never been seen before. 34 func (e *Engine) deduplicateAssetAction(ctx context.Context, action *assetAction) error { 35 ref := action.getRef() 36 37 refKey, err := buildRefKey(ref) 38 if err != nil { 39 return fmt.Errorf("could not build reference key: %w", err) 40 } 41 42 // Check if this action have been seen before. 43 if e.seenAssetActions.Contains(refKey) { 44 if err := e.dedupAction(ctx, action); err != nil { 45 e.log.Error("unable to deduplicate action", logging.String("action", action.String()), logging.Error(err)) 46 } 47 return ErrChainEventAlreadySeen 48 } 49 50 // Prior the introduction of the second bridge, the TxRef did 51 // not track the chain ID. Now that all TxRef have the chain ID filled, 52 // we must ensure an older TxRef is not applied twice because it got its 53 // chain ID valued, during a replay. 54 // 55 // This verification is only meaningful on actions coming from Ethereum 56 // Mainnet, hence the condition. 57 if ref.ChainId != "" && ref.ChainId == e.primaryEthChainID { 58 ref.ChainId = "" 59 60 refKeyWithChainID, err := buildRefKey(ref) 61 if err != nil { 62 return fmt.Errorf("could not build reference key: %w", err) 63 } 64 65 if e.seenAssetActions.Contains(refKeyWithChainID) { 66 if err := e.dedupAction(ctx, action); err != nil { 67 e.log.Error("unable to deduplicate action", logging.String("action", action.String()), logging.Error(err)) 68 } 69 return ErrChainEventAlreadySeen 70 } 71 } 72 73 // First time we see this transaction, so we keep track of it. 74 e.seenAssetActions.Add(refKey) 75 76 return nil 77 } 78 79 func buildRefKey(ref snapshot.TxRef) (string, error) { 80 buf, err := vgproto.Marshal(&ref) 81 if err != nil { 82 return "", err 83 } 84 85 return hex.EncodeToString(vgcrypto.Hash(buf)), nil 86 }