github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/cmd/puppeth/wizard_genesis.go (about)

     1  // Copyright 2017 The go-simplechain Authors
     2  // This file is part of go-simplechain.
     3  //
     4  // go-simplechain 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-simplechain 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-simplechain. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"fmt"
    23  	"github.com/bigzoro/my_simplechain/core/types"
    24  	"github.com/bigzoro/my_simplechain/rlp"
    25  	"io"
    26  	"io/ioutil"
    27  	"math/big"
    28  	"math/rand"
    29  	"net/http"
    30  	"os"
    31  	"path/filepath"
    32  	"time"
    33  
    34  	"github.com/bigzoro/my_simplechain/common"
    35  	"github.com/bigzoro/my_simplechain/core"
    36  	"github.com/bigzoro/my_simplechain/log"
    37  	"github.com/bigzoro/my_simplechain/params"
    38  )
    39  
    40  // makeGenesis creates a new genesis struct based on some user input.
    41  func (w *wizard) makeGenesis() {
    42  	// Construct a default genesis block
    43  	genesis := &core.Genesis{
    44  		Timestamp:  uint64(time.Now().Unix()),
    45  		GasLimit:   8894304,
    46  		Difficulty: big.NewInt(524288),
    47  		Alloc:      make(core.GenesisAlloc),
    48  		Config: &params.ChainConfig{
    49  			SingularityBlock: big.NewInt(0),
    50  		},
    51  	}
    52  	// Figure out which consensus engine to choose
    53  	fmt.Println()
    54  	fmt.Println("Which consensus engine to use? (default = clique)")
    55  	fmt.Println(" 1. Raft - etcd-raft")
    56  	fmt.Println(" 2. Clique - proof-of-authority")
    57  	fmt.Println(" 3. Pbft")
    58  
    59  	choice := w.read()
    60  	switch {
    61  	case choice == "1":
    62  		// In case of ethash, we're pretty much done
    63  		//genesis.Config.Ethash = new(params.EthashConfig)
    64  		//genesis.ExtraData = make([]byte, 32)
    65  		genesis.Config.Raft = true
    66  		genesis.ExtraData = make([]byte, 32)
    67  	case choice == "3":
    68  		// In the case of clique, configure the consensus parameters
    69  		genesis.Difficulty = big.NewInt(1)
    70  		genesis.Config.Pbft = &params.PbftConfig{
    71  			ProposerPolicy: 0,
    72  			Epoch:          30000,
    73  		}
    74  		// We also need the initial list of signers
    75  		fmt.Println()
    76  		fmt.Println("Which accounts are allowed to seal? (mandatory at least one)")
    77  
    78  		var signers []common.Address
    79  		for {
    80  			if address := w.readAddress(); address != nil {
    81  				signers = append(signers, *address)
    82  				continue
    83  			}
    84  			if len(signers) > 0 {
    85  				break
    86  			}
    87  		}
    88  		// Sort the signers and embed into the extra-data section
    89  		for i := 0; i < len(signers); i++ {
    90  			for j := i + 1; j < len(signers); j++ {
    91  				if bytes.Compare(signers[i][:], signers[j][:]) > 0 {
    92  					signers[i], signers[j] = signers[j], signers[i]
    93  				}
    94  			}
    95  		}
    96  		var buf bytes.Buffer
    97  		var extra []byte
    98  		var addresses []common.Address
    99  		for _, sealAddress := range signers {
   100  			addresses = append(addresses, sealAddress)
   101  		}
   102  
   103  		// compensate the lack bytes if header.Extra is not enough ByzantineExtraVanity bytes.
   104  		if len(extra) < types.ByzantineExtraVanity {
   105  			extra = append(extra, bytes.Repeat([]byte{0x00}, types.ByzantineExtraVanity-len(extra))...)
   106  		}
   107  		buf.Write(extra[:types.ByzantineExtraVanity])
   108  
   109  		ist := &types.ByzantineExtra{
   110  			Validators:    addresses,
   111  			Seal:          []byte{},
   112  			CommittedSeal: [][]byte{},
   113  		}
   114  
   115  		payload, err := rlp.EncodeToBytes(&ist)
   116  		if err != nil {
   117  			return
   118  		}
   119  
   120  		extra = append(buf.Bytes(), payload...)
   121  		genesis.ExtraData = extra
   122  	case choice == "" || choice == "2":
   123  		// In the case of clique, configure the consensus parameters
   124  		genesis.Difficulty = big.NewInt(1)
   125  		genesis.Config.Clique = &params.CliqueConfig{
   126  			Period: 15,
   127  			Epoch:  30000,
   128  		}
   129  		fmt.Println()
   130  		fmt.Println("How many seconds should blocks take? (default = 15)")
   131  		genesis.Config.Clique.Period = uint64(w.readDefaultInt(15))
   132  
   133  		// We also need the initial list of signers
   134  		fmt.Println()
   135  		fmt.Println("Which accounts are allowed to seal? (mandatory at least one)")
   136  
   137  		var signers []common.Address
   138  		for {
   139  			if address := w.readAddress(); address != nil {
   140  				signers = append(signers, *address)
   141  				continue
   142  			}
   143  			if len(signers) > 0 {
   144  				break
   145  			}
   146  		}
   147  		// Sort the signers and embed into the extra-data section
   148  		for i := 0; i < len(signers); i++ {
   149  			for j := i + 1; j < len(signers); j++ {
   150  				if bytes.Compare(signers[i][:], signers[j][:]) > 0 {
   151  					signers[i], signers[j] = signers[j], signers[i]
   152  				}
   153  			}
   154  		}
   155  		genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+65)
   156  		for i, signer := range signers {
   157  			copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:])
   158  		}
   159  
   160  	default:
   161  		log.Crit("Invalid consensus engine choice", "choice", choice)
   162  	}
   163  	// Consensus all set, just ask for initial funds and go
   164  	fmt.Println()
   165  	fmt.Println("Which accounts should be pre-funded? (advisable at least one)")
   166  	for {
   167  		// Read the address of the account to fund
   168  		if address := w.readAddress(); address != nil {
   169  			genesis.Alloc[*address] = core.GenesisAccount{
   170  				Balance: new(big.Int).Lsh(big.NewInt(1), 256-7), // 2^256 / 128 (allow many pre-funds without balance overflows)
   171  			}
   172  			continue
   173  		}
   174  		break
   175  	}
   176  	fmt.Println()
   177  	fmt.Println("Should the precompile-addresses (0x1 .. 0xff) be pre-funded with 1 wei? (advisable yes)")
   178  	if w.readDefaultYesNo(true) {
   179  		// Add a batch of precompile balances to avoid them getting deleted
   180  		for i := int64(0); i < 256; i++ {
   181  			genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)}
   182  		}
   183  	}
   184  	// Query the user for some custom extras
   185  	fmt.Println()
   186  	fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)")
   187  	genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536))))
   188  
   189  	// All done, store the genesis and flush to disk
   190  	log.Info("Configured new genesis block")
   191  
   192  	w.conf.Genesis = genesis
   193  	w.conf.flush()
   194  }
   195  
   196  // importGenesis imports a Geth genesis spec into puppeth.
   197  func (w *wizard) importGenesis() {
   198  	// Request the genesis JSON spec URL from the user
   199  	fmt.Println()
   200  	fmt.Println("Where's the genesis file? (local file or http/https url)")
   201  	url := w.readURL()
   202  
   203  	// Convert the various allowed URLs to a reader stream
   204  	var reader io.Reader
   205  
   206  	switch url.Scheme {
   207  	case "http", "https":
   208  		// Remote web URL, retrieve it via an HTTP client
   209  		res, err := http.Get(url.String())
   210  		if err != nil {
   211  			log.Error("Failed to retrieve remote genesis", "err", err)
   212  			return
   213  		}
   214  		defer res.Body.Close()
   215  		reader = res.Body
   216  
   217  	case "":
   218  		// Schemaless URL, interpret as a local file
   219  		file, err := os.Open(url.String())
   220  		if err != nil {
   221  			log.Error("Failed to open local genesis", "err", err)
   222  			return
   223  		}
   224  		defer file.Close()
   225  		reader = file
   226  
   227  	default:
   228  		log.Error("Unsupported genesis URL scheme", "scheme", url.Scheme)
   229  		return
   230  	}
   231  	// Parse the genesis file and inject it successful
   232  	var genesis core.Genesis
   233  	if err := json.NewDecoder(reader).Decode(&genesis); err != nil {
   234  		log.Error("Invalid genesis spec: %v", err)
   235  		return
   236  	}
   237  	log.Info("Imported genesis block")
   238  
   239  	w.conf.Genesis = &genesis
   240  	w.conf.flush()
   241  }
   242  
   243  // manageGenesis permits the modification of chain configuration parameters in
   244  // a genesis config and the export of the entire genesis spec.
   245  func (w *wizard) manageGenesis() {
   246  	// Figure out whether to modify or export the genesis
   247  	fmt.Println()
   248  	fmt.Println(" 1. Modify existing configurations")
   249  	fmt.Println(" 2. Export genesis configurations")
   250  	fmt.Println(" 3. Remove genesis configuration")
   251  
   252  	choice := w.read()
   253  	switch choice {
   254  	case "1":
   255  		// Fork rule updating requested, iterate over each fork
   256  		fmt.Println()
   257  		fmt.Printf("Which block should SingularityBlock come into effect? (default = %v)\n", w.conf.Genesis.Config.SingularityBlock)
   258  		w.conf.Genesis.Config.SingularityBlock = w.readDefaultBigInt(w.conf.Genesis.Config.SingularityBlock)
   259  
   260  		out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", "  ")
   261  		fmt.Printf("Chain configuration updated:\n\n%s\n", out)
   262  
   263  		w.conf.flush()
   264  
   265  	case "2":
   266  		// Save whatever genesis configuration we currently have
   267  		fmt.Println()
   268  		fmt.Printf("Which folder to save the genesis specs into? (default = current)\n")
   269  		fmt.Printf("  Will create %s.json, %s-aleth.json, %s-harmony.json, %s-parity.json\n", w.network, w.network, w.network, w.network)
   270  
   271  		folder := w.readDefaultString(".")
   272  		if err := os.MkdirAll(folder, 0755); err != nil {
   273  			log.Error("Failed to create spec folder", "folder", folder, "err", err)
   274  			return
   275  		}
   276  		out, _ := json.MarshalIndent(w.conf.Genesis, "", "  ")
   277  
   278  		// Export the native genesis spec used by puppeth and Geth
   279  		gethJson := filepath.Join(folder, fmt.Sprintf("%s.json", w.network))
   280  		if err := ioutil.WriteFile((gethJson), out, 0644); err != nil {
   281  			log.Error("Failed to save genesis file", "err", err)
   282  			return
   283  		}
   284  		log.Info("Saved native genesis chain spec", "path", gethJson)
   285  
   286  		// Export the genesis spec used by Aleth (formerly C++ Ethereum)
   287  		if spec, err := newAlethGenesisSpec(w.network, w.conf.Genesis); err != nil {
   288  			log.Error("Failed to create Aleth chain spec", "err", err)
   289  		} else {
   290  			saveGenesis(folder, w.network, "aleth", spec)
   291  		}
   292  		// Export the genesis spec used by Parity
   293  		if spec, err := newParityChainSpec(w.network, w.conf.Genesis, []string{}); err != nil {
   294  			log.Error("Failed to create Parity chain spec", "err", err)
   295  		} else {
   296  			saveGenesis(folder, w.network, "parity", spec)
   297  		}
   298  		// Export the genesis spec used by Harmony (formerly EthereumJ)
   299  		saveGenesis(folder, w.network, "harmony", w.conf.Genesis)
   300  
   301  	case "3":
   302  		// Make sure we don't have any services running
   303  		if len(w.conf.servers()) > 0 {
   304  			log.Error("Genesis reset requires all services and servers torn down")
   305  			return
   306  		}
   307  		log.Info("Genesis block destroyed")
   308  
   309  		w.conf.Genesis = nil
   310  		w.conf.flush()
   311  	default:
   312  		log.Error("That's not something I can do")
   313  		return
   314  	}
   315  }
   316  
   317  // saveGenesis JSON encodes an arbitrary genesis spec into a pre-defined file.
   318  func saveGenesis(folder, network, client string, spec interface{}) {
   319  	path := filepath.Join(folder, fmt.Sprintf("%s-%s.json", network, client))
   320  
   321  	out, _ := json.MarshalIndent(spec, "", "  ")
   322  	if err := ioutil.WriteFile(path, out, 0644); err != nil {
   323  		log.Error("Failed to save genesis file", "client", client, "err", err)
   324  		return
   325  	}
   326  	log.Info("Saved genesis chain spec", "client", client, "path", path)
   327  }