code.vegaprotocol.io/vega@v0.79.0/core/evtforward/engine.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 evtforward
    17  
    18  import (
    19  	"context"
    20  	"fmt"
    21  
    22  	"code.vegaprotocol.io/vega/core/evtforward/ethereum"
    23  	"code.vegaprotocol.io/vega/core/types"
    24  	"code.vegaprotocol.io/vega/logging"
    25  )
    26  
    27  const (
    28  	topEngineLogger = "event-forwarder"
    29  	ethereumLogger  = "ethereum"
    30  )
    31  
    32  type Engine struct {
    33  	cfg ethereum.Config
    34  	log *logging.Logger
    35  
    36  	ethEngine *ethereum.Engine
    37  
    38  	stakingStartingBlock         uint64
    39  	multisigControlStartingBlock uint64
    40  }
    41  
    42  func NewEngine(log *logging.Logger, config ethereum.Config) *Engine {
    43  	topEngineLogger := log.Named(topEngineLogger)
    44  	topEngineLogger.SetLevel(config.Level.Get())
    45  
    46  	return &Engine{
    47  		cfg: config,
    48  		log: topEngineLogger,
    49  	}
    50  }
    51  
    52  // ReloadConf updates the internal configuration of the Event Forwarder engine.
    53  func (e *Engine) ReloadConf(config ethereum.Config) {
    54  	e.log.Info("Reloading configuration")
    55  
    56  	if e.log.GetLevel() != config.Level.Get() {
    57  		e.log.Debug("Updating log level",
    58  			logging.String("old", e.log.GetLevel().String()),
    59  			logging.String("new", config.Level.String()),
    60  		)
    61  		e.log.SetLevel(config.Level.Get())
    62  	}
    63  	if e.ethEngine != nil {
    64  		e.ethEngine.ReloadConf(config)
    65  	}
    66  }
    67  
    68  func (e *Engine) UpdateCollateralStartingBlock(b uint64) {
    69  	e.ethEngine.UpdateCollateralStartingBlock(b)
    70  }
    71  
    72  func (e *Engine) UpdateStakingStartingBlock(b uint64) {
    73  	e.stakingStartingBlock = b
    74  	e.ethEngine.UpdateStakingStartingBlock(b)
    75  }
    76  
    77  func (e *Engine) UpdateMultisigControlStartingBlock(b uint64) {
    78  	e.multisigControlStartingBlock = b
    79  	e.ethEngine.UpdateMultiSigControlStartingBlock(b)
    80  }
    81  
    82  func (e *Engine) VerifyHeartbeat(ctx context.Context, height uint64, chainID string, contract string, blockTime uint64) error {
    83  	return e.ethEngine.VerifyHeartbeat(ctx, height, chainID, contract, blockTime)
    84  }
    85  
    86  func (e *Engine) UpdateStartingBlock(address string, block uint64) {
    87  	e.ethEngine.UpdateStartingBlock(address, block)
    88  }
    89  
    90  func (e *Engine) SetupEthereumEngine(
    91  	client ethereum.Client,
    92  	forwarder ethereum.Forwarder,
    93  	config ethereum.Config,
    94  	ethCfg *types.EthereumConfig,
    95  	assets ethereum.Assets,
    96  ) error {
    97  	if e.log.IsDebug() {
    98  		e.log.Debug("Ethereum configuration has been loaded")
    99  	}
   100  
   101  	if e.ethEngine != nil {
   102  		if e.log.IsDebug() {
   103  			e.log.Debug("Stopping previous Ethereum Event Forwarder")
   104  		}
   105  		e.Stop()
   106  	}
   107  
   108  	if e.log.IsDebug() {
   109  		e.log.Debug("Setting up the Ethereum Event Forwarder")
   110  	}
   111  
   112  	ethLogger := e.log.Named(ethereumLogger)
   113  	ethLogger.SetLevel(config.Level.Get())
   114  
   115  	filterer, err := ethereum.NewLogFilterer(
   116  		e.cfg,
   117  		ethLogger,
   118  		client,
   119  		ethCfg.CollateralBridge(),
   120  		ethCfg.StakingBridge(),
   121  		ethCfg.VestingBridge(),
   122  		ethCfg.MultiSigControl(),
   123  		assets,
   124  		ethCfg.ChainID(),
   125  	)
   126  	if err != nil {
   127  		return fmt.Errorf("couldn't create the log filterer: %w", err)
   128  	}
   129  
   130  	e.ethEngine = ethereum.NewEngine(
   131  		e.cfg,
   132  		ethLogger,
   133  		filterer,
   134  		forwarder,
   135  		ethCfg.StakingBridge(),
   136  		ethCfg.VestingBridge(),
   137  		ethCfg.MultiSigControl(),
   138  		ethCfg.CollateralBridge(),
   139  		ethCfg.ChainID(),
   140  		ethCfg.BlockTime(),
   141  	)
   142  
   143  	e.UpdateCollateralStartingBlock(filterer.CurrentHeight(context.Background()))
   144  
   145  	if e.multisigControlStartingBlock != 0 {
   146  		e.ethEngine.UpdateMultiSigControlStartingBlock(e.multisigControlStartingBlock)
   147  	}
   148  	if e.stakingStartingBlock != 0 {
   149  		e.ethEngine.UpdateStakingStartingBlock(e.stakingStartingBlock)
   150  	}
   151  
   152  	if err := filterer.VerifyClient(context.Background()); err != nil {
   153  		return err
   154  	}
   155  
   156  	e.Start()
   157  
   158  	return nil
   159  }
   160  
   161  func (e *Engine) SetupSecondaryEthereumEngine(
   162  	client ethereum.Client,
   163  	forwarder ethereum.Forwarder,
   164  	config ethereum.Config,
   165  	ethCfg *types.EVMChainConfig,
   166  	assets ethereum.Assets,
   167  ) error {
   168  	if e.log.IsDebug() {
   169  		e.log.Debug("Secondary Ethereum configuration has been loaded")
   170  	}
   171  
   172  	if e.ethEngine != nil {
   173  		if e.log.IsDebug() {
   174  			e.log.Debug("Stopping previous secondary Ethereum Event Forwarder")
   175  		}
   176  		e.Stop()
   177  	}
   178  
   179  	if e.log.IsDebug() {
   180  		e.log.Debug("Setting up EVM Event Forwarder")
   181  	}
   182  
   183  	ethLogger := e.log.Named(ethereumLogger)
   184  	ethLogger.SetLevel(config.Level.Get())
   185  
   186  	filterer, err := ethereum.NewLogFilterer(
   187  		e.cfg,
   188  		ethLogger,
   189  		client,
   190  		ethCfg.CollateralBridge(),
   191  		types.EthereumContract{},
   192  		types.EthereumContract{},
   193  		ethCfg.MultiSigControl(),
   194  		assets,
   195  		ethCfg.ChainID(),
   196  	)
   197  	if err != nil {
   198  		return fmt.Errorf("couldn't create the log filterer: %w", err)
   199  	}
   200  
   201  	e.ethEngine = ethereum.NewEngine(
   202  		e.cfg,
   203  		ethLogger,
   204  		filterer,
   205  		forwarder,
   206  		types.EthereumContract{},
   207  		types.EthereumContract{},
   208  		ethCfg.MultiSigControl(),
   209  		ethCfg.CollateralBridge(),
   210  		ethCfg.ChainID(),
   211  		ethCfg.BlockTime(),
   212  	)
   213  
   214  	e.UpdateCollateralStartingBlock(filterer.CurrentHeight(context.Background()))
   215  
   216  	if e.multisigControlStartingBlock != 0 {
   217  		e.ethEngine.UpdateMultiSigControlStartingBlock(e.multisigControlStartingBlock)
   218  	}
   219  	if e.stakingStartingBlock != 0 {
   220  		e.ethEngine.UpdateStakingStartingBlock(e.stakingStartingBlock)
   221  	}
   222  
   223  	if err := filterer.VerifyClient(context.Background()); err != nil {
   224  		return err
   225  	}
   226  
   227  	e.Start()
   228  
   229  	return nil
   230  }
   231  
   232  func (e *Engine) Start() {
   233  	if e.ethEngine != nil {
   234  		go func() {
   235  			e.log.Info("Starting the Ethereum Event Forwarder")
   236  			e.ethEngine.Start()
   237  		}()
   238  	}
   239  }
   240  
   241  func (e *Engine) Stop() {
   242  	if e.ethEngine != nil {
   243  		e.log.Info("Stopping the Ethereum Event Forwarder")
   244  		e.ethEngine.Stop()
   245  	}
   246  	e.log.Info("The Event Forwarder engine stopped")
   247  }
   248  
   249  // NoopEngine can be use as a stub for the Engine. It does nothing.
   250  type NoopEngine struct {
   251  	log *logging.Logger
   252  }
   253  
   254  func NewNoopEngine(log *logging.Logger, config ethereum.Config) *NoopEngine {
   255  	topEngineLogger := log.Named(topEngineLogger)
   256  	topEngineLogger.SetLevel(config.Level.Get())
   257  
   258  	return &NoopEngine{
   259  		log: topEngineLogger,
   260  	}
   261  }
   262  
   263  func (e *NoopEngine) ReloadConf(_ ethereum.Config) {
   264  	if e.log.IsDebug() {
   265  		e.log.Debug("Reloading Ethereum configuration is a no-op")
   266  	}
   267  }
   268  
   269  func (e *NoopEngine) UpdateCollateralStartingBlock(b uint64) {}
   270  
   271  func (e *NoopEngine) UpdateStakingStartingBlock(b uint64) {}
   272  
   273  func (e *NoopEngine) UpdateMultisigControlStartingBlock(b uint64) {}
   274  
   275  func (e *NoopEngine) VerifyHeartbeat(_ context.Context, _ uint64, _ string, _ string, _ uint64) error {
   276  	return nil
   277  }
   278  
   279  func (e *NoopEngine) UpdateStartingBlock(_ string, _ uint64) {}
   280  
   281  func (e *NoopEngine) SetupEthereumEngine(
   282  	_ ethereum.Client,
   283  	_ ethereum.Forwarder,
   284  	_ ethereum.Config,
   285  	_ *types.EthereumConfig,
   286  	_ ethereum.Assets,
   287  ) error {
   288  	if e.log.IsDebug() {
   289  		e.log.Debug("Starting Ethereum configuration is a no-op")
   290  	}
   291  
   292  	return nil
   293  }
   294  
   295  func (e *NoopEngine) SetupSecondaryEthereumEngine(
   296  	_ ethereum.Client,
   297  	_ ethereum.Forwarder,
   298  	_ ethereum.Config,
   299  	_ *types.EVMChainConfig,
   300  	_ ethereum.Assets,
   301  ) error {
   302  	if e.log.IsDebug() {
   303  		e.log.Debug("Starting secondary Ethereum configuration is a no-op")
   304  	}
   305  
   306  	return nil
   307  }
   308  
   309  func (e *NoopEngine) Start() {
   310  	if e.log.IsDebug() {
   311  		e.log.Debug("Starting Ethereum configuration is a no-op")
   312  	}
   313  }
   314  
   315  func (e *NoopEngine) Stop() {
   316  	if e.log.IsDebug() {
   317  		e.log.Debug("Stopping Ethereum configuration is a no-op")
   318  	}
   319  }