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