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