github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/ethclient/simulated/backend.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 simulated 18 19 import ( 20 "errors" 21 "time" 22 23 "github.com/ethereum/go-ethereum" 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/core" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/eth" 28 "github.com/ethereum/go-ethereum/eth/catalyst" 29 "github.com/ethereum/go-ethereum/eth/downloader" 30 "github.com/ethereum/go-ethereum/eth/ethconfig" 31 "github.com/ethereum/go-ethereum/eth/filters" 32 "github.com/ethereum/go-ethereum/ethclient" 33 "github.com/ethereum/go-ethereum/node" 34 "github.com/ethereum/go-ethereum/p2p" 35 "github.com/ethereum/go-ethereum/params" 36 "github.com/ethereum/go-ethereum/rpc" 37 ) 38 39 // Client exposes the methods provided by the Ethereum RPC client. 40 type Client interface { 41 ethereum.BlockNumberReader 42 ethereum.ChainReader 43 ethereum.ChainStateReader 44 ethereum.ContractCaller 45 ethereum.GasEstimator 46 ethereum.GasPricer 47 ethereum.GasPricer1559 48 ethereum.FeeHistoryReader 49 ethereum.LogFilterer 50 ethereum.PendingStateReader 51 ethereum.PendingContractCaller 52 ethereum.TransactionReader 53 ethereum.TransactionSender 54 ethereum.ChainIDReader 55 } 56 57 // simClient wraps ethclient. This exists to prevent extracting ethclient.Client 58 // from the Client interface returned by Backend. 59 type simClient struct { 60 *ethclient.Client 61 } 62 63 // Backend is a simulated blockchain. You can use it to test your contracts or 64 // other code that interacts with the Ethereum chain. 65 type Backend struct { 66 node *node.Node 67 beacon *catalyst.SimulatedBeacon 68 client simClient 69 } 70 71 // NewBackend creates a new simulated blockchain that can be used as a backend for 72 // contract bindings in unit tests. 73 // 74 // A simulated backend always uses chainID 1337. 75 func NewBackend(alloc types.GenesisAlloc, options ...func(nodeConf *node.Config, ethConf *ethconfig.Config)) *Backend { 76 // Create the default configurations for the outer node shell and the Ethereum 77 // service to mutate with the options afterwards 78 nodeConf := node.DefaultConfig 79 nodeConf.DataDir = "" 80 nodeConf.P2P = p2p.Config{NoDiscovery: true} 81 82 ethConf := ethconfig.Defaults 83 ethConf.Genesis = &core.Genesis{ 84 Config: params.AllDevChainProtocolChanges, 85 GasLimit: ethconfig.Defaults.Miner.GasCeil, 86 Alloc: alloc, 87 } 88 ethConf.SyncMode = downloader.FullSync 89 ethConf.TxPool.NoLocals = true 90 91 for _, option := range options { 92 option(&nodeConf, ðConf) 93 } 94 // Assemble the Ethereum stack to run the chain with 95 stack, err := node.New(&nodeConf) 96 if err != nil { 97 panic(err) // this should never happen 98 } 99 sim, err := newWithNode(stack, ðConf, 0) 100 if err != nil { 101 panic(err) // this should never happen 102 } 103 return sim 104 } 105 106 // newWithNode sets up a simulated backend on an existing node. The provided node 107 // must not be started and will be started by this method. 108 func newWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (*Backend, error) { 109 backend, err := eth.New(stack, conf) 110 if err != nil { 111 return nil, err 112 } 113 // Register the filter system 114 filterSystem := filters.NewFilterSystem(backend.APIBackend, filters.Config{}) 115 stack.RegisterAPIs([]rpc.API{{ 116 Namespace: "eth", 117 Service: filters.NewFilterAPI(filterSystem), 118 }}) 119 // Start the node 120 if err := stack.Start(); err != nil { 121 return nil, err 122 } 123 // Set up the simulated beacon 124 beacon, err := catalyst.NewSimulatedBeacon(blockPeriod, backend) 125 if err != nil { 126 return nil, err 127 } 128 // Reorg our chain back to genesis 129 if err := beacon.Fork(backend.BlockChain().GetCanonicalHash(0)); err != nil { 130 return nil, err 131 } 132 return &Backend{ 133 node: stack, 134 beacon: beacon, 135 client: simClient{ethclient.NewClient(stack.Attach())}, 136 }, nil 137 } 138 139 // Close shuts down the simBackend. 140 // The simulated backend can't be used afterwards. 141 func (n *Backend) Close() error { 142 if n.client.Client != nil { 143 n.client.Close() 144 n.client = simClient{} 145 } 146 var err error 147 if n.beacon != nil { 148 err = n.beacon.Stop() 149 n.beacon = nil 150 } 151 if n.node != nil { 152 err = errors.Join(err, n.node.Close()) 153 n.node = nil 154 } 155 return err 156 } 157 158 // Commit seals a block and moves the chain forward to a new empty block. 159 func (n *Backend) Commit() common.Hash { 160 return n.beacon.Commit() 161 } 162 163 // Rollback removes all pending transactions, reverting to the last committed state. 164 func (n *Backend) Rollback() { 165 n.beacon.Rollback() 166 } 167 168 // Fork creates a side-chain that can be used to simulate reorgs. 169 // 170 // This function should be called with the ancestor block where the new side 171 // chain should be started. Transactions (old and new) can then be applied on 172 // top and Commit-ed. 173 // 174 // Note, the side-chain will only become canonical (and trigger the events) when 175 // it becomes longer. Until then CallContract will still operate on the current 176 // canonical chain. 177 // 178 // There is a % chance that the side chain becomes canonical at the same length 179 // to simulate live network behavior. 180 func (n *Backend) Fork(parentHash common.Hash) error { 181 return n.beacon.Fork(parentHash) 182 } 183 184 // AdjustTime changes the block timestamp and creates a new block. 185 // It can only be called on empty blocks. 186 func (n *Backend) AdjustTime(adjustment time.Duration) error { 187 return n.beacon.AdjustTime(adjustment) 188 } 189 190 // Client returns a client that accesses the simulated chain. 191 func (n *Backend) Client() Client { 192 return n.client 193 }