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