| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | // Copyright 2018 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // +build none | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This file contains a miner stress test based on the Ethash consensus engine. | 
					
						
							|  |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"crypto/ecdsa" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"math/rand" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/accounts/keystore" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common/fdlimit" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/consensus/ethash" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/eth" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/eth/downloader" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2019-12-10 16:26:07 +08:00
										 |  |  | 	"github.com/ethereum/go-ethereum/miner" | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/node" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p" | 
					
						
							| 
									
										
										
										
											2018-11-07 09:55:56 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p/enode" | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func main() { | 
					
						
							|  |  |  | 	log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true)))) | 
					
						
							|  |  |  | 	fdlimit.Raise(2048) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Generate a batch of accounts to seal and fund with | 
					
						
							|  |  |  | 	faucets := make([]*ecdsa.PrivateKey, 128) | 
					
						
							|  |  |  | 	for i := 0; i < len(faucets); i++ { | 
					
						
							|  |  |  | 		faucets[i], _ = crypto.GenerateKey() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Pre-generate the ethash mining DAG so we don't race | 
					
						
							|  |  |  | 	ethash.MakeDataset(1, filepath.Join(os.Getenv("HOME"), ".ethash")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Create an Ethash network based off of the Ropsten config | 
					
						
							|  |  |  | 	genesis := makeGenesis(faucets) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		nodes  []*eth.Ethereum | 
					
						
							| 
									
										
										
										
											2018-11-07 09:55:56 +01:00
										 |  |  | 		enodes []*enode.Node | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	for i := 0; i < 4; i++ { | 
					
						
							|  |  |  | 		// Start the node and wait until it's up | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		stack, ethBackend, err := makeMiner(genesis) | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		defer stack.Close() | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		for stack.Server().NodeInfo().Ports.Listener == 0 { | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 			time.Sleep(250 * time.Millisecond) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		// Connect the node to all the previous ones | 
					
						
							| 
									
										
										
										
											2018-11-07 09:55:56 +01:00
										 |  |  | 		for _, n := range enodes { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 			stack.Server().AddPeer(n) | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		// Start tracking the node and its enode | 
					
						
							|  |  |  | 		nodes = append(nodes, ethBackend) | 
					
						
							|  |  |  | 		enodes = append(enodes, stack.Server().Self()) | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Inject the signer key and start sealing with it | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		store := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 		if _, err := store.NewAccount(""); err != nil { | 
					
						
							|  |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// Iterate over all the nodes and start mining | 
					
						
							|  |  |  | 	time.Sleep(3 * time.Second) | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	for _, node := range nodes { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		if err := node.StartMining(1); err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	time.Sleep(3 * time.Second) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Start injecting transactions from the faucets like crazy | 
					
						
							|  |  |  | 	nonces := make([]uint64, len(faucets)) | 
					
						
							|  |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		// Pick a random mining node | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 		index := rand.Intn(len(faucets)) | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		backend := nodes[index%len(nodes)] | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Create a self transaction and inject into the pool | 
					
						
							|  |  |  | 		tx, err := types.SignTx(types.NewTransaction(nonces[index], crypto.PubkeyToAddress(faucets[index].PublicKey), new(big.Int), 21000, big.NewInt(100000000000+rand.Int63n(65536)), nil), types.HomesteadSigner{}, faucets[index]) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		if err := backend.TxPool().AddLocal(tx); err != nil { | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 			panic(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		nonces[index]++ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Wait if we're too saturated | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		if pend, _ := backend.TxPool().Stats(); pend > 2048 { | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 			time.Sleep(100 * time.Millisecond) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // makeGenesis creates a custom Ethash genesis block based on some pre-defined | 
					
						
							|  |  |  | // faucet accounts. | 
					
						
							|  |  |  | func makeGenesis(faucets []*ecdsa.PrivateKey) *core.Genesis { | 
					
						
							| 
									
										
										
										
											2020-04-09 11:09:58 +02:00
										 |  |  | 	genesis := core.DefaultRopstenGenesisBlock() | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	genesis.Difficulty = params.MinimumDifficulty | 
					
						
							|  |  |  | 	genesis.GasLimit = 25000000 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	genesis.Config.ChainID = big.NewInt(18) | 
					
						
							|  |  |  | 	genesis.Config.EIP150Hash = common.Hash{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	genesis.Alloc = core.GenesisAlloc{} | 
					
						
							|  |  |  | 	for _, faucet := range faucets { | 
					
						
							|  |  |  | 		genesis.Alloc[crypto.PubkeyToAddress(faucet.PublicKey)] = core.GenesisAccount{ | 
					
						
							|  |  |  | 			Balance: new(big.Int).Exp(big.NewInt(2), big.NewInt(128), nil), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return genesis | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | func makeMiner(genesis *core.Genesis) (*node.Node, *eth.Ethereum, error) { | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	// Define the basic configurations for the Ethereum node | 
					
						
							|  |  |  | 	datadir, _ := ioutil.TempDir("", "") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	config := &node.Config{ | 
					
						
							|  |  |  | 		Name:    "geth", | 
					
						
							|  |  |  | 		Version: params.Version, | 
					
						
							|  |  |  | 		DataDir: datadir, | 
					
						
							|  |  |  | 		P2P: p2p.Config{ | 
					
						
							|  |  |  | 			ListenAddr:  "0.0.0.0:0", | 
					
						
							|  |  |  | 			NoDiscovery: true, | 
					
						
							|  |  |  | 			MaxPeers:    25, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		UseLightweightKDF: true, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 	// Create the node and configure a full Ethereum node on it | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	stack, err := node.New(config) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		return nil, nil, err | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-05 20:51:15 +08:00
										 |  |  | 	ethBackend, err := eth.New(stack, ðconfig.Config{ | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 		Genesis:         genesis, | 
					
						
							|  |  |  | 		NetworkId:       genesis.Config.ChainID.Uint64(), | 
					
						
							|  |  |  | 		SyncMode:        downloader.FullSync, | 
					
						
							|  |  |  | 		DatabaseCache:   256, | 
					
						
							|  |  |  | 		DatabaseHandles: 256, | 
					
						
							|  |  |  | 		TxPool:          core.DefaultTxPoolConfig, | 
					
						
							|  |  |  | 		GPO:             eth.DefaultConfig.GPO, | 
					
						
							|  |  |  | 		Ethash:          eth.DefaultConfig.Ethash, | 
					
						
							|  |  |  | 		Miner: miner.Config{ | 
					
						
							|  |  |  | 			GasFloor: genesis.GasLimit * 9 / 10, | 
					
						
							|  |  |  | 			GasCeil:  genesis.GasLimit * 11 / 10, | 
					
						
							|  |  |  | 			GasPrice: big.NewInt(1), | 
					
						
							|  |  |  | 			Recommit: time.Second, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, nil, err | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 19:40:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	err = stack.Start() | 
					
						
							|  |  |  | 	return stack, ethBackend, err | 
					
						
							| 
									
										
										
										
											2018-08-23 14:03:13 +03:00
										 |  |  | } |