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: &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: %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  }