github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/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/zhiqiangxu/go-ethereum/common"
    33  	"github.com/zhiqiangxu/go-ethereum/core"
    34  	"github.com/zhiqiangxu/go-ethereum/log"
    35  	"github.com/zhiqiangxu/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  			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 = &params.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", "err", 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  		fmt.Println()
   239  		fmt.Printf("Which block should YOLOv1 come into effect? (default = %v)\n", w.conf.Genesis.Config.YoloV1Block)
   240  		w.conf.Genesis.Config.YoloV1Block = w.readDefaultBigInt(w.conf.Genesis.Config.YoloV1Block)
   241  
   242  		out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", "  ")
   243  		fmt.Printf("Chain configuration updated:\n\n%s\n", out)
   244  
   245  		w.conf.flush()
   246  
   247  	case "2":
   248  		// Save whatever genesis configuration we currently have
   249  		fmt.Println()
   250  		fmt.Printf("Which folder to save the genesis specs into? (default = current)\n")
   251  		fmt.Printf("  Will create %s.json, %s-aleth.json, %s-harmony.json, %s-parity.json\n", w.network, w.network, w.network, w.network)
   252  
   253  		folder := w.readDefaultString(".")
   254  		if err := os.MkdirAll(folder, 0755); err != nil {
   255  			log.Error("Failed to create spec folder", "folder", folder, "err", err)
   256  			return
   257  		}
   258  		out, _ := json.MarshalIndent(w.conf.Genesis, "", "  ")
   259  
   260  		// Export the native genesis spec used by puppeth and Geth
   261  		gethJson := filepath.Join(folder, fmt.Sprintf("%s.json", w.network))
   262  		if err := ioutil.WriteFile((gethJson), out, 0644); err != nil {
   263  			log.Error("Failed to save genesis file", "err", err)
   264  			return
   265  		}
   266  		log.Info("Saved native genesis chain spec", "path", gethJson)
   267  
   268  		// Export the genesis spec used by Aleth (formerly C++ Ethereum)
   269  		if spec, err := newAlethGenesisSpec(w.network, w.conf.Genesis); err != nil {
   270  			log.Error("Failed to create Aleth chain spec", "err", err)
   271  		} else {
   272  			saveGenesis(folder, w.network, "aleth", spec)
   273  		}
   274  		// Export the genesis spec used by Parity
   275  		if spec, err := newParityChainSpec(w.network, w.conf.Genesis, []string{}); err != nil {
   276  			log.Error("Failed to create Parity chain spec", "err", err)
   277  		} else {
   278  			saveGenesis(folder, w.network, "parity", spec)
   279  		}
   280  		// Export the genesis spec used by Harmony (formerly EthereumJ)
   281  		saveGenesis(folder, w.network, "harmony", w.conf.Genesis)
   282  
   283  	case "3":
   284  		// Make sure we don't have any services running
   285  		if len(w.conf.servers()) > 0 {
   286  			log.Error("Genesis reset requires all services and servers torn down")
   287  			return
   288  		}
   289  		log.Info("Genesis block destroyed")
   290  
   291  		w.conf.Genesis = nil
   292  		w.conf.flush()
   293  	default:
   294  		log.Error("That's not something I can do")
   295  		return
   296  	}
   297  }
   298  
   299  // saveGenesis JSON encodes an arbitrary genesis spec into a pre-defined file.
   300  func saveGenesis(folder, network, client string, spec interface{}) {
   301  	path := filepath.Join(folder, fmt.Sprintf("%s-%s.json", network, client))
   302  
   303  	out, _ := json.MarshalIndent(spec, "", "  ")
   304  	if err := ioutil.WriteFile(path, out, 0644); err != nil {
   305  		log.Error("Failed to save genesis file", "client", client, "err", err)
   306  		return
   307  	}
   308  	log.Info("Saved genesis chain spec", "client", client, "path", path)
   309  }