diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 8344a9fee8..e2b53de213 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -31,6 +31,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/consensus/beacon" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/filtermaps" @@ -71,6 +73,7 @@ type SimulatedBackend struct { database ethdb.Database // In memory database to store our testing data blockchain *core.BlockChain // Ethereum blockchain to handle the consensus + engine consensus.Engine // Consensus engine for block generation mu sync.Mutex pendingBlock *types.Block // Currently pending block that will be imported on request @@ -87,17 +90,32 @@ type SimulatedBackend struct { // and uses a simulated blockchain for testing purposes. // A simulated backend always uses chainID 1337. func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc types.GenesisAlloc, gasLimit uint64) *SimulatedBackend { + return NewSimulatedBackendWithConfig(database, alloc, gasLimit, params.AllEthashProtocolChanges) +} + +// NewSimulatedBackendWithConfig creates a new binding backend based on the given database +// and chain config. Use this when you need features from newer EVM versions (e.g., PUSH0 from Shanghai). +func NewSimulatedBackendWithConfig(database ethdb.Database, alloc types.GenesisAlloc, gasLimit uint64, config *params.ChainConfig) *SimulatedBackend { genesis := core.Genesis{ - Config: params.AllEthashProtocolChanges, + Config: config, GasLimit: gasLimit, Alloc: alloc, } - blockchain, _ := core.NewBlockChain(database, &genesis, ethash.NewFaker(), core.DefaultConfig()) + // Use beacon.NewFaker() for post-merge configs (Shanghai+), ethash.NewFaker() otherwise + var engine consensus.Engine + if config.ShanghaiBlock != nil { + engine = beacon.NewFaker() + } else { + engine = ethash.NewFaker() + } + + blockchain, _ := core.NewBlockChain(database, &genesis, engine, core.DefaultConfig()) backend := &SimulatedBackend{ database: database, blockchain: blockchain, + engine: engine, config: genesis.Config, } @@ -155,7 +173,7 @@ func (b *SimulatedBackend) Rollback() { } func (b *SimulatedBackend) rollback(parent *types.Block) { - blocks, _ := core.GenerateChain(b.config, parent, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}) + blocks, _ := core.GenerateChain(b.config, parent, b.engine, b.database, 1, func(int, *core.BlockGen) {}) b.pendingBlock = blocks[0] b.pendingState, _ = state.New(b.pendingBlock.Root(), b.blockchain.StateCache()) @@ -687,6 +705,10 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM if call.Gas == 0 { call.Gas = 10 * header.GasLimit } + // Cap gas to protocol limit to avoid exceeding MaxTxGas + if call.Gas > params.MaxTxGas { + call.Gas = params.MaxTxGas + } if call.Value == nil { call.Value = new(big.Int) } @@ -739,7 +761,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa return fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce) } // Include tx in chain - blocks, receipts := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { + blocks, receipts := core.GenerateChain(b.config, block, b.engine, b.database, 1, func(number int, block *core.BlockGen) { for _, tx := range b.pendingBlock.Transactions() { block.AddTxWithChain(b.blockchain, tx) } @@ -770,7 +792,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter if query.FromBlock != nil { from = query.FromBlock.Int64() } - to := int64(-1) + to := int64(rpc.LatestBlockNumber) if query.ToBlock != nil { to = query.ToBlock.Int64() } @@ -865,7 +887,7 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { return errors.New("could not find parent") } - blocks, _ := core.GenerateChain(b.config, block, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { + blocks, _ := core.GenerateChain(b.config, block, b.engine, b.database, 1, func(number int, block *core.BlockGen) { block.OffsetTime(int64(adjustment.Seconds())) }) stateDB, err := b.blockchain.State() @@ -967,19 +989,23 @@ func (fb *filterBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 } func (fb *filterBackend) ChainConfig() *params.ChainConfig { - panic("not supported") + return fb.bc.Config() } func (fb *filterBackend) CurrentHeader() *types.Header { - panic("not supported") + return fb.bc.CurrentHeader() } func (fb *filterBackend) NewMatcherBackend() filtermaps.MatcherBackend { - panic("not supported") + return &simulatedMatcherBackend{bc: fb.bc} } func (fb *filterBackend) CurrentView() *filtermaps.ChainView { - panic("implement me") + head := fb.bc.CurrentBlock() + if head == nil { + return nil + } + return filtermaps.NewChainView(fb.bc, head.Number.Uint64(), head.Hash()) } func (fb *filterBackend) HistoryPruningCutoff() uint64 { @@ -992,3 +1018,41 @@ func nullSubscription() event.Subscription { return nil }) } + +// simulatedMatcherBackend implements filtermaps.MatcherBackend for simulated backend. +// It returns empty indexed ranges to force unindexed search, which works correctly +// for simulated backends without needing full FilterMaps indexing. +type simulatedMatcherBackend struct { + bc *core.BlockChain +} + +func (s *simulatedMatcherBackend) GetParams() *filtermaps.Params { + return nil +} + +func (s *simulatedMatcherBackend) GetBlockLvPointer(ctx context.Context, blockNumber uint64) (uint64, error) { + return 0, nil +} + +func (s *simulatedMatcherBackend) GetFilterMapRows(ctx context.Context, mapIndices []uint32, rowIndex uint32, baseLayerOnly bool) ([]filtermaps.FilterRow, error) { + return nil, nil +} + +func (s *simulatedMatcherBackend) GetLogByLvIndex(ctx context.Context, lvIndex uint64) (*types.Log, error) { + return nil, nil +} + +func (s *simulatedMatcherBackend) SyncLogIndex(ctx context.Context) (filtermaps.SyncRange, error) { + head := s.bc.CurrentBlock() + if head == nil { + return filtermaps.SyncRange{}, nil + } + // Return empty IndexedBlocks to force unindexed search + return filtermaps.SyncRange{ + IndexedView: nil, + ValidBlocks: common.Range[uint64]{}, + IndexedBlocks: common.Range[uint64]{}, + }, nil +} + +func (s *simulatedMatcherBackend) Close() {} diff --git a/accounts/abi/bind/v2/lib_test.go b/accounts/abi/bind/v2/lib_test.go index 55414ed65d..12b1abf4c9 100644 --- a/accounts/abi/bind/v2/lib_test.go +++ b/accounts/abi/bind/v2/lib_test.go @@ -28,61 +28,44 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/v2/internal/contracts/nested_libraries" "github.com/ethereum/go-ethereum/accounts/abi/bind/v2/internal/contracts/solc_errors" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/ethclient/simulated" - "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" ) var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") var testAddr = crypto.PubkeyToAddress(testKey.PublicKey) +var testChainID = big.NewInt(1337) -func testSetup() (*backends.SimulatedBackend, error) { - backend := simulated.NewBackend( +func testSetup() *backends.SimulatedBackend { + return backends.NewSimulatedBackendWithConfig( + rawdb.NewMemoryDatabase(), types.GenesisAlloc{ testAddr: {Balance: big.NewInt(1000000000000000000)}, }, - func(nodeConf *node.Config, ethConf *ethconfig.Config) { - ethConf.Genesis.Difficulty = big.NewInt(0) - }, + 60000000, + params.MergedTestChainConfig, ) - - // we should just be able to use the backend directly, instead of using - // this deprecated interface. However, the simulated backend no longer - // implements backends.SimulatedBackend... - bindBackend := backends.SimulatedBackend{ - Backend: backend, - Client: backend.Client(), - } - return &bindBackend, nil } -func makeTestDeployer(backend simulated.Client) func(input, deployer []byte) (common.Address, *types.Transaction, error) { - chainId, _ := backend.ChainID(context.Background()) - return bind.DefaultDeployer(bind.NewKeyedTransactor(testKey, chainId), backend) +func makeTestDeployer(backend *backends.SimulatedBackend) func(input, deployer []byte) (common.Address, *types.Transaction, error) { + return bind.DefaultDeployer(bind.NewKeyedTransactor(testKey, testChainID), backend) } // makeTestDeployerWithNonceAssignment is similar to makeTestDeployer, // but it returns a deployer that automatically tracks nonce, // enabling the deployment of multiple contracts from the same account. -func makeTestDeployerWithNonceAssignment(backend simulated.Client) func(input, deployer []byte) (common.Address, *types.Transaction, error) { - chainId, _ := backend.ChainID(context.Background()) - return bind.DeployerWithNonceAssignment(bind.NewKeyedTransactor(testKey, chainId), backend) +func makeTestDeployerWithNonceAssignment(backend *backends.SimulatedBackend) func(input, deployer []byte) (common.Address, *types.Transaction, error) { + return bind.DeployerWithNonceAssignment(bind.NewKeyedTransactor(testKey, testChainID), backend) } // test that deploying a contract with library dependencies works, // verifying by calling method on the deployed contract. func TestDeploymentLibraries(t *testing.T) { - // TODO - bor: refactor and enable (task: POS-3046) - t.Skip("bor: Skipping all tests for now. To be fixed later") - bindBackend, err := testSetup() - if err != nil { - t.Fatalf("err setting up test: %v", err) - } - defer bindBackend.Backend.Close() + bindBackend := testSetup() + defer bindBackend.Close() c := nested_libraries.NewC1() constructorInput := c.PackConstructor(big.NewInt(42), big.NewInt(1)) @@ -90,7 +73,7 @@ func TestDeploymentLibraries(t *testing.T) { Contracts: []*bind.MetaData{&nested_libraries.C1MetaData}, Inputs: map[string][]byte{nested_libraries.C1MetaData.ID: constructorInput}, } - res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployerWithNonceAssignment(bindBackend.Client)) + res, err := bind.LinkAndDeploy(deploymentParams, makeTestDeployerWithNonceAssignment(bindBackend)) if err != nil { t.Fatalf("err: %+v\n", err) } @@ -122,13 +105,8 @@ func TestDeploymentLibraries(t *testing.T) { // Same as TestDeployment. However, stagger the deployments with overrides: // first deploy the library deps and then the contract. func TestDeploymentWithOverrides(t *testing.T) { - // TODO - bor: refactor and enable (task: POS-3046) - t.Skip("bor: Skipping all tests for now. To be fixed later") - bindBackend, err := testSetup() - if err != nil { - t.Fatalf("err setting up test: %v", err) - } - defer bindBackend.Backend.Close() + bindBackend := testSetup() + defer bindBackend.Close() // deploy all the library dependencies of our target contract, but not the target contract itself. deploymentParams := &bind.DeploymentParams{ @@ -191,7 +169,7 @@ func TestDeploymentWithOverrides(t *testing.T) { // returns transaction auth to send a basic transaction from testAddr func defaultTxAuth() *bind.TransactOpts { - signer := types.LatestSigner(params.AllDevChainProtocolChanges) + signer := types.LatestSigner(params.MergedTestChainConfig) opts := &bind.TransactOpts{ From: testAddr, Nonce: nil, @@ -212,13 +190,9 @@ func defaultTxAuth() *bind.TransactOpts { } func TestEvents(t *testing.T) { - // TODO - bor: refactor and enable (task: POS-3046) - t.Skip("bor: Skipping all tests for now. To be fixed later") // test watch/filter logs method on a contract that emits various kinds of events (struct-containing, etc.) - backend, err := testSetup() - if err != nil { - t.Fatalf("error setting up testing env: %v", err) - } + backend := testSetup() + defer backend.Close() deploymentParams := &bind.DeploymentParams{ Contracts: []*bind.MetaData{&events.CMetaData}, } @@ -321,13 +295,10 @@ done: } func TestErrors(t *testing.T) { - // TODO - bor: refactor and enable (task: POS-3046) - t.Skip("bor: Skipping all tests for now. To be fixed later") // test watch/filter logs method on a contract that emits various kinds of events (struct-containing, etc.) - backend, err := testSetup() - if err != nil { - t.Fatalf("error setting up testing env: %v", err) - } + backend := testSetup() + defer backend.Close() + deploymentParams := &bind.DeploymentParams{ Contracts: []*bind.MetaData{&solc_errors.CMetaData}, } @@ -344,7 +315,7 @@ func TestErrors(t *testing.T) { c := solc_errors.NewC() instance := c.Instance(backend, res.Addresses[solc_errors.CMetaData.ID]) packedInput := c.PackFoo() - opts := &bind.CallOpts{From: res.Addresses[solc_errors.CMetaData.ID]} + opts := &bind.CallOpts{From: testAddr} _, err = bind.Call[struct{}](instance, opts, packedInput, nil) if err == nil { t.Fatalf("expected call to fail") diff --git a/params/config.go b/params/config.go index 62258790bd..aa442cc60e 100644 --- a/params/config.go +++ b/params/config.go @@ -671,8 +671,9 @@ var ( // MergedTestChainConfig contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers for testing purposes. + // Includes all Bor hard forks enabled at block 0. MergedTestChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), + ChainID: big.NewInt(1337), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, @@ -703,10 +704,24 @@ var ( Osaka: DefaultOsakaBlobConfig, }, Bor: &BorConfig{ - Sprint: map[string]uint64{ - "0": 4}, - BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}, - Period: map[string]uint64{"0": 2}, + Sprint: map[string]uint64{"0": 4}, + Period: map[string]uint64{"0": 2}, + ProducerDelay: map[string]uint64{"0": 1}, + BackupMultiplier: map[string]uint64{"0": 2}, + ValidatorContract: "0x0000000000000000000000000000000000001000", + StateReceiverContract: "0x0000000000000000000000000000000000001001", + BurntContract: map[string]string{"0": "0x000000000000000000000000000000000000dead"}, + BlockAlloc: map[string]interface{}{}, + // Bor hard forks + JaipurBlock: big.NewInt(0), + DelhiBlock: big.NewInt(0), + IndoreBlock: big.NewInt(0), + AhmedabadBlock: big.NewInt(0), + BhilaiBlock: big.NewInt(0), + RioBlock: big.NewInt(0), + MadhugiriBlock: big.NewInt(0), + MadhugiriProBlock: big.NewInt(0), + DandeliBlock: big.NewInt(0), }, }