github.com/shrimpyuk/bor@v0.2.15-0.20220224151350-fb4ec6020bae/miner/stress/1559/main.go (about) 1 // Copyright 2021 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 // This file contains a miner stress test for eip 1559. 18 package main 19 20 import ( 21 "crypto/ecdsa" 22 "io/ioutil" 23 "math/big" 24 "math/rand" 25 "os" 26 "os/signal" 27 "time" 28 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/common/fdlimit" 31 "github.com/ethereum/go-ethereum/consensus/ethash" 32 "github.com/ethereum/go-ethereum/core" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/crypto" 35 "github.com/ethereum/go-ethereum/eth" 36 "github.com/ethereum/go-ethereum/eth/downloader" 37 "github.com/ethereum/go-ethereum/eth/ethconfig" 38 "github.com/ethereum/go-ethereum/log" 39 "github.com/ethereum/go-ethereum/miner" 40 "github.com/ethereum/go-ethereum/node" 41 "github.com/ethereum/go-ethereum/p2p" 42 "github.com/ethereum/go-ethereum/p2p/enode" 43 "github.com/ethereum/go-ethereum/params" 44 ) 45 46 var ( 47 londonBlock = big.NewInt(30) // Predefined london fork block for activating eip 1559. 48 ) 49 50 func main() { 51 log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 52 fdlimit.Raise(2048) 53 54 // Generate a batch of accounts to seal and fund with 55 faucets := make([]*ecdsa.PrivateKey, 128) 56 for i := 0; i < len(faucets); i++ { 57 faucets[i], _ = crypto.GenerateKey() 58 } 59 // Pre-generate the ethash mining DAG so we don't race 60 ethash.MakeDataset(1, ethconfig.Defaults.Ethash.DatasetDir) 61 62 // Create an Ethash network based off of the Ropsten config 63 genesis := makeGenesis(faucets) 64 65 // Handle interrupts. 66 interruptCh := make(chan os.Signal, 5) 67 signal.Notify(interruptCh, os.Interrupt) 68 69 var ( 70 stacks []*node.Node 71 nodes []*eth.Ethereum 72 enodes []*enode.Node 73 ) 74 for i := 0; i < 4; i++ { 75 // Start the node and wait until it's up 76 stack, ethBackend, err := makeMiner(genesis) 77 if err != nil { 78 panic(err) 79 } 80 defer stack.Close() 81 82 for stack.Server().NodeInfo().Ports.Listener == 0 { 83 time.Sleep(250 * time.Millisecond) 84 } 85 // Connect the node to all the previous ones 86 for _, n := range enodes { 87 stack.Server().AddPeer(n) 88 } 89 // Start tracking the node and its enode 90 nodes = append(nodes, ethBackend) 91 enodes = append(enodes, stack.Server().Self()) 92 } 93 94 // Iterate over all the nodes and start mining 95 time.Sleep(3 * time.Second) 96 for _, node := range nodes { 97 if err := node.StartMining(1); err != nil { 98 panic(err) 99 } 100 } 101 time.Sleep(3 * time.Second) 102 103 // Start injecting transactions from the faucets like crazy 104 var ( 105 nonces = make([]uint64, len(faucets)) 106 107 // The signer activates the 1559 features even before the fork, 108 // so the new 1559 txs can be created with this signer. 109 signer = types.LatestSignerForChainID(genesis.Config.ChainID) 110 ) 111 for { 112 // Stop when interrupted. 113 select { 114 case <-interruptCh: 115 for _, node := range stacks { 116 node.Close() 117 } 118 return 119 default: 120 } 121 122 // Pick a random mining node 123 index := rand.Intn(len(faucets)) 124 backend := nodes[index%len(nodes)] 125 126 headHeader := backend.BlockChain().CurrentHeader() 127 baseFee := headHeader.BaseFee 128 129 // Create a self transaction and inject into the pool. The legacy 130 // and 1559 transactions can all be created by random even if the 131 // fork is not happened. 132 tx := makeTransaction(nonces[index], faucets[index], signer, baseFee) 133 if err := backend.TxPool().AddLocal(tx); err != nil { 134 continue 135 } 136 nonces[index]++ 137 138 // Wait if we're too saturated 139 if pend, _ := backend.TxPool().Stats(); pend > 4192 { 140 time.Sleep(100 * time.Millisecond) 141 } 142 143 // Wait if the basefee is raised too fast 144 if baseFee != nil && baseFee.Cmp(new(big.Int).Mul(big.NewInt(100), big.NewInt(params.GWei))) > 0 { 145 time.Sleep(500 * time.Millisecond) 146 } 147 } 148 } 149 150 func makeTransaction(nonce uint64, privKey *ecdsa.PrivateKey, signer types.Signer, baseFee *big.Int) *types.Transaction { 151 // Generate legacy transaction 152 if rand.Intn(2) == 0 { 153 tx, err := types.SignTx(types.NewTransaction(nonce, crypto.PubkeyToAddress(privKey.PublicKey), new(big.Int), 21000, big.NewInt(100000000000+rand.Int63n(65536)), nil), signer, privKey) 154 if err != nil { 155 panic(err) 156 } 157 return tx 158 } 159 // Generate eip 1559 transaction 160 recipient := crypto.PubkeyToAddress(privKey.PublicKey) 161 162 // Feecap and feetip are limited to 32 bytes. Offer a sightly 163 // larger buffer for creating both valid and invalid transactions. 164 var buf = make([]byte, 32+5) 165 rand.Read(buf) 166 gasTipCap := new(big.Int).SetBytes(buf) 167 168 // If the given base fee is nil(the 1559 is still not available), 169 // generate a fake base fee in order to create 1559 tx forcibly. 170 if baseFee == nil { 171 baseFee = new(big.Int).SetInt64(int64(rand.Int31())) 172 } 173 // Generate the feecap, 75% valid feecap and 25% unguaranted. 174 var gasFeeCap *big.Int 175 if rand.Intn(4) == 0 { 176 rand.Read(buf) 177 gasFeeCap = new(big.Int).SetBytes(buf) 178 } else { 179 gasFeeCap = new(big.Int).Add(baseFee, gasTipCap) 180 } 181 return types.MustSignNewTx(privKey, signer, &types.DynamicFeeTx{ 182 ChainID: signer.ChainID(), 183 Nonce: nonce, 184 GasTipCap: gasTipCap, 185 GasFeeCap: gasFeeCap, 186 Gas: 21000, 187 To: &recipient, 188 Value: big.NewInt(100), 189 Data: nil, 190 AccessList: nil, 191 }) 192 } 193 194 // makeGenesis creates a custom Ethash genesis block based on some pre-defined 195 // faucet accounts. 196 func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { 197 genesis := core.DefaultRopstenGenesisBlock() 198 199 genesis.Config = params.AllEthashProtocolChanges 200 genesis.Config.LondonBlock = londonBlock 201 genesis.Difficulty = params.MinimumDifficulty 202 203 // Small gaslimit for easier basefee moving testing. 204 genesis.GasLimit = 8_000_000 205 206 genesis.Config.ChainID = big.NewInt(18) 207 genesis.Config.EIP150Hash = common.Hash{} 208 209 genesis.Alloc = core.GenesisAlloc{} 210 for _, faucet := range faucets { 211 genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = core.GenesisAccount{ 212 Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), 213 } 214 } 215 if londonBlock.Sign() == 0 { 216 log.Info("Enabled the eip 1559 by default") 217 } else { 218 log.Info("Registered the london fork", "number", londonBlock) 219 } 220 return genesis 221 } 222 223 func makeMiner(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { 224 // Define the basic configurations for the Ethereum node 225 datadir, _ := ioutil.TempDir("", "") 226 227 config := &node.Config{ 228 Name: "geth", 229 Version: params.Version, 230 DataDir: datadir, 231 P2P: p2p.Config{ 232 ListenAddr: "0.0.0.0:0", 233 NoDiscovery: true, 234 MaxPeers: 25, 235 }, 236 UseLightweightKDF: true, 237 } 238 // Create the node and configure a full Ethereum node on it 239 stack, err := node.New(config) 240 if err != nil { 241 return nil, nil, err 242 } 243 ethBackend, err := eth.New(stack, ðconfig.Config{ 244 Genesis: genesis, 245 NetworkId: genesis.Config.ChainID.Uint64(), 246 SyncMode: downloader.FullSync, 247 DatabaseCache: 256, 248 DatabaseHandles: 256, 249 TxPool: core.DefaultTxPoolConfig, 250 GPO: ethconfig.Defaults.GPO, 251 Ethash: ethconfig.Defaults.Ethash, 252 Miner: miner.Config{ 253 Etherbase: common.Address{1}, 254 GasCeil: genesis.GasLimit * 11 / 10, 255 GasPrice: big.NewInt(1), 256 Recommit: time.Second, 257 }, 258 }) 259 if err != nil { 260 return nil, nil, err 261 } 262 err = stack.Start() 263 return stack, ethBackend, err 264 }