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 }