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