github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/eth/catalyst/simulated_beacon_test.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 "math/big" 22 "testing" 23 "time" 24 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/core" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/eth" 30 "github.com/ethereum/go-ethereum/eth/downloader" 31 "github.com/ethereum/go-ethereum/eth/ethconfig" 32 "github.com/ethereum/go-ethereum/miner" 33 "github.com/ethereum/go-ethereum/node" 34 "github.com/ethereum/go-ethereum/p2p" 35 "github.com/ethereum/go-ethereum/params" 36 ) 37 38 func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis) (*node.Node, *eth.Ethereum, *SimulatedBeacon) { 39 t.Helper() 40 41 n, err := node.New(&node.Config{ 42 P2P: p2p.Config{ 43 ListenAddr: "127.0.0.1:8545", 44 NoDiscovery: true, 45 MaxPeers: 0, 46 }, 47 }) 48 if err != nil { 49 t.Fatal("can't create node:", err) 50 } 51 52 ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256, Miner: miner.DefaultConfig} 53 ethservice, err := eth.New(n, ethcfg) 54 if err != nil { 55 t.Fatal("can't create eth service:", err) 56 } 57 58 simBeacon, err := NewSimulatedBeacon(1, ethservice) 59 if err != nil { 60 t.Fatal("can't create simulated beacon:", err) 61 } 62 63 n.RegisterLifecycle(simBeacon) 64 65 if err := n.Start(); err != nil { 66 t.Fatal("can't start node:", err) 67 } 68 69 ethservice.SetSynced() 70 return n, ethservice, simBeacon 71 } 72 73 // send 20 transactions, >10 withdrawals and ensure they are included in order 74 // send enough transactions to fill multiple blocks 75 func TestSimulatedBeaconSendWithdrawals(t *testing.T) { 76 var withdrawals []types.Withdrawal 77 txs := make(map[common.Hash]*types.Transaction) 78 79 var ( 80 // testKey is a private key to use for funding a tester account. 81 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 82 83 // testAddr is the Ethereum address of the tester account. 84 testAddr = crypto.PubkeyToAddress(testKey.PublicKey) 85 ) 86 87 // short period (1 second) for testing purposes 88 var gasLimit uint64 = 10_000_000 89 genesis := core.DeveloperGenesisBlock(gasLimit, &testAddr) 90 node, ethService, mock := startSimulatedBeaconEthService(t, genesis) 91 _ = mock 92 defer node.Close() 93 94 chainHeadCh := make(chan core.ChainHeadEvent, 10) 95 subscription := ethService.BlockChain().SubscribeChainHeadEvent(chainHeadCh) 96 defer subscription.Unsubscribe() 97 98 // generate some withdrawals 99 for i := 0; i < 20; i++ { 100 withdrawals = append(withdrawals, types.Withdrawal{Index: uint64(i)}) 101 if err := mock.withdrawals.add(&withdrawals[i]); err != nil { 102 t.Fatal("addWithdrawal failed", err) 103 } 104 } 105 106 // generate a bunch of transactions 107 signer := types.NewEIP155Signer(ethService.BlockChain().Config().ChainID) 108 for i := 0; i < 20; i++ { 109 tx, err := types.SignTx(types.NewTransaction(uint64(i), common.Address{}, big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, testKey) 110 if err != nil { 111 t.Fatalf("error signing transaction, err=%v", err) 112 } 113 txs[tx.Hash()] = tx 114 115 if err := ethService.APIBackend.SendTx(context.Background(), tx); err != nil { 116 t.Fatal("SendTx failed", err) 117 } 118 } 119 120 includedTxs := make(map[common.Hash]struct{}) 121 var includedWithdrawals []uint64 122 123 timer := time.NewTimer(12 * time.Second) 124 for { 125 select { 126 case evt := <-chainHeadCh: 127 for _, includedTx := range evt.Block.Transactions() { 128 includedTxs[includedTx.Hash()] = struct{}{} 129 } 130 for _, includedWithdrawal := range evt.Block.Withdrawals() { 131 includedWithdrawals = append(includedWithdrawals, includedWithdrawal.Index) 132 } 133 134 // ensure all withdrawals/txs included. this will take two blocks b/c number of withdrawals > 10 135 if len(includedTxs) == len(txs) && len(includedWithdrawals) == len(withdrawals) && evt.Block.Number().Cmp(big.NewInt(2)) == 0 { 136 return 137 } 138 case <-timer.C: 139 t.Fatal("timed out without including all withdrawals/txs") 140 } 141 } 142 }