github.com/ethereum-optimism/optimism/l2geth@v0.0.0-20230612200230-50b04ade19e3/rollup/sync_service.go (about)

     1  package rollup
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"math/big"
     8  	"strconv"
     9  	"sync"
    10  	"sync/atomic"
    11  	"time"
    12  
    13  	"github.com/ethereum-optimism/optimism/l2geth/common"
    14  	"github.com/ethereum-optimism/optimism/l2geth/core"
    15  	"github.com/ethereum-optimism/optimism/l2geth/core/state"
    16  	"github.com/ethereum-optimism/optimism/l2geth/ethdb"
    17  	"github.com/ethereum-optimism/optimism/l2geth/event"
    18  	"github.com/ethereum-optimism/optimism/l2geth/log"
    19  
    20  	"github.com/ethereum-optimism/optimism/l2geth/core/rawdb"
    21  	"github.com/ethereum-optimism/optimism/l2geth/core/types"
    22  
    23  	"github.com/ethereum-optimism/optimism/l2geth/eth/gasprice"
    24  	"github.com/ethereum-optimism/optimism/l2geth/rollup/fees"
    25  	"github.com/ethereum-optimism/optimism/l2geth/rollup/rcfg"
    26  )
    27  
    28  var (
    29  	// errBadConfig is the error when the SyncService is started with invalid
    30  	// configuration options
    31  	errBadConfig = errors.New("bad config")
    32  	// errShortRemoteTip is an error for when the remote tip is shorter than the
    33  	// local tip
    34  	errShortRemoteTip = errors.New("unexpected remote less than tip")
    35  	// errZeroGasPriceTx is the error for when a user submits a transaction
    36  	// with gas price zero and fees are currently enforced
    37  	errZeroGasPriceTx = errors.New("cannot accept 0 gas price transaction")
    38  	float1            = big.NewFloat(1)
    39  )
    40  
    41  // SyncService implements the main functionality around pulling in transactions
    42  // and executing them. It can be configured to run in both sequencer mode and in
    43  // verifier mode.
    44  type SyncService struct {
    45  	ctx                            context.Context
    46  	cancel                         context.CancelFunc
    47  	verifier                       bool
    48  	db                             ethdb.Database
    49  	scope                          event.SubscriptionScope
    50  	txFeed                         event.Feed
    51  	txLock                         sync.Mutex
    52  	loopLock                       sync.Mutex
    53  	enable                         bool
    54  	bc                             *core.BlockChain
    55  	txpool                         *core.TxPool
    56  	RollupGpo                      *gasprice.RollupOracle
    57  	client                         RollupClient
    58  	syncing                        atomic.Value
    59  	chainHeadSub                   event.Subscription
    60  	OVMContext                     OVMContext
    61  	pollInterval                   time.Duration
    62  	timestampRefreshThreshold      time.Duration
    63  	chainHeadCh                    chan core.ChainHeadEvent
    64  	backend                        Backend
    65  	gasPriceOracleOwnerAddress     common.Address
    66  	gasPriceOracleOwnerAddressLock *sync.RWMutex
    67  	enforceFees                    bool
    68  	signer                         types.Signer
    69  	feeThresholdUp                 *big.Float
    70  	feeThresholdDown               *big.Float
    71  }
    72  
    73  // NewSyncService returns an initialized sync service
    74  func NewSyncService(ctx context.Context, cfg Config, txpool *core.TxPool, bc *core.BlockChain, db ethdb.Database) (*SyncService, error) {
    75  	if bc == nil {
    76  		return nil, errors.New("Must pass BlockChain to SyncService")
    77  	}
    78  
    79  	ctx, cancel := context.WithCancel(ctx)
    80  	_ = cancel // satisfy govet
    81  
    82  	if cfg.IsVerifier {
    83  		log.Info("Running in verifier mode", "sync-backend", cfg.Backend.String())
    84  	} else {
    85  		log.Info("Running in sequencer mode", "sync-backend", cfg.Backend.String())
    86  		log.Info("Fees", "threshold-up", cfg.FeeThresholdUp, "threshold-down", cfg.FeeThresholdDown)
    87  		log.Info("Enforce Fees", "set", cfg.EnforceFees)
    88  	}
    89  
    90  	pollInterval := cfg.PollInterval
    91  	if pollInterval == 0 {
    92  		log.Info("Sanitizing poll interval to 15 seconds")
    93  		pollInterval = time.Second * 15
    94  	}
    95  	timestampRefreshThreshold := cfg.TimestampRefreshThreshold
    96  	if timestampRefreshThreshold == 0 {
    97  		log.Info("Sanitizing timestamp refresh threshold to 3 minutes")
    98  		timestampRefreshThreshold = time.Minute * 3
    99  	}
   100  
   101  	// Layer 2 chainid
   102  	chainID := bc.Config().ChainID
   103  	if chainID == nil {
   104  		return nil, errors.New("Must configure with chain id")
   105  	}
   106  	// Initialize the rollup client
   107  	client := NewClient(cfg.RollupClientHttp, chainID)
   108  	log.Info("Configured rollup client", "url", cfg.RollupClientHttp, "chain-id", chainID.Uint64(), "ctc-deploy-height", cfg.CanonicalTransactionChainDeployHeight)
   109  
   110  	// Ensure sane values for the fee thresholds
   111  	if cfg.FeeThresholdDown != nil {
   112  		// The fee threshold down should be less than 1
   113  		if cfg.FeeThresholdDown.Cmp(float1) != -1 {
   114  			return nil, fmt.Errorf("%w: fee threshold down not lower than 1: %f", errBadConfig,
   115  				cfg.FeeThresholdDown)
   116  		}
   117  	}
   118  	if cfg.FeeThresholdUp != nil {
   119  		// The fee threshold up should be greater than 1
   120  		if cfg.FeeThresholdUp.Cmp(float1) != 1 {
   121  			return nil, fmt.Errorf("%w: fee threshold up not larger than 1: %f", errBadConfig,
   122  				cfg.FeeThresholdUp)
   123  		}
   124  	}
   125  
   126  	service := SyncService{
   127  		ctx:                            ctx,
   128  		cancel:                         cancel,
   129  		verifier:                       cfg.IsVerifier,
   130  		enable:                         cfg.Eth1SyncServiceEnable,
   131  		syncing:                        atomic.Value{},
   132  		bc:                             bc,
   133  		txpool:                         txpool,
   134  		chainHeadCh:                    make(chan core.ChainHeadEvent, 1),
   135  		client:                         client,
   136  		db:                             db,
   137  		pollInterval:                   pollInterval,
   138  		timestampRefreshThreshold:      timestampRefreshThreshold,
   139  		backend:                        cfg.Backend,
   140  		gasPriceOracleOwnerAddress:     cfg.GasPriceOracleOwnerAddress,
   141  		gasPriceOracleOwnerAddressLock: new(sync.RWMutex),
   142  		enforceFees:                    cfg.EnforceFees,
   143  		signer:                         types.NewEIP155Signer(chainID),
   144  		feeThresholdDown:               cfg.FeeThresholdDown,
   145  		feeThresholdUp:                 cfg.FeeThresholdUp,
   146  	}
   147  
   148  	// The chainHeadSub is used to synchronize the SyncService with the chain.
   149  	// As the SyncService processes transactions, it waits until the transaction
   150  	// is added to the chain. This synchronization is required for handling
   151  	// reorgs and also favors safety over liveliness. If a transaction breaks
   152  	// things downstream, it is expected that this channel will halt ingestion
   153  	// of additional transactions by the SyncService.
   154  	service.chainHeadSub = service.bc.SubscribeChainHeadEvent(service.chainHeadCh)
   155  
   156  	// Initial sync service setup if it is enabled. This code depends on
   157  	// a remote server that indexes the layer one contracts. Place this
   158  	// code behind this if statement so that this can run without the
   159  	// requirement of the remote server being up.
   160  	if service.enable {
   161  		// Ensure that the rollup client can connect to a remote server
   162  		// before starting. Retry until it can connect.
   163  		tEnsure := time.NewTicker(10 * time.Second)
   164  		for ; true; <-tEnsure.C {
   165  			err := service.ensureClient()
   166  			if err != nil {
   167  				log.Info("Cannot connect to upstream service", "msg", err)
   168  			} else {
   169  				log.Info("Connected to upstream service")
   170  				tEnsure.Stop()
   171  				break
   172  			}
   173  		}
   174  
   175  		if !cfg.IsVerifier || cfg.Backend == BackendL2 {
   176  			// Wait until the remote service is done syncing
   177  			tStatus := time.NewTicker(10 * time.Second)
   178  			for ; true; <-tStatus.C {
   179  				status, err := service.client.SyncStatus(service.backend)
   180  				if err != nil {
   181  					log.Error("Cannot get sync status")
   182  					continue
   183  				}
   184  				if !status.Syncing {
   185  					tStatus.Stop()
   186  					break
   187  				}
   188  				log.Info("Still syncing", "index", status.CurrentTransactionIndex, "tip", status.HighestKnownTransactionIndex)
   189  			}
   190  		}
   191  
   192  		// Initialize the latest L1 data here to make sure that
   193  		// it happens before the RPC endpoints open up
   194  		// Only do it if the sync service is enabled so that this
   195  		// can be ran without needing to have a configured RollupClient.
   196  		err := service.initializeLatestL1(cfg.CanonicalTransactionChainDeployHeight)
   197  		if err != nil {
   198  			return nil, fmt.Errorf("Cannot initialize latest L1 data: %w", err)
   199  		}
   200  
   201  		// Log the OVMContext information on startup
   202  		bn := service.GetLatestL1BlockNumber()
   203  		ts := service.GetLatestL1Timestamp()
   204  		log.Info("Initialized Latest L1 Info", "blocknumber", bn, "timestamp", ts)
   205  
   206  		index := service.GetLatestIndex()
   207  		queueIndex := service.GetLatestEnqueueIndex()
   208  		verifiedIndex := service.GetLatestVerifiedIndex()
   209  		block := service.bc.CurrentBlock()
   210  		if block == nil {
   211  			block = types.NewBlock(&types.Header{}, nil, nil, nil)
   212  		}
   213  		header := block.Header()
   214  		log.Info("Initial Rollup State", "state", header.Root.Hex(), "index", stringify(index), "queue-index", stringify(queueIndex), "verified-index", verifiedIndex)
   215  
   216  		// The sequencer needs to sync to the tip at start up
   217  		// By setting the sync status to true, it will prevent RPC calls.
   218  		// Be sure this is set to false later.
   219  		if !service.verifier {
   220  			service.setSyncStatus(true)
   221  		}
   222  	}
   223  	return &service, nil
   224  }
   225  
   226  // ensureClient checks to make sure that the remote transaction source is
   227  // available. It will return an error if it cannot connect via HTTP
   228  func (s *SyncService) ensureClient() error {
   229  	_, err := s.client.GetLatestEthContext()
   230  	if err != nil {
   231  		return fmt.Errorf("Cannot connect to data service: %w", err)
   232  	}
   233  	return nil
   234  }
   235  
   236  // Start initializes the service
   237  func (s *SyncService) Start() error {
   238  	if !s.enable {
   239  		log.Info("Running without syncing enabled")
   240  		return nil
   241  	}
   242  	log.Info("Initializing Sync Service")
   243  	if err := s.updateGasPriceOracleCache(nil); err != nil {
   244  		return err
   245  	}
   246  
   247  	if s.verifier {
   248  		go s.VerifierLoop()
   249  	} else {
   250  		go func() {
   251  			if err := s.syncTransactionsToTip(); err != nil {
   252  				log.Crit("Sequencer cannot sync transactions to tip", "err", err)
   253  			}
   254  			if err := s.syncQueueToTip(); err != nil {
   255  				log.Crit("Sequencer cannot sync queue to tip", "err", err)
   256  			}
   257  			s.setSyncStatus(false)
   258  			go s.SequencerLoop()
   259  		}()
   260  	}
   261  	return nil
   262  }
   263  
   264  // initializeLatestL1 sets the initial values of the `L1BlockNumber`
   265  // and `L1Timestamp` to the deploy height of the Canonical Transaction
   266  // chain if the chain is empty, otherwise set it from the last
   267  // transaction processed. This must complete before transactions
   268  // are accepted via RPC when running as a sequencer.
   269  func (s *SyncService) initializeLatestL1(ctcDeployHeight *big.Int) error {
   270  	index := s.GetLatestIndex()
   271  	if index == nil {
   272  		if ctcDeployHeight == nil {
   273  			return errors.New("Must configure with canonical transaction chain deploy height")
   274  		}
   275  		log.Info("Initializing initial OVM Context", "ctc-deploy-height", ctcDeployHeight.Uint64())
   276  		context, err := s.client.GetEthContext(ctcDeployHeight.Uint64())
   277  		if err != nil {
   278  			return fmt.Errorf("Cannot fetch ctc deploy block at height %d: %w", ctcDeployHeight.Uint64(), err)
   279  		}
   280  		s.SetLatestL1Timestamp(context.Timestamp)
   281  		s.SetLatestL1BlockNumber(context.BlockNumber)
   282  	} else {
   283  		// Recover from accidentally skipped batches if necessary.
   284  		if s.verifier && s.backend == BackendL1 {
   285  			tx, err := s.client.GetRawTransaction(*index, s.backend)
   286  			if err != nil {
   287  				return fmt.Errorf("Cannot fetch transaction from dtl at index %d: %w", *index, err)
   288  			}
   289  
   290  			oldbatchIndex := s.GetLatestBatchIndex()
   291  			newBatchIndex := tx.Transaction.BatchIndex
   292  			if tx.Transaction.BatchIndex > 0 {
   293  				newBatchIndex -= 1
   294  			}
   295  
   296  			log.Info("Updating batch index", "old", oldbatchIndex, "new", newBatchIndex)
   297  			s.SetLatestBatchIndex(&newBatchIndex)
   298  		}
   299  
   300  		log.Info("Found latest index", "index", *index)
   301  		block := s.bc.GetBlockByNumber(*index + 1)
   302  		if block == nil {
   303  			block = s.bc.CurrentBlock()
   304  			blockNum := block.Number().Uint64()
   305  			if blockNum > *index {
   306  				// This is recoverable with a reorg but should never happen
   307  				return fmt.Errorf("Current block height greater than index")
   308  			}
   309  			var idx *uint64
   310  			if blockNum > 0 {
   311  				num := blockNum - 1
   312  				idx = &num
   313  			}
   314  			s.SetLatestIndex(idx)
   315  			log.Info("Block not found, resetting index", "new", stringify(idx), "old", *index)
   316  		}
   317  		txs := block.Transactions()
   318  		if len(txs) != 1 {
   319  			log.Error("Unexpected number of transactions in block", "count", len(txs))
   320  			panic("Cannot recover OVM Context")
   321  		}
   322  		tx := txs[0]
   323  		s.SetLatestL1Timestamp(tx.L1Timestamp())
   324  		s.SetLatestL1BlockNumber(tx.L1BlockNumber().Uint64())
   325  	}
   326  	queueIndex := s.GetLatestEnqueueIndex()
   327  	if queueIndex == nil {
   328  		enqueue, err := s.client.GetLastConfirmedEnqueue()
   329  		// There are no enqueues yet
   330  		if errors.Is(err, errElementNotFound) {
   331  			return nil
   332  		}
   333  		// Other unexpected error
   334  		if err != nil {
   335  			return fmt.Errorf("Cannot fetch last confirmed queue tx: %w", err)
   336  		}
   337  		// No error, the queue element was found
   338  		queueIndex = enqueue.GetMeta().QueueIndex
   339  	} else {
   340  		log.Info("Found latest queue index", "queue-index", *queueIndex)
   341  		// The queue index is defined. Work backwards from the tip
   342  		// to make sure that the indexed queue index is the latest
   343  		// enqueued transaction
   344  		block := s.bc.CurrentBlock()
   345  		for {
   346  			// There are no blocks in the chain
   347  			// This should never happen
   348  			if block == nil {
   349  				log.Warn("Found no genesis block when fixing queue index")
   350  				break
   351  			}
   352  			num := block.Number().Uint64()
   353  			// Handle the genesis block
   354  			if num == 0 {
   355  				log.Info("Hit genesis block when fixing queue index")
   356  				queueIndex = nil
   357  				break
   358  			}
   359  			txs := block.Transactions()
   360  			// This should never happen
   361  			if len(txs) != 1 {
   362  				log.Warn("Found block with unexpected number of txs", "count", len(txs), "height", num)
   363  				break
   364  			}
   365  			tx := txs[0]
   366  			qi := tx.GetMeta().QueueIndex
   367  			// When the queue index is set
   368  			if qi != nil {
   369  				if *qi == *queueIndex {
   370  					log.Info("Found correct staring queue index", "queue-index", *qi)
   371  				} else {
   372  					log.Info("Found incorrect staring queue index, fixing", "old", *queueIndex, "new", *qi)
   373  					queueIndex = qi
   374  				}
   375  				break
   376  			}
   377  			block = s.bc.GetBlockByNumber(num - 1)
   378  		}
   379  	}
   380  	s.SetLatestEnqueueIndex(queueIndex)
   381  	return nil
   382  }
   383  
   384  // setSyncStatus sets the `syncing` field as well as prevents
   385  // any transactions from coming in via RPC.
   386  // `syncing` should never be set directly outside of this function.
   387  func (s *SyncService) setSyncStatus(status bool) {
   388  	log.Info("Setting sync status", "status", status)
   389  	s.syncing.Store(status)
   390  }
   391  
   392  // IsSyncing returns the syncing status of the syncservice.
   393  // Returns false if not yet set.
   394  func (s *SyncService) IsSyncing() bool {
   395  	value := s.syncing.Load()
   396  	val, ok := value.(bool)
   397  	if !ok {
   398  		return false
   399  	}
   400  	return val
   401  }
   402  
   403  // Stop will close the open channels and cancel the goroutines
   404  // started by this service.
   405  func (s *SyncService) Stop() error {
   406  	log.Info("Stopping sync service")
   407  	s.scope.Close()
   408  	s.chainHeadSub.Unsubscribe()
   409  	close(s.chainHeadCh)
   410  
   411  	if s.cancel != nil {
   412  		defer s.cancel()
   413  	}
   414  	return nil
   415  }
   416  
   417  // VerifierLoop is the main loop for Verifier mode
   418  func (s *SyncService) VerifierLoop() {
   419  	log.Info("Starting Verifier Loop", "poll-interval", s.pollInterval, "timestamp-refresh-threshold", s.timestampRefreshThreshold)
   420  	t := time.NewTicker(s.pollInterval)
   421  	defer t.Stop()
   422  
   423  	for {
   424  		select {
   425  		case <-t.C:
   426  			if err := s.verify(); err != nil {
   427  				log.Error("Could not verify", "error", err)
   428  			}
   429  		case <-s.ctx.Done():
   430  			return
   431  		}
   432  	}
   433  }
   434  
   435  // verify is the main logic for the Verifier. The verifier logic is different
   436  // depending on the Backend
   437  func (s *SyncService) verify() error {
   438  	switch s.backend {
   439  	case BackendL1:
   440  		if err := s.syncBatchesToTip(); err != nil {
   441  			return fmt.Errorf("Verifier cannot sync transaction batches to tip: %w", err)
   442  		}
   443  	case BackendL2:
   444  		if err := s.syncTransactionsToTip(); err != nil {
   445  			return fmt.Errorf("Verifier cannot sync transactions with BackendL2: %w", err)
   446  		}
   447  	}
   448  	return nil
   449  }
   450  
   451  // SequencerLoop is the polling loop that runs in sequencer mode. It sequences
   452  // transactions and then updates the EthContext.
   453  func (s *SyncService) SequencerLoop() {
   454  	log.Info("Starting Sequencer Loop", "poll-interval", s.pollInterval, "timestamp-refresh-threshold", s.timestampRefreshThreshold)
   455  	t := time.NewTicker(s.pollInterval)
   456  	defer t.Stop()
   457  	for ; true; <-t.C {
   458  		s.txLock.Lock()
   459  		if err := s.sequence(); err != nil {
   460  			log.Error("Could not sequence", "error", err)
   461  		}
   462  		s.txLock.Unlock()
   463  
   464  		if err := s.updateL1BlockNumber(); err != nil {
   465  			log.Error("Could not update execution context", "error", err)
   466  		}
   467  	}
   468  }
   469  
   470  // sequence is the main logic for the Sequencer. It will sync any `enqueue`
   471  // transactions it has yet to sync and then pull in transaction batches to
   472  // compare against the transactions it has in its local state. The sequencer
   473  // should reorg based on the transaction batches that are posted because
   474  // L1 is the source of truth. The sequencer concurrently accepts user
   475  // transactions via the RPC. When reorg logic is enabled, this should
   476  // also call `syncBatchesToTip`
   477  func (s *SyncService) sequence() error {
   478  	if err := s.syncQueueToTip(); err != nil {
   479  		return fmt.Errorf("Sequencer cannot sequence queue: %w", err)
   480  	}
   481  	return nil
   482  }
   483  
   484  func (s *SyncService) syncQueueToTip() error {
   485  	if err := s.syncToTip(s.syncQueue, s.client.GetLatestEnqueueIndex); err != nil {
   486  		return fmt.Errorf("Cannot sync queue to tip: %w", err)
   487  	}
   488  	return nil
   489  }
   490  
   491  func (s *SyncService) syncBatchesToTip() error {
   492  	if err := s.syncToTip(s.syncBatches, s.client.GetLatestTransactionBatchIndex); err != nil {
   493  		return fmt.Errorf("Cannot sync transaction batches to tip: %w", err)
   494  	}
   495  	return nil
   496  }
   497  
   498  func (s *SyncService) syncTransactionsToTip() error {
   499  	sync := func() (*uint64, error) {
   500  		return s.syncTransactions(s.backend)
   501  	}
   502  	check := func() (*uint64, error) {
   503  		return s.client.GetLatestTransactionIndex(s.backend)
   504  	}
   505  	if err := s.syncToTip(sync, check); err != nil {
   506  		return fmt.Errorf("Verifier cannot sync transactions with backend %s: %w", s.backend.String(), err)
   507  	}
   508  	return nil
   509  }
   510  
   511  // updateL1GasPrice queries for the current L1 gas price and then stores it
   512  // in the L1 Gas Price Oracle. This must be called over time to properly
   513  // estimate the transaction fees that the sequencer should charge.
   514  func (s *SyncService) updateL1GasPrice(statedb *state.StateDB) error {
   515  	value, err := s.readGPOStorageSlot(statedb, rcfg.L1GasPriceSlot)
   516  	if err != nil {
   517  		return err
   518  	}
   519  	return s.RollupGpo.SetL1GasPrice(value)
   520  }
   521  
   522  // updateL2GasPrice accepts a state db and reads the gas price from the gas
   523  // price oracle at the state that corresponds to the state db. If no state db
   524  // is passed in, then the tip is used.
   525  func (s *SyncService) updateL2GasPrice(statedb *state.StateDB) error {
   526  	value, err := s.readGPOStorageSlot(statedb, rcfg.L2GasPriceSlot)
   527  	if err != nil {
   528  		return err
   529  	}
   530  	return s.RollupGpo.SetL2GasPrice(value)
   531  }
   532  
   533  // updateOverhead will update the overhead value from the OVM_GasPriceOracle
   534  // in the local cache
   535  func (s *SyncService) updateOverhead(statedb *state.StateDB) error {
   536  	value, err := s.readGPOStorageSlot(statedb, rcfg.OverheadSlot)
   537  	if err != nil {
   538  		return err
   539  	}
   540  	return s.RollupGpo.SetOverhead(value)
   541  }
   542  
   543  // updateScalar will update the scalar value from the OVM_GasPriceOracle
   544  // in the local cache
   545  func (s *SyncService) updateScalar(statedb *state.StateDB) error {
   546  	scalar, err := s.readGPOStorageSlot(statedb, rcfg.ScalarSlot)
   547  	if err != nil {
   548  		return err
   549  	}
   550  	decimals, err := s.readGPOStorageSlot(statedb, rcfg.DecimalsSlot)
   551  	if err != nil {
   552  		return err
   553  	}
   554  	return s.RollupGpo.SetScalar(scalar, decimals)
   555  }
   556  
   557  // cacheGasPriceOracleOwner accepts a statedb and caches the gas price oracle
   558  // owner address locally
   559  func (s *SyncService) cacheGasPriceOracleOwner(statedb *state.StateDB) error {
   560  	s.gasPriceOracleOwnerAddressLock.Lock()
   561  	defer s.gasPriceOracleOwnerAddressLock.Unlock()
   562  
   563  	value, err := s.readGPOStorageSlot(statedb, rcfg.L2GasPriceOracleOwnerSlot)
   564  	if err != nil {
   565  		return err
   566  	}
   567  	s.gasPriceOracleOwnerAddress = common.BigToAddress(value)
   568  	return nil
   569  }
   570  
   571  // readGPOStorageSlot is a helper function for reading storage
   572  // slots from the OVM_GasPriceOracle
   573  func (s *SyncService) readGPOStorageSlot(statedb *state.StateDB, hash common.Hash) (*big.Int, error) {
   574  	var err error
   575  	if statedb == nil {
   576  		statedb, err = s.bc.State()
   577  		if err != nil {
   578  			return nil, err
   579  		}
   580  	}
   581  	result := statedb.GetState(rcfg.L2GasPriceOracleAddress, hash)
   582  	return result.Big(), nil
   583  }
   584  
   585  // updateGasPriceOracleCache caches the owner as well as updating the
   586  // the L2 gas price from the OVM_GasPriceOracle.
   587  // This should be sure to read all public variables from the
   588  // OVM_GasPriceOracle
   589  func (s *SyncService) updateGasPriceOracleCache(hash *common.Hash) error {
   590  	var statedb *state.StateDB
   591  	var err error
   592  	if hash != nil {
   593  		statedb, err = s.bc.StateAt(*hash)
   594  	} else {
   595  		statedb, err = s.bc.State()
   596  	}
   597  	if err != nil {
   598  		return err
   599  	}
   600  	if err := s.cacheGasPriceOracleOwner(statedb); err != nil {
   601  		return err
   602  	}
   603  	if err := s.updateL2GasPrice(statedb); err != nil {
   604  		return err
   605  	}
   606  	if err := s.updateL1GasPrice(statedb); err != nil {
   607  		return err
   608  	}
   609  	if err := s.updateOverhead(statedb); err != nil {
   610  		return err
   611  	}
   612  	if err := s.updateScalar(statedb); err != nil {
   613  		return err
   614  	}
   615  	return nil
   616  }
   617  
   618  // A thread safe getter for the gas price oracle owner address
   619  func (s *SyncService) GasPriceOracleOwnerAddress() *common.Address {
   620  	s.gasPriceOracleOwnerAddressLock.RLock()
   621  	defer s.gasPriceOracleOwnerAddressLock.RUnlock()
   622  	return &s.gasPriceOracleOwnerAddress
   623  }
   624  
   625  /// Update the execution context's timestamp and blocknumber
   626  /// over time. This is only necessary for the sequencer.
   627  func (s *SyncService) updateL1BlockNumber() error {
   628  	context, err := s.client.GetLatestEthContext()
   629  	if err != nil {
   630  		return fmt.Errorf("Cannot get eth context: %w", err)
   631  	}
   632  	latest := s.GetLatestL1BlockNumber()
   633  	if context.BlockNumber > latest {
   634  		log.Info("Updating L1 block number", "blocknumber", context.BlockNumber)
   635  		s.SetLatestL1BlockNumber(context.BlockNumber)
   636  	}
   637  	return nil
   638  }
   639  
   640  // Methods for safely accessing and storing the latest
   641  // L1 blocknumber and timestamp. These are held in memory.
   642  
   643  // GetLatestL1Timestamp returns the OVMContext timestamp
   644  func (s *SyncService) GetLatestL1Timestamp() uint64 {
   645  	return atomic.LoadUint64(&s.OVMContext.timestamp)
   646  }
   647  
   648  // GetLatestL1BlockNumber returns the OVMContext blocknumber
   649  func (s *SyncService) GetLatestL1BlockNumber() uint64 {
   650  	return atomic.LoadUint64(&s.OVMContext.blockNumber)
   651  }
   652  
   653  // SetLatestL1Timestamp will set the OVMContext timestamp
   654  func (s *SyncService) SetLatestL1Timestamp(ts uint64) {
   655  	atomic.StoreUint64(&s.OVMContext.timestamp, ts)
   656  }
   657  
   658  // SetLatestL1BlockNumber will set the OVMContext blocknumber
   659  func (s *SyncService) SetLatestL1BlockNumber(bn uint64) {
   660  	atomic.StoreUint64(&s.OVMContext.blockNumber, bn)
   661  }
   662  
   663  // GetLatestEnqueueIndex reads the last queue index processed
   664  func (s *SyncService) GetLatestEnqueueIndex() *uint64 {
   665  	return rawdb.ReadHeadQueueIndex(s.db)
   666  }
   667  
   668  // GetNextEnqueueIndex returns the next queue index to process
   669  func (s *SyncService) GetNextEnqueueIndex() uint64 {
   670  	latest := s.GetLatestEnqueueIndex()
   671  	if latest == nil {
   672  		return 0
   673  	}
   674  	return *latest + 1
   675  }
   676  
   677  // SetLatestEnqueueIndex writes the last queue index that was processed
   678  func (s *SyncService) SetLatestEnqueueIndex(index *uint64) {
   679  	if index != nil {
   680  		rawdb.WriteHeadQueueIndex(s.db, *index)
   681  	}
   682  }
   683  
   684  // GetLatestIndex reads the last CTC index that was processed
   685  func (s *SyncService) GetLatestIndex() *uint64 {
   686  	return rawdb.ReadHeadIndex(s.db)
   687  }
   688  
   689  // GetNextIndex reads the next CTC index to process
   690  func (s *SyncService) GetNextIndex() uint64 {
   691  	latest := s.GetLatestIndex()
   692  	if latest == nil {
   693  		return 0
   694  	}
   695  	return *latest + 1
   696  }
   697  
   698  // SetLatestIndex writes the last CTC index that was processed
   699  func (s *SyncService) SetLatestIndex(index *uint64) {
   700  	if index != nil {
   701  		rawdb.WriteHeadIndex(s.db, *index)
   702  	}
   703  }
   704  
   705  // GetLatestVerifiedIndex reads the last verified CTC index that was processed
   706  // These are set by processing batches of transactions that were submitted to
   707  // the Canonical Transaction Chain.
   708  func (s *SyncService) GetLatestVerifiedIndex() *uint64 {
   709  	return rawdb.ReadHeadVerifiedIndex(s.db)
   710  }
   711  
   712  // GetNextVerifiedIndex reads the next verified index
   713  func (s *SyncService) GetNextVerifiedIndex() uint64 {
   714  	index := s.GetLatestVerifiedIndex()
   715  	if index == nil {
   716  		return 0
   717  	}
   718  	return *index + 1
   719  }
   720  
   721  // SetLatestVerifiedIndex writes the last verified index that was processed
   722  func (s *SyncService) SetLatestVerifiedIndex(index *uint64) {
   723  	if index != nil {
   724  		rawdb.WriteHeadVerifiedIndex(s.db, *index)
   725  	}
   726  }
   727  
   728  // GetLatestBatchIndex reads the last processed transaction batch
   729  func (s *SyncService) GetLatestBatchIndex() *uint64 {
   730  	return rawdb.ReadHeadBatchIndex(s.db)
   731  }
   732  
   733  // GetNextBatchIndex reads the index of the next transaction batch to process
   734  func (s *SyncService) GetNextBatchIndex() uint64 {
   735  	index := s.GetLatestBatchIndex()
   736  	if index == nil {
   737  		return 0
   738  	}
   739  	return *index + 1
   740  }
   741  
   742  // SetLatestBatchIndex writes the last index of the transaction batch that was processed
   743  func (s *SyncService) SetLatestBatchIndex(index *uint64) {
   744  	if index != nil {
   745  		rawdb.WriteHeadBatchIndex(s.db, *index)
   746  	}
   747  }
   748  
   749  // applyTransaction is a higher level API for applying a transaction
   750  func (s *SyncService) applyTransaction(tx *types.Transaction) error {
   751  	if tx.GetMeta().Index != nil {
   752  		return s.applyIndexedTransaction(tx)
   753  	}
   754  	return s.applyTransactionToTip(tx)
   755  }
   756  
   757  // applyIndexedTransaction applys a transaction that has an index. This means
   758  // that the source of the transaction was either a L1 batch or from the
   759  // sequencer.
   760  func (s *SyncService) applyIndexedTransaction(tx *types.Transaction) error {
   761  	if tx == nil {
   762  		return errors.New("Transaction is nil in applyIndexedTransaction")
   763  	}
   764  	index := tx.GetMeta().Index
   765  	if index == nil {
   766  		return errors.New("No index found in applyIndexedTransaction")
   767  	}
   768  	log.Trace("Applying indexed transaction", "index", *index)
   769  	next := s.GetNextIndex()
   770  	if *index == next {
   771  		return s.applyTransactionToTip(tx)
   772  	}
   773  	if *index < next {
   774  		return s.applyHistoricalTransaction(tx)
   775  	}
   776  	return fmt.Errorf("Received tx at index %d when looking for %d", *index, next)
   777  }
   778  
   779  // applyHistoricalTransaction will compare a historical transaction against what
   780  // is locally indexed. This will trigger a reorg in the future
   781  func (s *SyncService) applyHistoricalTransaction(tx *types.Transaction) error {
   782  	if tx == nil {
   783  		return errors.New("Transaction is nil in applyHistoricalTransaction")
   784  	}
   785  	index := tx.GetMeta().Index
   786  	if index == nil {
   787  		return errors.New("No index is found in applyHistoricalTransaction")
   788  	}
   789  	// Handle the off by one
   790  	block := s.bc.GetBlockByNumber(*index + 1)
   791  	if block == nil {
   792  		return fmt.Errorf("Block %d is not found", *index+1)
   793  	}
   794  	txs := block.Transactions()
   795  	if len(txs) != 1 {
   796  		return fmt.Errorf("More than one transaction found in block %d", *index+1)
   797  	}
   798  	if !isCtcTxEqual(tx, txs[0]) {
   799  		log.Error("Mismatched transaction", "index", *index)
   800  	} else {
   801  		log.Debug("Historical transaction matches", "index", *index, "hash", tx.Hash().Hex())
   802  	}
   803  	return nil
   804  }
   805  
   806  // applyTransactionToTip will do sanity checks on the transaction before
   807  // applying it to the tip. It blocks until the transaction has been included in
   808  // the chain. It is assumed that validation around the index has already
   809  // happened.
   810  func (s *SyncService) applyTransactionToTip(tx *types.Transaction) error {
   811  	if tx == nil {
   812  		return errors.New("nil transaction passed to applyTransactionToTip")
   813  	}
   814  	// Queue Origin L1 to L2 transactions must have a timestamp that is set by
   815  	// the L1 block that holds the transaction. This should never happen but is
   816  	// a sanity check to prevent fraudulent execution.
   817  	// No need to unlock here as the lock is only taken when its a queue origin
   818  	// sequencer transaction.
   819  	if tx.QueueOrigin() == types.QueueOriginL1ToL2 {
   820  		if tx.L1Timestamp() == 0 {
   821  			return fmt.Errorf("Queue origin L1 to L2 transaction without a timestamp: %s", tx.Hash().Hex())
   822  		}
   823  	}
   824  
   825  	// If there is no L1 timestamp assigned to the transaction, then assign a
   826  	// timestamp to it. The property that L1 to L2 transactions have the same
   827  	// timestamp as the L1 block that it was included in is removed for better
   828  	// UX. This functionality can be added back in during a future release. For
   829  	// now, the sequencer will assign a timestamp to each transaction.
   830  	ts := s.GetLatestL1Timestamp()
   831  	bn := s.GetLatestL1BlockNumber()
   832  
   833  	// The L1Timestamp is 0 for QueueOriginSequencer transactions when
   834  	// running as the sequencer, the transactions are coming in via RPC.
   835  	// This code path also runs for replicas/verifiers so any logic involving
   836  	// `time.Now` can only run for the sequencer. All other nodes must listen
   837  	// to what the sequencer says is the timestamp, otherwise there will be a
   838  	// network split.
   839  	// Note that it should never be possible for the timestamp to be set to
   840  	// 0 when running as a verifier.
   841  	shouldMalleateTimestamp := !s.verifier && tx.QueueOrigin() == types.QueueOriginL1ToL2
   842  	if tx.L1Timestamp() == 0 || shouldMalleateTimestamp {
   843  		// Get the latest known timestamp
   844  		current := time.Unix(int64(ts), 0)
   845  		// Get the current clocktime
   846  		now := time.Now()
   847  		// If enough time has passed, then assign the
   848  		// transaction to have the timestamp now. Otherwise,
   849  		// use the current timestamp
   850  		if now.Sub(current) > s.timestampRefreshThreshold {
   851  			current = now
   852  		}
   853  		log.Info("Updating latest timestamp", "timestamp", current, "unix", current.Unix())
   854  		tx.SetL1Timestamp(uint64(current.Unix()))
   855  	} else if tx.L1Timestamp() == 0 && s.verifier {
   856  		// This should never happen
   857  		log.Error("No tx timestamp found when running as verifier", "hash", tx.Hash().Hex())
   858  	} else if tx.L1Timestamp() < ts {
   859  		// This should never happen, but sometimes does
   860  		log.Error("Timestamp monotonicity violation", "hash", tx.Hash().Hex(), "latest", ts, "tx", tx.L1Timestamp())
   861  	}
   862  
   863  	l1BlockNumber := tx.L1BlockNumber()
   864  	// Set the L1 blocknumber
   865  	if l1BlockNumber == nil {
   866  		tx.SetL1BlockNumber(bn)
   867  	} else if l1BlockNumber.Uint64() > bn {
   868  		s.SetLatestL1BlockNumber(l1BlockNumber.Uint64())
   869  	} else if l1BlockNumber.Uint64() < bn {
   870  		// l1BlockNumber < latest l1BlockNumber
   871  		// indicates an error
   872  		log.Error("Blocknumber monotonicity violation", "hash", tx.Hash().Hex(),
   873  			"new", l1BlockNumber.Uint64(), "old", bn)
   874  	}
   875  
   876  	// Store the latest timestamp value
   877  	if tx.L1Timestamp() > ts {
   878  		s.SetLatestL1Timestamp(tx.L1Timestamp())
   879  	}
   880  
   881  	index := s.GetLatestIndex()
   882  	if tx.GetMeta().Index == nil {
   883  		if index == nil {
   884  			tx.SetIndex(0)
   885  		} else {
   886  			tx.SetIndex(*index + 1)
   887  		}
   888  	}
   889  
   890  	// On restart, these values are repaired to handle
   891  	// the case where the index is updated but the
   892  	// transaction isn't yet added to the chain
   893  	s.SetLatestIndex(tx.GetMeta().Index)
   894  	if queueIndex := tx.GetMeta().QueueIndex; queueIndex != nil {
   895  		s.SetLatestEnqueueIndex(queueIndex)
   896  	}
   897  
   898  	// The index was set above so it is safe to dereference
   899  	log.Debug("Applying transaction to tip", "index", *tx.GetMeta().Index, "hash", tx.Hash().Hex(), "origin", tx.QueueOrigin().String())
   900  
   901  	txs := types.Transactions{tx}
   902  	errCh := make(chan error, 1)
   903  	s.txFeed.Send(core.NewTxsEvent{
   904  		Txs:   txs,
   905  		ErrCh: errCh,
   906  	})
   907  	// Block until the transaction has been added to the chain
   908  	log.Trace("Waiting for transaction to be added to chain", "hash", tx.Hash().Hex())
   909  
   910  	select {
   911  	case err := <-errCh:
   912  		log.Error("Got error waiting for transaction to be added to chain", "msg", err)
   913  		s.SetLatestL1Timestamp(ts)
   914  		s.SetLatestL1BlockNumber(bn)
   915  		s.SetLatestIndex(index)
   916  		return err
   917  	case <-s.chainHeadCh:
   918  		// Update the cache when the transaction is from the owner
   919  		// of the gas price oracle
   920  		sender, _ := types.Sender(s.signer, tx)
   921  		owner := s.GasPriceOracleOwnerAddress()
   922  		if owner != nil && sender == *owner {
   923  			if err := s.updateGasPriceOracleCache(nil); err != nil {
   924  				s.SetLatestL1Timestamp(ts)
   925  				s.SetLatestL1BlockNumber(bn)
   926  				s.SetLatestIndex(index)
   927  				return err
   928  			}
   929  		}
   930  		return nil
   931  	}
   932  }
   933  
   934  // applyBatchedTransaction applies transactions that were batched to layer one.
   935  // The sequencer checks for batches over time to make sure that it does not
   936  // deviate from the L1 state and this is the main method of transaction
   937  // ingestion for the verifier.
   938  func (s *SyncService) applyBatchedTransaction(tx *types.Transaction) error {
   939  	if tx == nil {
   940  		return errors.New("nil transaction passed into applyBatchedTransaction")
   941  	}
   942  	index := tx.GetMeta().Index
   943  	if index == nil {
   944  		return errors.New("No index found on transaction")
   945  	}
   946  	log.Trace("Applying batched transaction", "index", *index)
   947  	err := s.applyIndexedTransaction(tx)
   948  	if err != nil {
   949  		return fmt.Errorf("Cannot apply batched transaction: %w", err)
   950  	}
   951  	s.SetLatestVerifiedIndex(index)
   952  	return nil
   953  }
   954  
   955  // verifyFee will verify that a valid fee is being paid.
   956  func (s *SyncService) verifyFee(tx *types.Transaction) error {
   957  	fee, err := fees.CalculateTotalFee(tx, s.RollupGpo)
   958  	if err != nil {
   959  		return fmt.Errorf("invalid transaction: %w", err)
   960  	}
   961  
   962  	// Prevent transactions without enough balance from
   963  	// being accepted by the chain but allow through 0
   964  	// gas price transactions
   965  	cost := tx.Value()
   966  	if tx.GasPrice().Cmp(common.Big0) != 0 {
   967  		cost = cost.Add(cost, fee)
   968  	}
   969  	state, err := s.bc.State()
   970  	if err != nil {
   971  		return err
   972  	}
   973  	from, err := types.Sender(s.signer, tx)
   974  	if err != nil {
   975  		return fmt.Errorf("invalid transaction: %w", core.ErrInvalidSender)
   976  	}
   977  	if state.GetBalance(from).Cmp(cost) < 0 {
   978  		return fmt.Errorf("invalid transaction: %w", core.ErrInsufficientFunds)
   979  	}
   980  
   981  	if tx.GasPrice().Cmp(common.Big0) == 0 {
   982  		// Allow 0 gas price transactions only if it is the owner of the gas
   983  		// price oracle
   984  		gpoOwner := s.GasPriceOracleOwnerAddress()
   985  		if gpoOwner != nil {
   986  			if from == *gpoOwner {
   987  				return nil
   988  			}
   989  		}
   990  		// Exit early if fees are enforced and the gasPrice is set to 0
   991  		if s.enforceFees {
   992  			return errZeroGasPriceTx
   993  		}
   994  		// If fees are not enforced and the gas price is 0, return early
   995  		return nil
   996  	}
   997  
   998  	// Ensure that the user L2 gas price is high enough
   999  	l2GasPrice, err := s.RollupGpo.SuggestL2GasPrice(context.Background())
  1000  	if err != nil {
  1001  		return err
  1002  	}
  1003  
  1004  	// Reject user transactions that do not have large enough of a gas price.
  1005  	// Allow for a buffer in case the gas price changes in between the user
  1006  	// calling `eth_gasPrice` and submitting the transaction.
  1007  	opts := fees.PaysEnoughOpts{
  1008  		UserGasPrice:     tx.GasPrice(),
  1009  		ExpectedGasPrice: l2GasPrice,
  1010  		ThresholdUp:      s.feeThresholdUp,
  1011  		ThresholdDown:    s.feeThresholdDown,
  1012  	}
  1013  
  1014  	// Check the error type and return the correct error message to the user
  1015  	if err := fees.PaysEnough(&opts); err != nil {
  1016  		if errors.Is(err, fees.ErrGasPriceTooLow) {
  1017  			return fmt.Errorf("%w: %d wei, use at least tx.gasPrice = %s wei",
  1018  				fees.ErrGasPriceTooLow, tx.GasPrice(), l2GasPrice)
  1019  		}
  1020  		if errors.Is(err, fees.ErrGasPriceTooHigh) {
  1021  			return fmt.Errorf("%w: %d wei, use at most tx.gasPrice = %s wei",
  1022  				fees.ErrGasPriceTooHigh, tx.GasPrice(), l2GasPrice)
  1023  		}
  1024  		return err
  1025  	}
  1026  	return nil
  1027  }
  1028  
  1029  // Higher level API for applying transactions. Should only be called for
  1030  // queue origin sequencer transactions, as the contracts on L1 manage the same
  1031  // validity checks that are done here.
  1032  func (s *SyncService) ValidateAndApplySequencerTransaction(tx *types.Transaction) error {
  1033  	if s.verifier {
  1034  		return errors.New("Verifier does not accept transactions out of band")
  1035  	}
  1036  	if tx == nil {
  1037  		return errors.New("nil transaction passed to ValidateAndApplySequencerTransaction")
  1038  	}
  1039  	s.txLock.Lock()
  1040  	defer s.txLock.Unlock()
  1041  	if err := s.verifyFee(tx); err != nil {
  1042  		return err
  1043  	}
  1044  	log.Trace("Sequencer transaction validation", "hash", tx.Hash().Hex())
  1045  
  1046  	qo := tx.QueueOrigin()
  1047  	if qo != types.QueueOriginSequencer {
  1048  		return fmt.Errorf("invalid transaction with queue origin %s", qo.String())
  1049  	}
  1050  	if err := s.txpool.ValidateTx(tx); err != nil {
  1051  		return fmt.Errorf("invalid transaction: %w", err)
  1052  	}
  1053  	if err := s.applyTransaction(tx); err != nil {
  1054  		return err
  1055  	}
  1056  	return nil
  1057  }
  1058  
  1059  // syncer represents a function that can sync remote items and then returns the
  1060  // index that it synced to as well as an error if it encountered one. It has
  1061  // side effects on the state and its functionality depends on the current state
  1062  type syncer func() (*uint64, error)
  1063  
  1064  // rangeSyncer represents a function that syncs a range of items between its two
  1065  // arguments (inclusive)
  1066  type rangeSyncer func(uint64, uint64) error
  1067  
  1068  // nextGetter is a type that represents a function that will return the next
  1069  // index
  1070  type nextGetter func() uint64
  1071  
  1072  // indexGetter is a type that represents a function that returns an index and an
  1073  // error if there is a problem fetching the index. The different types of
  1074  // indices are canonical transaction chain indices, queue indices and batch
  1075  // indices. It does not induce side effects on state
  1076  type indexGetter func() (*uint64, error)
  1077  
  1078  // isAtTip is a function that will determine if the local chain is at the tip
  1079  // of the remote datasource
  1080  func (s *SyncService) isAtTip(index *uint64, get indexGetter) (bool, error) {
  1081  	latest, err := get()
  1082  	if errors.Is(err, errElementNotFound) {
  1083  		if index == nil {
  1084  			return true, nil
  1085  		}
  1086  		return false, nil
  1087  	}
  1088  	if err != nil {
  1089  		return false, err
  1090  	}
  1091  	// There are no known enqueue transactions locally or remotely
  1092  	if latest == nil && index == nil {
  1093  		return true, nil
  1094  	}
  1095  	// Only one of the transactions are nil due to the check above so they
  1096  	// cannot be equal
  1097  	if latest == nil || index == nil {
  1098  		return false, nil
  1099  	}
  1100  	// The indices are equal
  1101  	if *latest == *index {
  1102  		return true, nil
  1103  	}
  1104  	// The local tip is greater than the remote tip. This should never happen
  1105  	if *latest < *index {
  1106  		return false, fmt.Errorf("is at tip mismatch: remote (%d) - local (%d): %w", *latest, *index, errShortRemoteTip)
  1107  	}
  1108  	// The indices are not equal
  1109  	return false, nil
  1110  }
  1111  
  1112  // syncToTip is a function that can be used to sync to the tip of an ordered
  1113  // list of things. It is used to sync transactions, enqueue elements and batches
  1114  func (s *SyncService) syncToTip(sync syncer, getTip indexGetter) error {
  1115  	s.loopLock.Lock()
  1116  	defer s.loopLock.Unlock()
  1117  
  1118  	for {
  1119  		index, err := sync()
  1120  		if errors.Is(err, errElementNotFound) {
  1121  			return nil
  1122  		}
  1123  		if err != nil {
  1124  			return err
  1125  		}
  1126  		isAtTip, err := s.isAtTip(index, getTip)
  1127  		if err != nil {
  1128  			return err
  1129  		}
  1130  		if isAtTip {
  1131  			return nil
  1132  		}
  1133  	}
  1134  }
  1135  
  1136  // sync will sync a range of items
  1137  func (s *SyncService) sync(getLatest indexGetter, getNext nextGetter, syncer rangeSyncer) (*uint64, error) {
  1138  	latestIndex, err := getLatest()
  1139  	if err != nil {
  1140  		return nil, fmt.Errorf("Cannot sync: %w", err)
  1141  	}
  1142  	if latestIndex == nil {
  1143  		return nil, errors.New("Latest index is not defined")
  1144  	}
  1145  
  1146  	nextIndex := getNext()
  1147  	if nextIndex == *latestIndex+1 {
  1148  		return latestIndex, nil
  1149  	}
  1150  	if err := syncer(nextIndex, *latestIndex); err != nil {
  1151  		return nil, err
  1152  	}
  1153  	return latestIndex, nil
  1154  }
  1155  
  1156  // syncBatches will sync a range of batches from the current known tip to the
  1157  // remote tip.
  1158  func (s *SyncService) syncBatches() (*uint64, error) {
  1159  	index, err := s.sync(s.client.GetLatestTransactionBatchIndex, s.GetNextBatchIndex, s.syncTransactionBatchRange)
  1160  	if err != nil {
  1161  		return nil, fmt.Errorf("Cannot sync batches: %w", err)
  1162  	}
  1163  	return index, nil
  1164  }
  1165  
  1166  // syncTransactionBatchRange will sync a range of batched transactions from
  1167  // start to end (inclusive)
  1168  func (s *SyncService) syncTransactionBatchRange(start, end uint64) error {
  1169  	log.Info("Syncing transaction batch range", "start", start, "end", end)
  1170  	for i := start; i <= end; i++ {
  1171  		log.Debug("Fetching transaction batch", "index", i)
  1172  		_, txs, err := s.client.GetTransactionBatch(i)
  1173  		if err != nil {
  1174  			return fmt.Errorf("Cannot get transaction batch: %w", err)
  1175  		}
  1176  		for _, tx := range txs {
  1177  			if err := s.applyBatchedTransaction(tx); err != nil {
  1178  				return fmt.Errorf("cannot apply batched transaction: %w", err)
  1179  			}
  1180  		}
  1181  		s.SetLatestBatchIndex(&i)
  1182  	}
  1183  	return nil
  1184  }
  1185  
  1186  // syncQueue will sync from the local tip to the known tip of the remote
  1187  // enqueue transaction feed.
  1188  func (s *SyncService) syncQueue() (*uint64, error) {
  1189  	index, err := s.sync(s.client.GetLatestEnqueueIndex, s.GetNextEnqueueIndex, s.syncQueueTransactionRange)
  1190  	if err != nil {
  1191  		return nil, fmt.Errorf("Cannot sync queue: %w", err)
  1192  	}
  1193  	return index, nil
  1194  }
  1195  
  1196  // syncQueueTransactionRange will apply a range of queue transactions from
  1197  // start to end (inclusive)
  1198  func (s *SyncService) syncQueueTransactionRange(start, end uint64) error {
  1199  	log.Info("Syncing enqueue transactions range", "start", start, "end", end)
  1200  	for i := start; i <= end; i++ {
  1201  		tx, err := s.client.GetEnqueue(i)
  1202  		if err != nil {
  1203  			return fmt.Errorf("Canot get enqueue transaction; %w", err)
  1204  		}
  1205  		if err := s.applyTransaction(tx); err != nil {
  1206  			return fmt.Errorf("Cannot apply transaction: %w", err)
  1207  		}
  1208  	}
  1209  	return nil
  1210  }
  1211  
  1212  // syncTransactions will sync transactions to the remote tip based on the
  1213  // backend
  1214  func (s *SyncService) syncTransactions(backend Backend) (*uint64, error) {
  1215  	getLatest := func() (*uint64, error) {
  1216  		return s.client.GetLatestTransactionIndex(backend)
  1217  	}
  1218  	sync := func(start, end uint64) error {
  1219  		return s.syncTransactionRange(start, end, backend)
  1220  	}
  1221  	index, err := s.sync(getLatest, s.GetNextIndex, sync)
  1222  	if err != nil {
  1223  		return nil, fmt.Errorf("Cannot sync transactions with backend %s: %w", backend.String(), err)
  1224  	}
  1225  	return index, nil
  1226  }
  1227  
  1228  // syncTransactionRange will sync a range of transactions from
  1229  // start to end (inclusive) from a specific Backend
  1230  func (s *SyncService) syncTransactionRange(start, end uint64, backend Backend) error {
  1231  	log.Info("Syncing transaction range", "start", start, "end", end, "backend", backend.String())
  1232  	for i := start; i <= end; i++ {
  1233  		tx, err := s.client.GetTransaction(i, backend)
  1234  		if err != nil {
  1235  			return fmt.Errorf("cannot fetch transaction %d: %w", i, err)
  1236  		}
  1237  		if err := s.applyTransaction(tx); err != nil {
  1238  			return fmt.Errorf("Cannot apply transaction: %w", err)
  1239  		}
  1240  	}
  1241  	return nil
  1242  }
  1243  
  1244  // SubscribeNewTxsEvent registers a subscription of NewTxsEvent and
  1245  // starts sending event to the given channel.
  1246  func (s *SyncService) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
  1247  	return s.scope.Track(s.txFeed.Subscribe(ch))
  1248  }
  1249  
  1250  func stringify(i *uint64) string {
  1251  	if i == nil {
  1252  		return "<nil>"
  1253  	}
  1254  	return strconv.FormatUint(*i, 10)
  1255  }
  1256  
  1257  // IngestTransaction should only be called by trusted parties as it skips all
  1258  // validation and applies the transaction
  1259  func (s *SyncService) IngestTransaction(tx *types.Transaction) error {
  1260  	return s.applyTransaction(tx)
  1261  }