github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/cmd/puppeth/wizard_genesis.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "io" 24 "math/big" 25 "math/rand" 26 "net/http" 27 "os" 28 "path/filepath" 29 "time" 30 31 "github.com/tirogen/go-ethereum/common" 32 "github.com/tirogen/go-ethereum/core" 33 "github.com/tirogen/go-ethereum/log" 34 "github.com/tirogen/go-ethereum/params" 35 ) 36 37 // makeGenesis creates a new genesis struct based on some user input. 38 func (w *wizard) makeGenesis() { 39 // Construct a default genesis block 40 genesis := &core.Genesis{ 41 Timestamp: uint64(time.Now().Unix()), 42 GasLimit: 4700000, 43 Difficulty: big.NewInt(524288), 44 Alloc: make(core.GenesisAlloc), 45 Config: ¶ms.ChainConfig{ 46 HomesteadBlock: big.NewInt(0), 47 EIP150Block: big.NewInt(0), 48 EIP155Block: big.NewInt(0), 49 EIP158Block: big.NewInt(0), 50 ByzantiumBlock: big.NewInt(0), 51 ConstantinopleBlock: big.NewInt(0), 52 PetersburgBlock: big.NewInt(0), 53 IstanbulBlock: big.NewInt(0), 54 }, 55 } 56 // Figure out which consensus engine to choose 57 fmt.Println() 58 fmt.Println("Which consensus engine to use? (default = clique)") 59 fmt.Println(" 1. Ethash - proof-of-work") 60 fmt.Println(" 2. Clique - proof-of-authority") 61 62 choice := w.read() 63 switch { 64 case choice == "1": 65 // In case of ethash, we're pretty much done 66 genesis.Config.Ethash = new(params.EthashConfig) 67 genesis.ExtraData = make([]byte, 32) 68 69 case choice == "" || choice == "2": 70 // In the case of clique, configure the consensus parameters 71 genesis.Difficulty = big.NewInt(1) 72 genesis.Config.Clique = ¶ms.CliqueConfig{ 73 Period: 15, 74 Epoch: 30000, 75 } 76 fmt.Println() 77 fmt.Println("How many seconds should blocks take? (default = 15)") 78 genesis.Config.Clique.Period = uint64(w.readDefaultInt(15)) 79 80 // We also need the initial list of signers 81 fmt.Println() 82 fmt.Println("Which accounts are allowed to seal? (mandatory at least one)") 83 84 var signers []common.Address 85 for { 86 if address := w.readAddress(); address != nil { 87 signers = append(signers, *address) 88 continue 89 } 90 if len(signers) > 0 { 91 break 92 } 93 } 94 // Sort the signers and embed into the extra-data section 95 for i := 0; i < len(signers); i++ { 96 for j := i + 1; j < len(signers); j++ { 97 if bytes.Compare(signers[i][:], signers[j][:]) > 0 { 98 signers[i], signers[j] = signers[j], signers[i] 99 } 100 } 101 } 102 genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+65) 103 for i, signer := range signers { 104 copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) 105 } 106 107 default: 108 log.Crit("Invalid consensus engine choice", "choice", choice) 109 } 110 // Consensus all set, just ask for initial funds and go 111 fmt.Println() 112 fmt.Println("Which accounts should be pre-funded? (advisable at least one)") 113 for { 114 // Read the address of the account to fund 115 if address := w.readAddress(); address != nil { 116 genesis.Alloc[*address] = core.GenesisAccount{ 117 Balance: new(big.Int).Lsh(big.NewInt(1), 256-7), // 2^256 / 128 (allow many pre-funds without balance overflows) 118 } 119 continue 120 } 121 break 122 } 123 fmt.Println() 124 fmt.Println("Should the precompile-addresses (0x1 .. 0xff) be pre-funded with 1 wei? (advisable yes)") 125 if w.readDefaultYesNo(true) { 126 // Add a batch of precompile balances to avoid them getting deleted 127 for i := int64(0); i < 256; i++ { 128 genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)} 129 } 130 } 131 // Query the user for some custom extras 132 fmt.Println() 133 fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)") 134 genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536)))) 135 136 // All done, store the genesis and flush to disk 137 log.Info("Configured new genesis block") 138 139 w.conf.Genesis = genesis 140 w.conf.flush() 141 } 142 143 // importGenesis imports a Geth genesis spec into puppeth. 144 func (w *wizard) importGenesis() { 145 // Request the genesis JSON spec URL from the user 146 fmt.Println() 147 fmt.Println("Where's the genesis file? (local file or http/https url)") 148 url := w.readURL() 149 150 // Convert the various allowed URLs to a reader stream 151 var reader io.Reader 152 153 switch url.Scheme { 154 case "http", "https": 155 // Remote web URL, retrieve it via an HTTP client 156 res, err := http.Get(url.String()) 157 if err != nil { 158 log.Error("Failed to retrieve remote genesis", "err", err) 159 return 160 } 161 defer res.Body.Close() 162 reader = res.Body 163 164 case "": 165 // Schemaless URL, interpret as a local file 166 file, err := os.Open(url.String()) 167 if err != nil { 168 log.Error("Failed to open local genesis", "err", err) 169 return 170 } 171 defer file.Close() 172 reader = file 173 174 default: 175 log.Error("Unsupported genesis URL scheme", "scheme", url.Scheme) 176 return 177 } 178 // Parse the genesis file and inject it successful 179 var genesis core.Genesis 180 if err := json.NewDecoder(reader).Decode(&genesis); err != nil { 181 log.Error("Invalid genesis spec", "err", err) 182 return 183 } 184 log.Info("Imported genesis block") 185 186 w.conf.Genesis = &genesis 187 w.conf.flush() 188 } 189 190 // manageGenesis permits the modification of chain configuration parameters in 191 // a genesis config and the export of the entire genesis spec. 192 func (w *wizard) manageGenesis() { 193 // Figure out whether to modify or export the genesis 194 fmt.Println() 195 fmt.Println(" 1. Modify existing configurations") 196 fmt.Println(" 2. Export genesis configurations") 197 fmt.Println(" 3. Remove genesis configuration") 198 199 choice := w.read() 200 switch choice { 201 case "1": 202 // Fork rule updating requested, iterate over each fork 203 fmt.Println() 204 fmt.Printf("Which block should Homestead come into effect? (default = %v)\n", w.conf.Genesis.Config.HomesteadBlock) 205 w.conf.Genesis.Config.HomesteadBlock = w.readDefaultBigInt(w.conf.Genesis.Config.HomesteadBlock) 206 207 fmt.Println() 208 fmt.Printf("Which block should EIP150 (Tangerine Whistle) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP150Block) 209 w.conf.Genesis.Config.EIP150Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP150Block) 210 211 fmt.Println() 212 fmt.Printf("Which block should EIP155 (Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP155Block) 213 w.conf.Genesis.Config.EIP155Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP155Block) 214 215 fmt.Println() 216 fmt.Printf("Which block should EIP158/161 (also Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP158Block) 217 w.conf.Genesis.Config.EIP158Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP158Block) 218 219 fmt.Println() 220 fmt.Printf("Which block should Byzantium come into effect? (default = %v)\n", w.conf.Genesis.Config.ByzantiumBlock) 221 w.conf.Genesis.Config.ByzantiumBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ByzantiumBlock) 222 223 fmt.Println() 224 fmt.Printf("Which block should Constantinople come into effect? (default = %v)\n", w.conf.Genesis.Config.ConstantinopleBlock) 225 w.conf.Genesis.Config.ConstantinopleBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ConstantinopleBlock) 226 if w.conf.Genesis.Config.PetersburgBlock == nil { 227 w.conf.Genesis.Config.PetersburgBlock = w.conf.Genesis.Config.ConstantinopleBlock 228 } 229 fmt.Println() 230 fmt.Printf("Which block should Petersburg come into effect? (default = %v)\n", w.conf.Genesis.Config.PetersburgBlock) 231 w.conf.Genesis.Config.PetersburgBlock = w.readDefaultBigInt(w.conf.Genesis.Config.PetersburgBlock) 232 233 fmt.Println() 234 fmt.Printf("Which block should Istanbul come into effect? (default = %v)\n", w.conf.Genesis.Config.IstanbulBlock) 235 w.conf.Genesis.Config.IstanbulBlock = w.readDefaultBigInt(w.conf.Genesis.Config.IstanbulBlock) 236 237 fmt.Println() 238 fmt.Printf("Which block should Berlin come into effect? (default = %v)\n", w.conf.Genesis.Config.BerlinBlock) 239 w.conf.Genesis.Config.BerlinBlock = w.readDefaultBigInt(w.conf.Genesis.Config.BerlinBlock) 240 241 fmt.Println() 242 fmt.Printf("Which block should London come into effect? (default = %v)\n", w.conf.Genesis.Config.LondonBlock) 243 w.conf.Genesis.Config.LondonBlock = w.readDefaultBigInt(w.conf.Genesis.Config.LondonBlock) 244 245 out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ") 246 fmt.Printf("Chain configuration updated:\n\n%s\n", out) 247 248 w.conf.flush() 249 250 case "2": 251 // Save whatever genesis configuration we currently have 252 fmt.Println() 253 fmt.Printf("Which folder to save the genesis spec into? (default = current)\n") 254 fmt.Printf(" Will create %s.json\n", w.network) 255 256 folder := w.readDefaultString(".") 257 if err := os.MkdirAll(folder, 0755); err != nil { 258 log.Error("Failed to create spec folder", "folder", folder, "err", err) 259 return 260 } 261 out, _ := json.MarshalIndent(w.conf.Genesis, "", " ") 262 263 // Export the native genesis spec used by puppeth and Geth 264 gethJson := filepath.Join(folder, fmt.Sprintf("%s.json", w.network)) 265 if err := os.WriteFile(gethJson, out, 0644); err != nil { 266 log.Error("Failed to save genesis file", "err", err) 267 return 268 } 269 log.Info("Saved native genesis chain spec", "path", gethJson) 270 271 case "3": 272 // Make sure we don't have any services running 273 if len(w.conf.servers()) > 0 { 274 log.Error("Genesis reset requires all services and servers torn down") 275 return 276 } 277 log.Info("Genesis block destroyed") 278 279 w.conf.Genesis = nil 280 w.conf.flush() 281 default: 282 log.Error("That's not something I can do") 283 return 284 } 285 }