github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/sequencer/dbmanager.go (about)

     1  package sequencer
     2  
     3  import (
     4  	"context"
     5  	"math/big"
     6  	"time"
     7  
     8  	"github.com/0xPolygon/supernets2-node/log"
     9  	"github.com/0xPolygon/supernets2-node/pool"
    10  	"github.com/0xPolygon/supernets2-node/state"
    11  	"github.com/ethereum/go-ethereum/common"
    12  	"github.com/ethereum/go-ethereum/core/types"
    13  	"github.com/jackc/pgx/v4"
    14  )
    15  
    16  // Pool Loader and DB Updater
    17  type dbManager struct {
    18  	cfg              DBManagerCfg
    19  	txPool           txPool
    20  	state            stateInterface
    21  	worker           workerInterface
    22  	txsStore         TxsStore
    23  	l2ReorgCh        chan L2ReorgEvent
    24  	ctx              context.Context
    25  	batchConstraints batchConstraints
    26  	numberOfReorgs   uint64
    27  }
    28  
    29  func (d *dbManager) GetBatchByNumber(ctx context.Context, batchNumber uint64, dbTx pgx.Tx) (*state.Batch, error) {
    30  	return d.state.GetBatchByNumber(ctx, batchNumber, dbTx)
    31  }
    32  
    33  // ClosingBatchParameters contains the necessary parameters to close a batch
    34  type ClosingBatchParameters struct {
    35  	BatchNumber    uint64
    36  	StateRoot      common.Hash
    37  	LocalExitRoot  common.Hash
    38  	AccInputHash   common.Hash
    39  	Txs            []types.Transaction
    40  	BatchResources state.BatchResources
    41  	ClosingReason  state.ClosingReason
    42  }
    43  
    44  func newDBManager(ctx context.Context, config DBManagerCfg, txPool txPool, state stateInterface, worker *Worker, closingSignalCh ClosingSignalCh, txsStore TxsStore, batchConstraints batchConstraints) *dbManager {
    45  	numberOfReorgs, err := state.CountReorgs(ctx, nil)
    46  	if err != nil {
    47  		log.Error("failed to get number of reorgs: %v", err)
    48  	}
    49  
    50  	return &dbManager{ctx: ctx, cfg: config, txPool: txPool, state: state, worker: worker, txsStore: txsStore, l2ReorgCh: closingSignalCh.L2ReorgCh, batchConstraints: batchConstraints, numberOfReorgs: numberOfReorgs}
    51  }
    52  
    53  // Start stars the dbManager routines
    54  func (d *dbManager) Start() {
    55  	go d.loadFromPool()
    56  	go func() {
    57  		for {
    58  			time.Sleep(d.cfg.L2ReorgRetrievalInterval.Duration)
    59  			d.checkIfReorg()
    60  		}
    61  	}()
    62  	go d.storeProcessedTxAndDeleteFromPool()
    63  }
    64  
    65  // GetLastBatchNumber get the latest batch number from state
    66  func (d *dbManager) GetLastBatchNumber(ctx context.Context) (uint64, error) {
    67  	return d.state.GetLastBatchNumber(ctx, nil)
    68  }
    69  
    70  // OpenBatch opens a new batch to star processing transactions
    71  func (d *dbManager) OpenBatch(ctx context.Context, processingContext state.ProcessingContext, dbTx pgx.Tx) error {
    72  	return d.state.OpenBatch(ctx, processingContext, dbTx)
    73  }
    74  
    75  // CreateFirstBatch is using during genesis
    76  func (d *dbManager) CreateFirstBatch(ctx context.Context, sequencerAddress common.Address) state.ProcessingContext {
    77  	processingCtx := state.ProcessingContext{
    78  		BatchNumber:    1,
    79  		Coinbase:       sequencerAddress,
    80  		Timestamp:      time.Now(),
    81  		GlobalExitRoot: state.ZeroHash,
    82  	}
    83  	dbTx, err := d.state.BeginStateTransaction(ctx)
    84  	if err != nil {
    85  		log.Errorf("failed to begin state transaction for opening a batch, err: %v", err)
    86  		return processingCtx
    87  	}
    88  	err = d.state.OpenBatch(ctx, processingCtx, dbTx)
    89  	if err != nil {
    90  		if rollbackErr := dbTx.Rollback(ctx); rollbackErr != nil {
    91  			log.Errorf(
    92  				"failed to rollback dbTx when opening batch that gave err: %v. Rollback err: %v",
    93  				rollbackErr, err,
    94  			)
    95  		}
    96  		log.Errorf("failed to open a batch, err: %v", err)
    97  		return processingCtx
    98  	}
    99  	if err := dbTx.Commit(ctx); err != nil {
   100  		log.Errorf("failed to commit dbTx when opening batch, err: %v", err)
   101  		return processingCtx
   102  	}
   103  	return processingCtx
   104  }
   105  
   106  // checkIfReorg checks if a reorg has happened
   107  func (d *dbManager) checkIfReorg() {
   108  	numberOfReorgs, err := d.state.CountReorgs(d.ctx, nil)
   109  	if err != nil {
   110  		log.Error("failed to get number of reorgs: %v", err)
   111  	}
   112  
   113  	if numberOfReorgs != d.numberOfReorgs {
   114  		log.Warnf("New L2 reorg detected")
   115  		d.l2ReorgCh <- L2ReorgEvent{}
   116  	}
   117  }
   118  
   119  // loadFromPool keeps loading transactions from the pool
   120  func (d *dbManager) loadFromPool() {
   121  	for {
   122  		time.Sleep(d.cfg.PoolRetrievalInterval.Duration)
   123  
   124  		poolTransactions, err := d.txPool.GetNonWIPPendingTxs(d.ctx, 0)
   125  		if err != nil && err != pool.ErrNotFound {
   126  			log.Errorf("load tx from pool: %v", err)
   127  		}
   128  
   129  		for _, tx := range poolTransactions {
   130  			err := d.addTxToWorker(tx)
   131  			if err != nil {
   132  				log.Errorf("error adding transaction to worker: %v", err)
   133  			}
   134  		}
   135  	}
   136  }
   137  
   138  func (d *dbManager) addTxToWorker(tx pool.Transaction) error {
   139  	txTracker, err := d.worker.NewTxTracker(tx.Transaction, tx.ZKCounters, tx.IP)
   140  	if err != nil {
   141  		return err
   142  	}
   143  	dropReason, isWIP := d.worker.AddTxTracker(d.ctx, txTracker)
   144  	if dropReason != nil {
   145  		failedReason := dropReason.Error()
   146  		return d.txPool.UpdateTxStatus(d.ctx, txTracker.Hash, pool.TxStatusFailed, false, &failedReason)
   147  	} else {
   148  		if isWIP {
   149  			return d.txPool.UpdateTxWIPStatus(d.ctx, tx.Hash(), true)
   150  		}
   151  	}
   152  
   153  	return nil
   154  }
   155  
   156  // BeginStateTransaction starts a db transaction in the state
   157  func (d *dbManager) BeginStateTransaction(ctx context.Context) (pgx.Tx, error) {
   158  	return d.state.BeginStateTransaction(ctx)
   159  }
   160  
   161  // StoreProcessedTransaction stores a transaction in the state
   162  func (d *dbManager) StoreProcessedTransaction(ctx context.Context, batchNumber uint64, processedTx *state.ProcessTransactionResponse, coinbase common.Address, timestamp uint64, dbTx pgx.Tx) error {
   163  	return d.state.StoreTransaction(ctx, batchNumber, processedTx, coinbase, timestamp, dbTx)
   164  }
   165  
   166  // DeleteTransactionFromPool deletes a transaction from the pool
   167  func (d *dbManager) DeleteTransactionFromPool(ctx context.Context, txHash common.Hash) error {
   168  	return d.txPool.DeleteTransactionByHash(ctx, txHash)
   169  }
   170  
   171  // storeProcessedTxAndDeleteFromPool stores a tx into the state and changes it status in the pool
   172  func (d *dbManager) storeProcessedTxAndDeleteFromPool() {
   173  	for {
   174  		txToStore := <-d.txsStore.Ch
   175  		d.checkIfReorg()
   176  
   177  		// Flush the state db
   178  		err := d.state.FlushMerkleTree(d.ctx)
   179  		if err != nil {
   180  			log.Fatalf("StoreProcessedTxAndDeleteFromPool. Error flushing state db: %v", err)
   181  		}
   182  
   183  		log.Debugf("Storing tx %v", txToStore.txResponse.TxHash)
   184  		dbTx, err := d.BeginStateTransaction(d.ctx)
   185  		if err != nil {
   186  			log.Fatalf("StoreProcessedTxAndDeleteFromPool: %v", err)
   187  		}
   188  
   189  		err = d.StoreProcessedTransaction(d.ctx, txToStore.batchNumber, txToStore.txResponse, txToStore.coinbase, txToStore.timestamp, dbTx)
   190  		if err != nil {
   191  			log.Fatalf("StoreProcessedTxAndDeleteFromPool: %v", err)
   192  		}
   193  
   194  		// Update batch l2 data
   195  		batch, err := d.state.GetBatchByNumber(d.ctx, txToStore.batchNumber, dbTx)
   196  		if err != nil {
   197  			log.Fatalf("StoreProcessedTxAndDeleteFromPool: %v", err)
   198  		}
   199  
   200  		txData, err := state.EncodeTransaction(txToStore.txResponse.Tx)
   201  		if err != nil {
   202  			log.Fatalf("StoreProcessedTxAndDeleteFromPool: %v", err)
   203  		}
   204  		batch.BatchL2Data = append(batch.BatchL2Data, txData...)
   205  
   206  		if !txToStore.isForcedBatch {
   207  			err = d.state.UpdateBatchL2Data(d.ctx, txToStore.batchNumber, batch.BatchL2Data, dbTx)
   208  			if err != nil {
   209  				log.Fatalf("StoreProcessedTxAndDeleteFromPool: %v", err)
   210  			}
   211  		}
   212  
   213  		err = dbTx.Commit(d.ctx)
   214  		if err != nil {
   215  			log.Fatalf("StoreProcessedTxAndDeleteFromPool error committing : %v", err)
   216  		}
   217  
   218  		// Change Tx status to selected
   219  		err = d.txPool.UpdateTxStatus(d.ctx, txToStore.txResponse.TxHash, pool.TxStatusSelected, false, nil)
   220  		if err != nil {
   221  			log.Fatalf("StoreProcessedTxAndDeleteFromPool: %v", err)
   222  		}
   223  
   224  		log.Infof("StoreProcessedTxAndDeleteFromPool: successfully stored tx: %v for batch: %v", txToStore.txResponse.TxHash.String(), txToStore.batchNumber)
   225  		d.txsStore.Wg.Done()
   226  	}
   227  }
   228  
   229  // GetWIPBatch returns ready WIP batch
   230  func (d *dbManager) GetWIPBatch(ctx context.Context) (*WipBatch, error) {
   231  	const two = 2
   232  	var lastBatch, previousLastBatch *state.Batch
   233  	dbTx, err := d.BeginStateTransaction(ctx)
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  	defer func() {
   238  		err := dbTx.Commit(ctx)
   239  		if err != nil {
   240  			log.Errorf("failed to commit GetWIPBatch: %v", err)
   241  		}
   242  	}()
   243  
   244  	lastBatches, err := d.state.GetLastNBatches(ctx, two, dbTx)
   245  	if err != nil {
   246  		return nil, err
   247  	}
   248  
   249  	lastBatch = lastBatches[0]
   250  	if len(lastBatches) > 1 {
   251  		previousLastBatch = lastBatches[1]
   252  	}
   253  
   254  	lastBatchTxs, _, err := state.DecodeTxs(lastBatch.BatchL2Data)
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  	lastBatch.Transactions = lastBatchTxs
   259  
   260  	var prevLastBatchTxs []types.Transaction
   261  	if previousLastBatch != nil {
   262  		prevLastBatchTxs, _, err = state.DecodeTxs(previousLastBatch.BatchL2Data)
   263  		if err != nil {
   264  			return nil, err
   265  		}
   266  	}
   267  
   268  	var lastStateRoot common.Hash
   269  	// If the last two batches have no txs, the stateRoot can not be retrieved from the l2block because there is no tx.
   270  	// In this case, the stateRoot must be gotten from the previousLastBatch
   271  	if len(lastBatchTxs) == 0 && previousLastBatch != nil && len(prevLastBatchTxs) == 0 {
   272  		lastStateRoot = previousLastBatch.StateRoot
   273  	} else {
   274  		lastStateRoot, err = d.state.GetLastStateRoot(ctx, dbTx)
   275  		if err != nil {
   276  			return nil, err
   277  		}
   278  	}
   279  
   280  	wipBatch := &WipBatch{
   281  		batchNumber:    lastBatch.BatchNumber,
   282  		coinbase:       lastBatch.Coinbase,
   283  		localExitRoot:  lastBatch.LocalExitRoot,
   284  		timestamp:      lastBatch.Timestamp,
   285  		globalExitRoot: lastBatch.GlobalExitRoot,
   286  		countOfTxs:     len(lastBatch.Transactions),
   287  	}
   288  
   289  	// Init counters to MAX values
   290  	var totalBytes uint64 = d.batchConstraints.MaxBatchBytesSize
   291  	var batchZkCounters state.ZKCounters = state.ZKCounters{
   292  		CumulativeGasUsed:    d.batchConstraints.MaxCumulativeGasUsed,
   293  		UsedKeccakHashes:     d.batchConstraints.MaxKeccakHashes,
   294  		UsedPoseidonHashes:   d.batchConstraints.MaxPoseidonHashes,
   295  		UsedPoseidonPaddings: d.batchConstraints.MaxPoseidonPaddings,
   296  		UsedMemAligns:        d.batchConstraints.MaxMemAligns,
   297  		UsedArithmetics:      d.batchConstraints.MaxArithmetics,
   298  		UsedBinaries:         d.batchConstraints.MaxBinaries,
   299  		UsedSteps:            d.batchConstraints.MaxSteps,
   300  	}
   301  
   302  	isClosed, err := d.IsBatchClosed(ctx, lastBatch.BatchNumber)
   303  	if err != nil {
   304  		return nil, err
   305  	}
   306  
   307  	if isClosed {
   308  		wipBatch.batchNumber = lastBatch.BatchNumber + 1
   309  		wipBatch.stateRoot = lastBatch.StateRoot
   310  		wipBatch.initialStateRoot = lastBatch.StateRoot
   311  
   312  		processingContext := &state.ProcessingContext{
   313  			BatchNumber:    wipBatch.batchNumber,
   314  			Coinbase:       wipBatch.coinbase,
   315  			Timestamp:      wipBatch.timestamp,
   316  			GlobalExitRoot: wipBatch.globalExitRoot,
   317  		}
   318  		err = d.state.OpenBatch(ctx, *processingContext, dbTx)
   319  		if err != nil {
   320  			if rollbackErr := dbTx.Rollback(ctx); rollbackErr != nil {
   321  				log.Errorf(
   322  					"failed to rollback dbTx when opening batch that gave err: %v. Rollback err: %v",
   323  					rollbackErr, err,
   324  				)
   325  			}
   326  			log.Errorf("failed to open a batch, err: %v", err)
   327  			return nil, err
   328  		}
   329  		if err := dbTx.Commit(ctx); err != nil {
   330  			log.Errorf("failed to commit dbTx when opening batch, err: %v", err)
   331  			return nil, err
   332  		}
   333  	} else {
   334  		wipBatch.stateRoot = lastStateRoot
   335  		wipBatch.initialStateRoot = previousLastBatch.StateRoot
   336  		batchL2DataLen := len(lastBatch.BatchL2Data)
   337  
   338  		if batchL2DataLen > 0 {
   339  			wipBatch.countOfTxs = len(lastBatch.Transactions)
   340  			batchToExecute := *lastBatch
   341  			batchToExecute.BatchNumber = wipBatch.batchNumber
   342  			batchResponse, err := d.state.ExecuteBatch(ctx, batchToExecute, false, dbTx)
   343  			if err != nil {
   344  				return nil, err
   345  			}
   346  
   347  			zkCounters := &state.ZKCounters{
   348  				CumulativeGasUsed:    batchResponse.GetCumulativeGasUsed(),
   349  				UsedKeccakHashes:     batchResponse.CntKeccakHashes,
   350  				UsedPoseidonHashes:   batchResponse.CntPoseidonHashes,
   351  				UsedPoseidonPaddings: batchResponse.CntPoseidonPaddings,
   352  				UsedMemAligns:        batchResponse.CntMemAligns,
   353  				UsedArithmetics:      batchResponse.CntArithmetics,
   354  				UsedBinaries:         batchResponse.CntBinaries,
   355  				UsedSteps:            batchResponse.CntSteps,
   356  			}
   357  
   358  			err = batchZkCounters.Sub(*zkCounters)
   359  			if err != nil {
   360  				return nil, err
   361  			}
   362  
   363  			totalBytes -= uint64(batchL2DataLen)
   364  		} else {
   365  			wipBatch.countOfTxs = 0
   366  		}
   367  	}
   368  
   369  	wipBatch.remainingResources = state.BatchResources{ZKCounters: batchZkCounters, Bytes: totalBytes}
   370  	return wipBatch, nil
   371  }
   372  
   373  // GetLastClosedBatch gets the latest closed batch from state
   374  func (d *dbManager) GetLastClosedBatch(ctx context.Context) (*state.Batch, error) {
   375  	return d.state.GetLastClosedBatch(ctx, nil)
   376  }
   377  
   378  // GetLastBatch gets the latest batch from state
   379  func (d *dbManager) GetLastBatch(ctx context.Context) (*state.Batch, error) {
   380  	batch, err := d.state.GetLastBatch(d.ctx, nil)
   381  	if err != nil {
   382  		return nil, err
   383  	}
   384  	return batch, nil
   385  }
   386  
   387  // IsBatchClosed checks if a batch is closed
   388  func (d *dbManager) IsBatchClosed(ctx context.Context, batchNum uint64) (bool, error) {
   389  	return d.state.IsBatchClosed(ctx, batchNum, nil)
   390  }
   391  
   392  // GetLastNBatches gets the latest N batches from state
   393  func (d *dbManager) GetLastNBatches(ctx context.Context, numBatches uint) ([]*state.Batch, error) {
   394  	return d.state.GetLastNBatches(ctx, numBatches, nil)
   395  }
   396  
   397  // GetLatestGer gets the latest global exit root
   398  func (d *dbManager) GetLatestGer(ctx context.Context, gerFinalityNumberOfBlocks uint64) (state.GlobalExitRoot, time.Time, error) {
   399  	return d.state.GetLatestGer(ctx, gerFinalityNumberOfBlocks)
   400  }
   401  
   402  // CloseBatch closes a batch in the state
   403  func (d *dbManager) CloseBatch(ctx context.Context, params ClosingBatchParameters) error {
   404  	processingReceipt := state.ProcessingReceipt{
   405  		BatchNumber:    params.BatchNumber,
   406  		StateRoot:      params.StateRoot,
   407  		LocalExitRoot:  params.LocalExitRoot,
   408  		AccInputHash:   params.AccInputHash,
   409  		BatchResources: params.BatchResources,
   410  		ClosingReason:  params.ClosingReason,
   411  	}
   412  
   413  	batchL2Data, err := state.EncodeTransactions(params.Txs)
   414  	if err != nil {
   415  		return err
   416  	}
   417  
   418  	processingReceipt.BatchL2Data = batchL2Data
   419  
   420  	dbTx, err := d.BeginStateTransaction(ctx)
   421  	if err != nil {
   422  		return err
   423  	}
   424  
   425  	err = d.state.CloseBatch(ctx, processingReceipt, dbTx)
   426  	if err != nil {
   427  		err2 := dbTx.Rollback(ctx)
   428  		if err2 != nil {
   429  			log.Errorf("CloseBatch error rolling back: %v", err2)
   430  		}
   431  		return err
   432  	} else {
   433  		err := dbTx.Commit(ctx)
   434  		if err != nil {
   435  			log.Errorf("CloseBatch error committing: %v", err)
   436  			return err
   437  		}
   438  	}
   439  
   440  	return nil
   441  }
   442  
   443  // ProcessForcedBatch process a forced batch
   444  func (d *dbManager) ProcessForcedBatch(ForcedBatchNumber uint64, request state.ProcessRequest) (*state.ProcessBatchResponse, error) {
   445  	// Open Batch
   446  	processingCtx := state.ProcessingContext{
   447  		BatchNumber:    request.BatchNumber,
   448  		Coinbase:       request.Coinbase,
   449  		Timestamp:      request.Timestamp,
   450  		GlobalExitRoot: request.GlobalExitRoot,
   451  		ForcedBatchNum: &ForcedBatchNumber,
   452  	}
   453  	dbTx, err := d.state.BeginStateTransaction(d.ctx)
   454  	if err != nil {
   455  		log.Errorf("failed to begin state transaction for opening a forced batch, err: %v", err)
   456  		return nil, err
   457  	}
   458  
   459  	err = d.state.OpenBatch(d.ctx, processingCtx, dbTx)
   460  	if err != nil {
   461  		if rollbackErr := dbTx.Rollback(d.ctx); rollbackErr != nil {
   462  			log.Errorf(
   463  				"failed to rollback dbTx when opening a forced batch that gave err: %v. Rollback err: %v",
   464  				rollbackErr, err,
   465  			)
   466  		}
   467  		log.Errorf("failed to open a batch, err: %v", err)
   468  		return nil, err
   469  	}
   470  
   471  	// Fetch Forced Batch
   472  	forcedBatch, err := d.state.GetForcedBatch(d.ctx, ForcedBatchNumber, dbTx)
   473  	if err != nil {
   474  		if rollbackErr := dbTx.Rollback(d.ctx); rollbackErr != nil {
   475  			log.Errorf(
   476  				"failed to rollback dbTx when getting forced batch err: %v. Rollback err: %v",
   477  				rollbackErr, err,
   478  			)
   479  		}
   480  		log.Errorf("failed to get a forced batch, err: %v", err)
   481  		return nil, err
   482  	}
   483  
   484  	// Process Batch
   485  	processBatchResponse, err := d.state.ProcessSequencerBatch(d.ctx, request.BatchNumber, forcedBatch.RawTxsData, request.Caller, dbTx)
   486  	if err != nil {
   487  		log.Errorf("failed to process a forced batch, err: %v", err)
   488  		return nil, err
   489  	}
   490  
   491  	// Close Batch
   492  	txsBytes := uint64(0)
   493  	for _, resp := range processBatchResponse.Responses {
   494  		if !resp.ChangesStateRoot {
   495  			continue
   496  		}
   497  		txsBytes += resp.Tx.Size()
   498  	}
   499  	processingReceipt := state.ProcessingReceipt{
   500  		BatchNumber:   request.BatchNumber,
   501  		StateRoot:     processBatchResponse.NewStateRoot,
   502  		LocalExitRoot: processBatchResponse.NewLocalExitRoot,
   503  		AccInputHash:  processBatchResponse.NewAccInputHash,
   504  		BatchL2Data:   forcedBatch.RawTxsData,
   505  		BatchResources: state.BatchResources{
   506  			ZKCounters: processBatchResponse.UsedZkCounters,
   507  			Bytes:      txsBytes,
   508  		},
   509  		ClosingReason: state.ForcedBatchClosingReason,
   510  	}
   511  
   512  	isClosed := false
   513  	tryToCloseAndCommit := true
   514  	for tryToCloseAndCommit {
   515  		if !isClosed {
   516  			closingErr := d.state.CloseBatch(d.ctx, processingReceipt, dbTx)
   517  			tryToCloseAndCommit = closingErr != nil
   518  			if tryToCloseAndCommit {
   519  				continue
   520  			}
   521  			isClosed = true
   522  		}
   523  
   524  		if err := dbTx.Commit(d.ctx); err != nil {
   525  			log.Errorf("failed to commit dbTx when processing a forced batch, err: %v", err)
   526  		}
   527  		tryToCloseAndCommit = err != nil
   528  	}
   529  
   530  	return processBatchResponse, nil
   531  }
   532  
   533  // GetForcedBatchesSince gets L1 forced batches since timestamp
   534  func (d *dbManager) GetForcedBatchesSince(ctx context.Context, forcedBatchNumber, maxBlockNumber uint64, dbTx pgx.Tx) ([]*state.ForcedBatch, error) {
   535  	return d.state.GetForcedBatchesSince(ctx, forcedBatchNumber, maxBlockNumber, dbTx)
   536  }
   537  
   538  // GetLastL2BlockHeader gets the last l2 block number
   539  func (d *dbManager) GetLastL2BlockHeader(ctx context.Context, dbTx pgx.Tx) (*types.Header, error) {
   540  	return d.state.GetLastL2BlockHeader(ctx, dbTx)
   541  }
   542  
   543  func (d *dbManager) GetLastBlock(ctx context.Context, dbTx pgx.Tx) (*state.Block, error) {
   544  	return d.state.GetLastBlock(ctx, dbTx)
   545  }
   546  
   547  func (d *dbManager) GetLastTrustedForcedBatchNumber(ctx context.Context, dbTx pgx.Tx) (uint64, error) {
   548  	return d.state.GetLastTrustedForcedBatchNumber(ctx, dbTx)
   549  }
   550  
   551  func (d *dbManager) GetBalanceByStateRoot(ctx context.Context, address common.Address, root common.Hash) (*big.Int, error) {
   552  	return d.state.GetBalanceByStateRoot(ctx, address, root)
   553  }
   554  
   555  func (d *dbManager) GetTransactionsByBatchNumber(ctx context.Context, batchNumber uint64) (txs []types.Transaction, err error) {
   556  	return d.state.GetTransactionsByBatchNumber(ctx, batchNumber, nil)
   557  }
   558  
   559  func (d *dbManager) UpdateTxStatus(ctx context.Context, hash common.Hash, newStatus pool.TxStatus, isWIP bool, failedReason *string) error {
   560  	return d.txPool.UpdateTxStatus(ctx, hash, newStatus, isWIP, failedReason)
   561  }
   562  
   563  // GetLatestVirtualBatchTimestamp gets last virtual batch timestamp
   564  func (d *dbManager) GetLatestVirtualBatchTimestamp(ctx context.Context, dbTx pgx.Tx) (time.Time, error) {
   565  	return d.state.GetLatestVirtualBatchTimestamp(ctx, dbTx)
   566  }
   567  
   568  // CountReorgs returns the number of reorgs
   569  func (d *dbManager) CountReorgs(ctx context.Context, dbTx pgx.Tx) (uint64, error) {
   570  	return d.state.CountReorgs(ctx, dbTx)
   571  }
   572  
   573  // FlushMerkleTree persists updates in the Merkle tree
   574  func (d *dbManager) FlushMerkleTree(ctx context.Context) error {
   575  	return d.state.FlushMerkleTree(ctx)
   576  }