github.com/ethereum/go-ethereum@v1.16.1/eth/catalyst/simulated_beacon_api.go (about)

     1  // Copyright 2023 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package catalyst
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/core"
    24  	"github.com/ethereum/go-ethereum/core/types"
    25  )
    26  
    27  // simulatedBeaconAPI provides a RPC API for SimulatedBeacon.
    28  type simulatedBeaconAPI struct {
    29  	sim *SimulatedBeacon
    30  }
    31  
    32  // newSimulatedBeaconAPI returns an instance of simulatedBeaconAPI with a
    33  // buffered commit channel. If period is zero, it starts a goroutine to handle
    34  // new tx events.
    35  func newSimulatedBeaconAPI(sim *SimulatedBeacon) *simulatedBeaconAPI {
    36  	api := &simulatedBeaconAPI{sim: sim}
    37  	if sim.period == 0 {
    38  		// mine on demand if period is set to 0
    39  		go api.loop()
    40  	}
    41  	return api
    42  }
    43  
    44  // loop is the main loop for the API when it's running in period = 0 mode. It
    45  // ensures that block production is triggered as soon as a new withdrawal or
    46  // transaction is received.
    47  func (a *simulatedBeaconAPI) loop() {
    48  	var (
    49  		newTxs    = make(chan core.NewTxsEvent)
    50  		newWxs    = make(chan newWithdrawalsEvent)
    51  		newTxsSub = a.sim.eth.TxPool().SubscribeTransactions(newTxs, true)
    52  		newWxsSub = a.sim.withdrawals.subscribe(newWxs)
    53  		doCommit  = make(chan struct{}, 1)
    54  	)
    55  	defer newTxsSub.Unsubscribe()
    56  	defer newWxsSub.Unsubscribe()
    57  
    58  	// A background thread which signals to the simulator when to commit
    59  	// based on messages over doCommit.
    60  	go func() {
    61  		for range doCommit {
    62  			a.sim.Commit()
    63  			a.sim.eth.TxPool().Sync()
    64  
    65  			// It's worth noting that in case a tx ends up in the pool listed as
    66  			// "executable", but for whatever reason the miner does not include it in
    67  			// a block -- maybe the miner is enforcing a higher tip than the pool --
    68  			// this code will spinloop.
    69  			for {
    70  				if executable, _ := a.sim.eth.TxPool().Stats(); executable == 0 {
    71  					break
    72  				}
    73  				a.sim.Commit()
    74  			}
    75  		}
    76  	}()
    77  
    78  	for {
    79  		select {
    80  		case <-a.sim.shutdownCh:
    81  			close(doCommit)
    82  			return
    83  		case <-newWxs:
    84  			select {
    85  			case doCommit <- struct{}{}:
    86  			default:
    87  			}
    88  		case <-newTxs:
    89  			select {
    90  			case doCommit <- struct{}{}:
    91  			default:
    92  			}
    93  		}
    94  	}
    95  }
    96  
    97  // AddWithdrawal adds a withdrawal to the pending queue.
    98  func (a *simulatedBeaconAPI) AddWithdrawal(ctx context.Context, withdrawal *types.Withdrawal) error {
    99  	return a.sim.withdrawals.add(withdrawal)
   100  }
   101  
   102  // SetFeeRecipient sets the fee recipient for block building purposes.
   103  func (a *simulatedBeaconAPI) SetFeeRecipient(ctx context.Context, feeRecipient common.Address) {
   104  	a.sim.setFeeRecipient(feeRecipient)
   105  }