diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index f56aa3686b..ae9b4c154a 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -17,152 +17,19 @@ package backends import ( - "context" - "math" - "time" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/eth/catalyst" - "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/ethconfig" - "github.com/ethereum/go-ethereum/eth/filters" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/node" - "github.com/ethereum/go-ethereum/p2p" - "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/ethclient/simulated" ) -var _ bind.ContractBackend = (SimulatedBackend)(nil) -var _ bind.ContractBackend = (*simBackend)(nil) - -type SimChainManagement interface { - // Commit seals a block and moves the chain forward to a new empty block. - Commit() common.Hash - - // Rollback un-sends previously added transactions. - Rollback() - - // Fork sets the head to a new block, which is based on the provided parentHash. - Fork(ctx context.Context, parentHash common.Hash) error - - // AdjustTime changes the block timestamp. - AdjustTime(adjustment time.Duration) error - - // Close closes the backend. You need to call this to clean up resources. - Close() error +type SimulatedBackend struct { + simulated.Backend } -// SimulatedBackend all interfaces in the ethereum package, but is based on a -// simulated blockchain. It is intended for testing purposes. -type SimulatedBackend interface { - SimChainManagement - - // The backend implements all interfaces in the ethereum package. - ethereum.BlockNumberReader - ethereum.ChainReader - ethereum.ChainStateReader - ethereum.ContractCaller - ethereum.GasEstimator - ethereum.GasPricer - ethereum.GasPricer1559 - ethereum.LogFilterer - ethereum.PendingStateReader - ethereum.PendingContractCaller - ethereum.TransactionReader - ethereum.TransactionSender - ethereum.ChainIDReader -} - -type simBackend struct { - eth *eth.Ethereum - *catalyst.SimulatedBeacon - *ethclient.Client -} - -// NewSimulatedBackend creates a new binding backend using a simulated blockchain +// New creates a new binding backend using a simulated blockchain // for testing purposes. // A simulated backend always uses chainID 1337. +// +// Deprecated: please use simulated.Backend instead func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) SimulatedBackend { - // Setup the node object - nodeConf := node.DefaultConfig - nodeConf.DataDir = "" - nodeConf.P2P = p2p.Config{DiscAddr: "", ListenAddr: ""} - stack, err := node.New(&nodeConf) - if err != nil { - // This should never happen, if it does, please open an issue - panic(err) - } - - // Setup ethereum - genesis := core.Genesis{ - Config: params.AllDevChainProtocolChanges, - GasLimit: gasLimit, - Alloc: alloc, - } - conf := ethconfig.Defaults - conf.Genesis = &genesis - conf.SyncMode = downloader.FullSync - sim, err := NewSimWithNode(stack, &conf, math.MaxUint64) - if err != nil { - // This should never happen, if it does, please open an issue - panic(err) - } - return sim -} - -// NewSimWithNode sets up a simulated backend on an existing node -// this allows users to do persistent simulations. -// The provided node must not be started and will be started by NewSimWithNode -func NewSimWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (SimulatedBackend, error) { - backend, err := eth.New(stack, conf) - if err != nil { - return nil, err - } - - // Register the filter system - filterSystem := filters.NewFilterSystem(backend.APIBackend, filters.Config{}) - stack.RegisterAPIs([]rpc.API{{ - Namespace: "eth", - Service: filters.NewFilterAPI(filterSystem, false), - }}) - - // Start the node - if err := stack.Start(); err != nil { - return nil, err - } - - // Set up the simulated beacon - beacon, err := catalyst.NewSimulatedBeacon(blockPeriod, backend) - if err != nil { - return nil, err - } - - // Reorg our chain back to genesis - if err := beacon.Fork(context.Background(), backend.BlockChain().GetCanonicalHash(0)); err != nil { - return nil, err - } - - return &simBackend{ - eth: backend, - SimulatedBeacon: beacon, - Client: ethclient.NewClient(stack.Attach()), - }, nil -} - -func (n *simBackend) Close() error { - if n.Client != nil { - n.Client.Close() - n.Client = nil - } - if n.SimulatedBeacon != nil { - err := n.SimulatedBeacon.Stop() - n.SimulatedBeacon = nil - return err - } - return nil + return SimulatedBackend{simulated.New(alloc, gasLimit)} } diff --git a/ethclient/simulated/backend.go b/ethclient/simulated/backend.go new file mode 100644 index 0000000000..345792eb3e --- /dev/null +++ b/ethclient/simulated/backend.go @@ -0,0 +1,168 @@ +// 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 simulated + +import ( + "context" + "math" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/catalyst" + "github.com/ethereum/go-ethereum/eth/downloader" + "github.com/ethereum/go-ethereum/eth/ethconfig" + "github.com/ethereum/go-ethereum/eth/filters" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/node" + "github.com/ethereum/go-ethereum/p2p" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/rpc" +) + +var _ bind.ContractBackend = (Backend)(nil) +var _ bind.ContractBackend = (*simBackend)(nil) + +type SimChainManagement interface { + // Commit seals a block and moves the chain forward to a new empty block. + Commit() common.Hash + + // Rollback un-sends previously added transactions. + Rollback() + + // Fork sets the head to a new block, which is based on the provided parentHash. + Fork(ctx context.Context, parentHash common.Hash) error + + // AdjustTime changes the block timestamp. + AdjustTime(adjustment time.Duration) error + + // Close closes the backend. You need to call this to clean up resources. + Close() error +} + +// Backend all interfaces in the ethereum package, but is based on a +// simulated blockchain. It is intended for testing purposes. +type Backend interface { + SimChainManagement + + // The backend implements all interfaces in the ethereum package. + ethereum.BlockNumberReader + ethereum.ChainReader + ethereum.ChainStateReader + ethereum.ContractCaller + ethereum.GasEstimator + ethereum.GasPricer + ethereum.GasPricer1559 + ethereum.LogFilterer + ethereum.PendingStateReader + ethereum.PendingContractCaller + ethereum.TransactionReader + ethereum.TransactionSender + ethereum.ChainIDReader +} + +type simBackend struct { + eth *eth.Ethereum + *catalyst.SimulatedBeacon + *ethclient.Client +} + +// New creates a new binding backend using a simulated blockchain +// for testing purposes. +// A simulated backend always uses chainID 1337. +func New(alloc core.GenesisAlloc, gasLimit uint64) Backend { + // Setup the node object + nodeConf := node.DefaultConfig + nodeConf.DataDir = "" + nodeConf.P2P = p2p.Config{DiscAddr: "", ListenAddr: ""} + stack, err := node.New(&nodeConf) + if err != nil { + // This should never happen, if it does, please open an issue + panic(err) + } + + // Setup ethereum + genesis := core.Genesis{ + Config: params.AllDevChainProtocolChanges, + GasLimit: gasLimit, + Alloc: alloc, + } + conf := ethconfig.Defaults + conf.Genesis = &genesis + conf.SyncMode = downloader.FullSync + sim, err := NewWithNode(stack, &conf, math.MaxUint64) + if err != nil { + // This should never happen, if it does, please open an issue + panic(err) + } + return sim +} + +// NewWithNode sets up a simulated backend on an existing node +// this allows users to do persistent simulations. +// The provided node must not be started and will be started by NewWithNode +func NewWithNode(stack *node.Node, conf *eth.Config, blockPeriod uint64) (Backend, error) { + backend, err := eth.New(stack, conf) + if err != nil { + return nil, err + } + + // Register the filter system + filterSystem := filters.NewFilterSystem(backend.APIBackend, filters.Config{}) + stack.RegisterAPIs([]rpc.API{{ + Namespace: "eth", + Service: filters.NewFilterAPI(filterSystem, false), + }}) + + // Start the node + if err := stack.Start(); err != nil { + return nil, err + } + + // Set up the simulated beacon + beacon, err := catalyst.NewSimulatedBeacon(blockPeriod, backend) + if err != nil { + return nil, err + } + + // Reorg our chain back to genesis + if err := beacon.Fork(context.Background(), backend.BlockChain().GetCanonicalHash(0)); err != nil { + return nil, err + } + + return &simBackend{ + eth: backend, + SimulatedBeacon: beacon, + Client: ethclient.NewClient(stack.Attach()), + }, nil +} + +func (n *simBackend) Close() error { + if n.Client != nil { + n.Client.Close() + n.Client = nil + } + if n.SimulatedBeacon != nil { + err := n.SimulatedBeacon.Stop() + n.SimulatedBeacon = nil + return err + } + return nil +} diff --git a/accounts/abi/bind/backends/simulated_test.go b/ethclient/simulated/backend_test.go similarity index 96% rename from accounts/abi/bind/backends/simulated_test.go rename to ethclient/simulated/backend_test.go index da45e0ccdf..fe315d2229 100644 --- a/accounts/abi/bind/backends/simulated_test.go +++ b/ethclient/simulated/backend_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see . -package backends +package simulated import ( "context" @@ -36,15 +36,15 @@ var ( testAddr = crypto.PubkeyToAddress(testKey.PublicKey) ) -func simTestBackend(testAddr common.Address) SimulatedBackend { - return NewSimulatedBackend( +func simTestBackend(testAddr common.Address) Backend { + return New( core.GenesisAlloc{ testAddr: {Balance: big.NewInt(10000000000000000)}, }, 10000000, ) } -func newTx(sim SimulatedBackend, key *ecdsa.PrivateKey) (*types.Transaction, error) { +func newTx(sim Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) { // create a signed transaction to send head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1)) @@ -67,7 +67,7 @@ func newTx(sim SimulatedBackend, key *ecdsa.PrivateKey) (*types.Transaction, err } func TestNewSim(t *testing.T) { - sim := NewSimulatedBackend(core.GenesisAlloc{}, 30_000_000) + sim := New(core.GenesisAlloc{}, 30_000_000) num, err := sim.BlockNumber(context.Background()) if err != nil { t.Fatal(err) @@ -87,7 +87,7 @@ func TestNewSim(t *testing.T) { } func TestAdjustTime(t *testing.T) { - sim := NewSimulatedBackend(core.GenesisAlloc{}, 10_000_000) + sim := New(core.GenesisAlloc{}, 10_000_000) defer sim.Close() block1, _ := sim.BlockByNumber(context.Background(), nil)