main.go 7.8 KB

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