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  }