github.com/carter-ya/go-ethereum@v0.0.0-20230628080049-d2309be3983b/miner/stress/clique/main.go (about) 1 // Copyright 2018 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 based on the Clique consensus engine. 18 package main 19 20 import ( 21 "bytes" 22 "crypto/ecdsa" 23 "math/big" 24 "math/rand" 25 "os" 26 "os/signal" 27 "time" 28 29 "github.com/ethereum/go-ethereum/accounts/keystore" 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/common/fdlimit" 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 func main() { 47 log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) 48 fdlimit.Raise(2048) 49 50 // Generate a batch of accounts to seal and fund with 51 faucets := make([]*ecdsa.PrivateKey, 128) 52 for i := 0; i < len(faucets); i++ { 53 faucets[i], _ = crypto.GenerateKey() 54 } 55 sealers := make([]*ecdsa.PrivateKey, 4) 56 for i := 0; i < len(sealers); i++ { 57 sealers[i], _ = crypto.GenerateKey() 58 } 59 // Create a Clique network based off of the Rinkeby config 60 genesis := makeGenesis(faucets, sealers) 61 62 // Handle interrupts. 63 interruptCh := make(chan os.Signal, 5) 64 signal.Notify(interruptCh, os.Interrupt) 65 66 var ( 67 stacks []*node.Node 68 nodes []*eth.Ethereum 69 enodes []*enode.Node 70 ) 71 for _, sealer := range sealers { 72 // Start the node and wait until it's up 73 stack, ethBackend, err := makeSealer(genesis) 74 if err != nil { 75 panic(err) 76 } 77 defer stack.Close() 78 79 for stack.Server().NodeInfo().Ports.Listener == 0 { 80 time.Sleep(250 * time.Millisecond) 81 } 82 // Connect the node to all the previous ones 83 for _, n := range enodes { 84 stack.Server().AddPeer(n) 85 } 86 // Start tracking the node and its enode 87 stacks = append(stacks, stack) 88 nodes = append(nodes, ethBackend) 89 enodes = append(enodes, stack.Server().Self()) 90 91 // Inject the signer key and start sealing with it 92 ks := keystore.NewKeyStore(stack.KeyStoreDir(), keystore.LightScryptN, keystore.LightScryptP) 93 signer, err := ks.ImportECDSA(sealer, "") 94 if err != nil { 95 panic(err) 96 } 97 if err := ks.Unlock(signer, ""); err != nil { 98 panic(err) 99 } 100 stack.AccountManager().AddBackend(ks) 101 } 102 103 // Iterate over all the nodes and start signing on them 104 time.Sleep(3 * time.Second) 105 for _, node := range nodes { 106 if err := node.StartMining(1); err != nil { 107 panic(err) 108 } 109 } 110 time.Sleep(3 * time.Second) 111 112 // Start injecting transactions from the faucet like crazy 113 nonces := make([]uint64, len(faucets)) 114 for { 115 // Stop when interrupted. 116 select { 117 case <-interruptCh: 118 for _, node := range stacks { 119 node.Close() 120 } 121 return 122 default: 123 } 124 125 // Pick a random signer node 126 index := rand.Intn(len(faucets)) 127 backend := nodes[index%len(nodes)] 128 129 // Create a self transaction and inject into the pool 130 tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000), nil), types.HomesteadSigner{}, faucets[index]) 131 if err != nil { 132 panic(err) 133 } 134 if err := backend.TxPool().AddLocal(tx); err != nil { 135 panic(err) 136 } 137 nonces[index]++ 138 139 // Wait if we're too saturated 140 if pend, _ := backend.TxPool().Stats(); pend > 2048 { 141 time.Sleep(100 * time.Millisecond) 142 } 143 } 144 } 145 146 // makeGenesis creates a custom Clique genesis block based on some pre-defined 147 // signer and faucet accounts. 148 func makeGenesis(faucets []*ecdsa.PrivateKey, sealers []*ecdsa.PrivateKey) *core.Genesis { 149 // Create a Clique network based off of the Rinkeby config 150 genesis := core.DefaultRinkebyGenesisBlock() 151 genesis.GasLimit = 25000000 152 153 genesis.Config.ChainID = big.NewInt(18) 154 genesis.Config.Clique.Period = 1 155 genesis.Config.EIP150Hash = common.Hash{} 156 157 genesis.Alloc = core.GenesisAlloc{} 158 for _, faucet := range faucets { 159 genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = core.GenesisAccount{ 160 Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), 161 } 162 } 163 // Sort the signers and embed into the extra-data section 164 signers := make([]common.Address, len(sealers)) 165 for i, sealer := range sealers { 166 signers[i] = crypto.PubkeyToAddress(sealer.PublicKey) 167 } 168 for i := 0; i < len(signers); i++ { 169 for j := i + 1; j < len(signers); j++ { 170 if bytes.Compare(signers[i][:], signers[j][:]) > 0 { 171 signers[i], signers[j] = signers[j], signers[i] 172 } 173 } 174 } 175 genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+65) 176 for i, signer := range signers { 177 copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) 178 } 179 // Return the genesis block for initialization 180 return genesis 181 } 182 183 func makeSealer(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { 184 // Define the basic configurations for the Ethereum node 185 datadir, _ := os.MkdirTemp("", "") 186 187 config := &node.Config{ 188 Name: "geth", 189 Version: params.Version, 190 DataDir: datadir, 191 P2P: p2p.Config{ 192 ListenAddr: "0.0.0.0:0", 193 NoDiscovery: true, 194 MaxPeers: 25, 195 }, 196 } 197 // Start the node and configure a full Ethereum node on it 198 stack, err := node.New(config) 199 if err != nil { 200 return nil, nil, err 201 } 202 // Create and register the backend 203 ethBackend, err := eth.New(stack, ðconfig.Config{ 204 Genesis: genesis, 205 NetworkId: genesis.Config.ChainID.Uint64(), 206 SyncMode: downloader.FullSync, 207 DatabaseCache: 256, 208 DatabaseHandles: 256, 209 TxPool: core.DefaultTxPoolConfig, 210 GPO: ethconfig.Defaults.GPO, 211 Miner: miner.Config{ 212 GasCeil: genesis.GasLimit * 11 / 10, 213 GasPrice: big.NewInt(1), 214 Recommit: time.Second, 215 }, 216 }) 217 if err != nil { 218 return nil, nil, err 219 } 220 221 err = stack.Start() 222 return stack, ethBackend, err 223 }