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