// Copyright 2023 The go-ethereum Authors // This file is part of the go-ethereum library. // // The go-ethereum library is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // The go-ethereum library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . package catalyst import ( "context" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" ) // simulatedBeaconAPI provides a RPC API for SimulatedBeacon. type simulatedBeaconAPI struct { sim *SimulatedBeacon } // newSimulatedBeaconAPI returns an instance of simulatedBeaconAPI with a // buffered commit channel. If period is zero, it starts a goroutine to handle // new tx events. func newSimulatedBeaconAPI(sim *SimulatedBeacon) *simulatedBeaconAPI { api := &simulatedBeaconAPI{sim: sim} if sim.period == 0 { // mine on demand if period is set to 0 go api.loop() } return api } // loop is the main loop for the API when it's running in period = 0 mode. It // ensures that block production is triggered as soon as a new withdrawal or // transaction is received. func (a *simulatedBeaconAPI) loop() { var ( newTxs = make(chan core.NewTxsEvent) newWxs = make(chan newWithdrawalsEvent) newTxsSub = a.sim.eth.TxPool().SubscribeTransactions(newTxs, true) newWxsSub = a.sim.withdrawals.subscribe(newWxs) doCommit = make(chan struct{}, 1) ) defer newTxsSub.Unsubscribe() defer newWxsSub.Unsubscribe() // A background thread which signals to the simulator when to commit // based on messages over doCommit. go func() { for range doCommit { a.sim.Commit() a.sim.eth.TxPool().Sync() // It's worth noting that in case a tx ends up in the pool listed as // "executable", but for whatever reason the miner does not include it in // a block -- maybe the miner is enforcing a higher tip than the pool -- // this code will spinloop. for { if executable, _ := a.sim.eth.TxPool().Stats(); executable == 0 { break } a.sim.Commit() } } }() for { select { case <-a.sim.shutdownCh: close(doCommit) return case <-newWxs: select { case doCommit <- struct{}{}: default: } case <-newTxs: select { case doCommit <- struct{}{}: default: } } } } // AddWithdrawal adds a withdrawal to the pending queue. func (a *simulatedBeaconAPI) AddWithdrawal(ctx context.Context, withdrawal *types.Withdrawal) error { return a.sim.withdrawals.add(withdrawal) } // SetFeeRecipient sets the fee recipient for block building purposes. func (a *simulatedBeaconAPI) SetFeeRecipient(ctx context.Context, feeRecipient common.Address) { a.sim.setFeeRecipient(feeRecipient) }