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