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: &params.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 = &params.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  }