github.com/hhwill/poc-eth@v0.0.0-20240218063348-3bb107c90dbf/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 "io/ioutil" 25 "math/big" 26 "math/rand" 27 "net/http" 28 "os" 29 "path/filepath" 30 "time" 31 32 "github.com/ethereum/go-ethereum/common" 33 "github.com/ethereum/go-ethereum/core" 34 "github.com/ethereum/go-ethereum/log" 35 "github.com/ethereum/go-ethereum/params" 36 ) 37 38 // makeGenesis creates a new genesis struct based on some user input. 39 func (w *wizard) makeGenesis() { 40 // Construct a default genesis block 41 genesis := &core.Genesis{ 42 Timestamp: uint64(time.Now().Unix()), 43 GasLimit: 4700000, 44 Difficulty: big.NewInt(524288), 45 Alloc: make(core.GenesisAlloc), 46 Config: ¶ms.ChainConfig{ 47 HomesteadBlock: big.NewInt(0), 48 EIP150Block: big.NewInt(0), 49 EIP155Block: big.NewInt(0), 50 EIP158Block: big.NewInt(0), 51 ByzantiumBlock: big.NewInt(0), 52 ConstantinopleBlock: big.NewInt(0), 53 PetersburgBlock: 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: %v", 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 out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ") 234 fmt.Printf("Chain configuration updated:\n\n%s\n", out) 235 236 w.conf.flush() 237 238 case "2": 239 // Save whatever genesis configuration we currently have 240 fmt.Println() 241 fmt.Printf("Which folder to save the genesis specs into? (default = current)\n") 242 fmt.Printf(" Will create %s.json, %s-aleth.json, %s-harmony.json, %s-parity.json\n", w.network, w.network, w.network, w.network) 243 244 folder := w.readDefaultString(".") 245 if err := os.MkdirAll(folder, 0755); err != nil { 246 log.Error("Failed to create spec folder", "folder", folder, "err", err) 247 return 248 } 249 out, _ := json.MarshalIndent(w.conf.Genesis, "", " ") 250 251 // Export the native genesis spec used by puppeth and Geth 252 gethJson := filepath.Join(folder, fmt.Sprintf("%s.json", w.network)) 253 if err := ioutil.WriteFile((gethJson), out, 0644); err != nil { 254 log.Error("Failed to save genesis file", "err", err) 255 return 256 } 257 log.Info("Saved native genesis chain spec", "path", gethJson) 258 259 // Export the genesis spec used by Aleth (formerly C++ Ethereum) 260 if spec, err := newAlethGenesisSpec(w.network, w.conf.Genesis); err != nil { 261 log.Error("Failed to create Aleth chain spec", "err", err) 262 } else { 263 saveGenesis(folder, w.network, "aleth", spec) 264 } 265 // Export the genesis spec used by Parity 266 if spec, err := newParityChainSpec(w.network, w.conf.Genesis, []string{}); err != nil { 267 log.Error("Failed to create Parity chain spec", "err", err) 268 } else { 269 saveGenesis(folder, w.network, "parity", spec) 270 } 271 // Export the genesis spec used by Harmony (formerly EthereumJ 272 saveGenesis(folder, w.network, "harmony", w.conf.Genesis) 273 274 case "3": 275 // Make sure we don't have any services running 276 if len(w.conf.servers()) > 0 { 277 log.Error("Genesis reset requires all services and servers torn down") 278 return 279 } 280 log.Info("Genesis block destroyed") 281 282 w.conf.Genesis = nil 283 w.conf.flush() 284 default: 285 log.Error("That's not something I can do") 286 return 287 } 288 } 289 290 // saveGenesis JSON encodes an arbitrary genesis spec into a pre-defined file. 291 func saveGenesis(folder, network, client string, spec interface{}) { 292 path := filepath.Join(folder, fmt.Sprintf("%s-%s.json", network, client)) 293 294 out, _ := json.Marshal(spec) 295 if err := ioutil.WriteFile(path, out, 0644); err != nil { 296 log.Error("Failed to save genesis file", "client", client, "err", err) 297 return 298 } 299 log.Info("Saved genesis chain spec", "client", client, "path", path) 300 }