Unverified Commit f74077b4 authored by Péter Szilágyi's avatar Péter Szilágyi Committed by GitHub

Merge pull request #18172 from holiman/puppeth_converter

cmd/puppeth: implement chainspec converters
parents 7a5c1b28 d4415f5e
This diff is collapsed.
// Copyright 2018 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"reflect"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/core"
)
// Tests the go-ethereum to Aleth chainspec conversion for the Stureby testnet.
func TestAlethSturebyConverter(t *testing.T) {
blob, err := ioutil.ReadFile("testdata/stureby_geth.json")
if err != nil {
t.Fatalf("could not read file: %v", err)
}
var genesis core.Genesis
if err := json.Unmarshal(blob, &genesis); err != nil {
t.Fatalf("failed parsing genesis: %v", err)
}
spec, err := newAlethGenesisSpec("stureby", &genesis)
if err != nil {
t.Fatalf("failed creating chainspec: %v", err)
}
expBlob, err := ioutil.ReadFile("testdata/stureby_aleth.json")
if err != nil {
t.Fatalf("could not read file: %v", err)
}
expspec := &alethGenesisSpec{}
if err := json.Unmarshal(expBlob, expspec); err != nil {
t.Fatalf("failed parsing genesis: %v", err)
}
if !reflect.DeepEqual(expspec, spec) {
t.Errorf("chainspec mismatch")
c := spew.ConfigState{
DisablePointerAddresses: true,
SortKeys: true,
}
exp := strings.Split(c.Sdump(expspec), "\n")
got := strings.Split(c.Sdump(spec), "\n")
for i := 0; i < len(exp) && i < len(got); i++ {
if exp[i] != got[i] {
fmt.Printf("got: %v\nexp: %v\n", exp[i], got[i])
}
}
}
}
// Tests the go-ethereum to Parity chainspec conversion for the Stureby testnet.
func TestParitySturebyConverter(t *testing.T) {
blob, err := ioutil.ReadFile("testdata/stureby_geth.json")
if err != nil {
t.Fatalf("could not read file: %v", err)
}
var genesis core.Genesis
if err := json.Unmarshal(blob, &genesis); err != nil {
t.Fatalf("failed parsing genesis: %v", err)
}
spec, err := newParityChainSpec("Stureby", &genesis, []string{})
if err != nil {
t.Fatalf("failed creating chainspec: %v", err)
}
expBlob, err := ioutil.ReadFile("testdata/stureby_parity.json")
if err != nil {
t.Fatalf("could not read file: %v", err)
}
expspec := &parityChainSpec{}
if err := json.Unmarshal(expBlob, expspec); err != nil {
t.Fatalf("failed parsing genesis: %v", err)
}
expspec.Nodes = []string{}
if !reflect.DeepEqual(expspec, spec) {
t.Errorf("chainspec mismatch")
c := spew.ConfigState{
DisablePointerAddresses: true,
SortKeys: true,
}
exp := strings.Split(c.Sdump(expspec), "\n")
got := strings.Split(c.Sdump(spec), "\n")
for i := 0; i < len(exp) && i < len(got); i++ {
if exp[i] != got[i] {
fmt.Printf("got: %v\nexp: %v\n", exp[i], got[i])
}
}
}
}
......@@ -640,7 +640,7 @@ func deployDashboard(client *sshClient, network string, conf *config, config *da
files[filepath.Join(workdir, network+".json")] = genesis
if conf.Genesis.Config.Ethash != nil {
cppSpec, err := newCppEthereumGenesisSpec(network, conf.Genesis)
cppSpec, err := newAlethGenesisSpec(network, conf.Genesis)
if err != nil {
return nil, err
}
......
......@@ -43,18 +43,23 @@ func main() {
Usage: "log level to emit to the screen",
},
}
app.Action = func(c *cli.Context) error {
app.Before = func(c *cli.Context) error {
// Set up the logger to print everything and the random generator
log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
rand.Seed(time.Now().UnixNano())
network := c.String("network")
if strings.Contains(network, " ") || strings.Contains(network, "-") || strings.ToLower(network) != network {
log.Crit("No spaces, hyphens or capital letters allowed in network name")
}
// Start the wizard and relinquish control
makeWizard(c.String("network")).run()
return nil
}
app.Action = runWizard
app.Run(os.Args)
}
// runWizard start the wizard and relinquish control to it.
func runWizard(c *cli.Context) error {
network := c.String("network")
if strings.Contains(network, " ") || strings.Contains(network, "-") || strings.ToLower(network) != network {
log.Crit("No spaces, hyphens or capital letters allowed in network name")
}
makeWizard(c.String("network")).run()
return nil
}
{
"sealEngine":"Ethash",
"params":{
"accountStartNonce":"0x00",
"maximumExtraDataSize":"0x20",
"homesteadForkBlock":"0x2710",
"daoHardforkBlock":"0x00",
"EIP150ForkBlock":"0x3a98",
"EIP158ForkBlock":"0x59d8",
"byzantiumForkBlock":"0x7530",
"constantinopleForkBlock":"0x9c40",
"minGasLimit":"0x1388",
"maxGasLimit":"0x7fffffffffffffff",
"tieBreakingGas":false,
"gasLimitBoundDivisor":"0x0400",
"minimumDifficulty":"0x20000",
"difficultyBoundDivisor":"0x0800",
"durationLimit":"0x0d",
"blockReward":"0x4563918244F40000",
"networkID":"0x4cb2e",
"chainID":"0x4cb2e",
"allowFutureBlocks":false
},
"genesis":{
"nonce":"0x0000000000000000",
"difficulty":"0x20000",
"mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"author":"0x0000000000000000000000000000000000000000",
"timestamp":"0x59a4e76d",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData":"0x0000000000000000000000000000000000000000000000000000000b4dc0ffee",
"gasLimit":"0x47b760"
},
"accounts":{
"0000000000000000000000000000000000000001":{
"balance":"1",
"precompiled":{
"name":"ecrecover",
"linear":{
"base":3000,
"word":0
}
}
},
"0000000000000000000000000000000000000002":{
"balance":"1",
"precompiled":{
"name":"sha256",
"linear":{
"base":60,
"word":12
}
}
},
"0000000000000000000000000000000000000003":{
"balance":"1",
"precompiled":{
"name":"ripemd160",
"linear":{
"base":600,
"word":120
}
}
},
"0000000000000000000000000000000000000004":{
"balance":"1",
"precompiled":{
"name":"identity",
"linear":{
"base":15,
"word":3
}
}
},
"0000000000000000000000000000000000000005":{
"balance":"1",
"precompiled":{
"name":"modexp",
"startingBlock":"0x7530"
}
},
"0000000000000000000000000000000000000006":{
"balance":"1",
"precompiled":{
"name":"alt_bn128_G1_add",
"startingBlock":"0x7530",
"linear":{
"base":500,
"word":0
}
}
},
"0000000000000000000000000000000000000007":{
"balance":"1",
"precompiled":{
"name":"alt_bn128_G1_mul",
"startingBlock":"0x7530",
"linear":{
"base":40000,
"word":0
}
}
},
"0000000000000000000000000000000000000008":{
"balance":"1",
"precompiled":{
"name":"alt_bn128_pairing_product",
"startingBlock":"0x7530"
}
}
}
}
{
"config": {
"ethash":{},
"chainId": 314158,
"homesteadBlock": 10000,
"eip150Block": 15000,
"eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"eip155Block": 23000,
"eip158Block": 23000,
"byzantiumBlock": 30000,
"constantinopleBlock": 40000
},
"nonce": "0x0",
"timestamp": "0x59a4e76d",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x0000000000000000000000000000000000000000000000000000000b4dc0ffee",
"gasLimit": "0x47b760",
"difficulty": "0x20000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"0000000000000000000000000000000000000001": {
"balance": "0x01"
},
"0000000000000000000000000000000000000002": {
"balance": "0x01"
},
"0000000000000000000000000000000000000003": {
"balance": "0x01"
},
"0000000000000000000000000000000000000004": {
"balance": "0x01"
},
"0000000000000000000000000000000000000005": {
"balance": "0x01"
},
"0000000000000000000000000000000000000006": {
"balance": "0x01"
},
"0000000000000000000000000000000000000007": {
"balance": "0x01"
},
"0000000000000000000000000000000000000008": {
"balance": "0x01"
}
}
}
{
"name":"Stureby",
"dataDir":"stureby",
"engine":{
"Ethash":{
"params":{
"minimumDifficulty":"0x20000",
"difficultyBoundDivisor":"0x800",
"durationLimit":"0xd",
"blockReward":{
"0x0":"0x4563918244f40000",
"0x7530":"0x29a2241af62c0000",
"0x9c40":"0x1bc16d674ec80000"
},
"homesteadTransition":"0x2710",
"eip100bTransition":"0x7530",
"difficultyBombDelays":{
"0x7530":"0x2dc6c0",
"0x9c40":"0x1e8480"
}
}
}
},
"params":{
"accountStartNonce":"0x0",
"maximumExtraDataSize":"0x20",
"gasLimitBoundDivisor":"0x400",
"minGasLimit":"0x1388",
"networkID":"0x4cb2e",
"chainID":"0x4cb2e",
"maxCodeSize":"0x6000",
"maxCodeSizeTransition":"0x0",
"eip98Transition": "0x7fffffffffffffff",
"eip150Transition":"0x3a98",
"eip160Transition":"0x59d8",
"eip161abcTransition":"0x59d8",
"eip161dTransition":"0x59d8",
"eip155Transition":"0x59d8",
"eip140Transition":"0x7530",
"eip211Transition":"0x7530",
"eip214Transition":"0x7530",
"eip658Transition":"0x7530",
"eip145Transition":"0x9c40",
"eip1014Transition":"0x9c40",
"eip1052Transition":"0x9c40",
"eip1283Transition":"0x9c40"
},
"genesis":{
"seal":{
"ethereum":{
"nonce":"0x0000000000000000",
"mixHash":"0x0000000000000000000000000000000000000000000000000000000000000000"
}
},
"difficulty":"0x20000",
"author":"0x0000000000000000000000000000000000000000",
"timestamp":"0x59a4e76d",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData":"0x0000000000000000000000000000000000000000000000000000000b4dc0ffee",
"gasLimit":"0x47b760"
},
"nodes":[
"enode://dfa7aca3f5b635fbfe7d0b20575f25e40d9e27b4bfbb3cf74364a42023ad9f25c1a4383bcc8cced86ee511a7d03415345a4df05be37f1dff040e4c780699f1c0@168.61.153.255:31303",
"enode://ef441b20dd70aeabf0eac35c3b8a2854e5ce04db0e30be9152ea9fd129359dcbb3f803993303ff5781c755dfd7223f3fe43505f583cccb740949407677412ba9@40.74.91.252:31303",
"enode://953b5ea1c8987cf46008232a0160324fd00d41320ecf00e23af86ec8f5396b19eb57ddab37c78141be56f62e9077de4f4dfa0747fa768ed8c8531bbfb1046237@40.70.214.166:31303",
"enode://276e613dd4b277a66591e565711e6c8bb107f0905248a9f8f8228c1a87992e156e5114bb9937c02824a9d9d25f76340442cf86e2028bf5293cae19904fb2b98e@35.178.251.52:30303",
"enode://064c820d41e52ed7d426ac64b60506c2998235bedc7e67cb497c6faf7bb4fc54fe56fc82d0add3180b747c0c4f40a1108a6f84d7d0629ed606d504528e61cc57@3.8.5.3:30303",
"enode://90069fdabcc5e684fa5d59430bebbb12755d9362dfe5006a1485b13d71a78a3812d36e74dd7d88e50b51add01e097ea80f16263aeaa4f0230db6c79e2a97e7ca@217.29.191.142:30303",
"enode://0aac74b7fd28726275e466acb5e03bc88a95927e9951eb66b5efb239b2f798ada0690853b2f2823fe4efa408f0f3d4dd258430bc952a5ff70677b8625b3e3b14@40.115.33.57:40404",
"enode://0b96415a10f835106d83e090a0528eed5e7887e5c802a6d084e9f1993a9d0fc713781e6e4101f6365e9b91259712f291acc0a9e6e667e22023050d602c36fbe2@40.115.33.57:40414"
],
"accounts":{
"0000000000000000000000000000000000000001":{
"balance":"1",
"nonce":"0",
"builtin":{
"name":"ecrecover",
"pricing":{
"linear":{
"base":3000,
"word":0
}
}
}
},
"0000000000000000000000000000000000000002":{
"balance":"1",
"nonce":"0",
"builtin":{
"name":"sha256",
"pricing":{
"linear":{
"base":60,
"word":12
}
}
}
},
"0000000000000000000000000000000000000003":{
"balance":"1",
"nonce":"0",
"builtin":{
"name":"ripemd160",
"pricing":{
"linear":{
"base":600,
"word":120
}
}
}
},
"0000000000000000000000000000000000000004":{
"balance":"1",
"nonce":"0",
"builtin":{
"name":"identity",
"pricing":{
"linear":{
"base":15,
"word":3
}
}
}
},
"0000000000000000000000000000000000000005":{
"balance":"1",
"nonce":"0",
"builtin":{
"name":"modexp",
"activate_at":"0x7530",
"pricing":{
"modexp":{
"divisor":20
}
}
}
},
"0000000000000000000000000000000000000006":{
"balance":"1",
"nonce":"0",
"builtin":{
"name":"alt_bn128_add",
"activate_at":"0x7530",
"pricing":{
"linear":{
"base":500,
"word":0
}
}
}
},
"0000000000000000000000000000000000000007":{
"balance":"1",
"nonce":"0",
"builtin":{
"name":"alt_bn128_mul",
"activate_at":"0x7530",
"pricing":{
"linear":{
"base":40000,
"word":0
}
}
}
},
"0000000000000000000000000000000000000008":{
"balance":"1",
"nonce":"0",
"builtin":{
"name":"alt_bn128_pairing",
"activate_at":"0x7530",
"pricing":{
"alt_bn128_pairing":{
"base":100000,
"pair":80000
}
}
}
}
}
}
......@@ -23,6 +23,7 @@ import (
"io/ioutil"
"math/big"
"net"
"net/url"
"os"
"path/filepath"
"sort"
......@@ -118,6 +119,47 @@ func (w *wizard) readDefaultString(def string) string {
return def
}
// readDefaultYesNo reads a single line from stdin, trimming if from spaces and
// interpreting it as a 'yes' or a 'no'. If an empty line is entered, the default
// value is returned.
func (w *wizard) readDefaultYesNo(def bool) bool {
for {
fmt.Printf("> ")
text, err := w.in.ReadString('\n')
if err != nil {
log.Crit("Failed to read user input", "err", err)
}
if text = strings.ToLower(strings.TrimSpace(text)); text == "" {
return def
}
if text == "y" || text == "yes" {
return true
}
if text == "n" || text == "no" {
return false
}
log.Error("Invalid input, expected 'y', 'yes', 'n', 'no' or empty")
}
}
// readURL reads a single line from stdin, trimming if from spaces and trying to
// interpret it as a URL (http, https or file).
func (w *wizard) readURL() *url.URL {
for {
fmt.Printf("> ")
text, err := w.in.ReadString('\n')
if err != nil {
log.Crit("Failed to read user input", "err", err)
}
uri, err := url.Parse(strings.TrimSpace(text))
if err != nil {
log.Error("Invalid input, expected URL", "err", err)
continue
}
return uri
}
}
// readInt reads a single line from stdin, trimming if from spaces, enforcing it
// to parse into an integer.
func (w *wizard) readInt() int {
......
......@@ -137,14 +137,14 @@ func (w *wizard) deployDashboard() {
if w.conf.ethstats != "" {
fmt.Println()
fmt.Println("Include ethstats secret on dashboard (y/n)? (default = yes)")
infos.trusted = w.readDefaultString("y") == "y"
infos.trusted = w.readDefaultYesNo(true)
}
// Try to deploy the dashboard container on the host
nocache := false
if existed {
fmt.Println()
fmt.Printf("Should the dashboard be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n"
nocache = w.readDefaultYesNo(false)
}
if out, err := deployDashboard(client, w.network, &w.conf, infos, nocache); err != nil {
log.Error("Failed to deploy dashboard container", "err", err)
......
......@@ -67,11 +67,11 @@ func (w *wizard) deployEthstats() {
if existed {
fmt.Println()
fmt.Printf("Keep existing IP %v blacklist (y/n)? (default = yes)\n", infos.banned)
if w.readDefaultString("y") != "y" {
if !w.readDefaultYesNo(true) {
// The user might want to clear the entire list, although generally probably not
fmt.Println()
fmt.Printf("Clear out blacklist and start over (y/n)? (default = no)\n")
if w.readDefaultString("n") != "n" {
if w.readDefaultYesNo(false) {
infos.banned = nil
}
// Offer the user to explicitly add/remove certain IP addresses
......@@ -106,7 +106,7 @@ func (w *wizard) deployEthstats() {
if existed {
fmt.Println()
fmt.Printf("Should the ethstats be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n"
nocache = w.readDefaultYesNo(false)
}
trusted := make([]string, 0, len(w.servers))
for _, client := range w.servers {
......
......@@ -100,7 +100,7 @@ func (w *wizard) deployExplorer() {
if existed {
fmt.Println()
fmt.Printf("Should the explorer be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n"
nocache = w.readDefaultYesNo(false)
}
if out, err := deployExplorer(client, w.network, chain, infos, nocache); err != nil {
log.Error("Failed to deploy explorer container", "err", err)
......
......@@ -81,7 +81,7 @@ func (w *wizard) deployFaucet() {
if infos.captchaToken != "" {
fmt.Println()
fmt.Println("Reuse previous reCaptcha API authorization (y/n)? (default = yes)")
if w.readDefaultString("y") != "y" {
if !w.readDefaultYesNo(true) {
infos.captchaToken, infos.captchaSecret = "", ""
}
}
......@@ -89,7 +89,7 @@ func (w *wizard) deployFaucet() {
// No previous authorization (or old one discarded)
fmt.Println()
fmt.Println("Enable reCaptcha protection against robots (y/n)? (default = no)")
if w.readDefaultString("n") == "n" {
if !w.readDefaultYesNo(false) {
log.Warn("Users will be able to requests funds via automated scripts")
} else {
// Captcha protection explicitly requested, read the site and secret keys
......@@ -132,7 +132,7 @@ func (w *wizard) deployFaucet() {
} else {
fmt.Println()
fmt.Printf("Reuse previous (%s) funding account (y/n)? (default = yes)\n", key.Address.Hex())
if w.readDefaultString("y") != "y" {
if !w.readDefaultYesNo(true) {
infos.node.keyJSON, infos.node.keyPass = "", ""
}
}
......@@ -166,7 +166,7 @@ func (w *wizard) deployFaucet() {
if existed {
fmt.Println()
fmt.Printf("Should the faucet be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n"
nocache = w.readDefaultYesNo(false)
}
if out, err := deployFaucet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
log.Error("Failed to deploy faucet container", "err", err)
......
......@@ -20,9 +20,13 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"math/big"
"math/rand"
"net/http"
"os"
"path/filepath"
"time"
"github.com/ethereum/go-ethereum/common"
......@@ -40,11 +44,12 @@ func (w *wizard) makeGenesis() {
Difficulty: big.NewInt(524288),
Alloc: make(core.GenesisAlloc),
Config: &params.ChainConfig{
HomesteadBlock: big.NewInt(1),
EIP150Block: big.NewInt(2),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(4),
HomesteadBlock: big.NewInt(1),
EIP150Block: big.NewInt(2),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(4),
ConstantinopleBlock: big.NewInt(5),
},
}
// Figure out which consensus engine to choose
......@@ -114,9 +119,13 @@ func (w *wizard) makeGenesis() {
}
break
}
// Add a batch of precompile balances to avoid them getting deleted
for i := int64(0); i < 256; i++ {
genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)}
fmt.Println()
fmt.Println("Should the precompile-addresses (0x1 .. 0xff) be pre-funded with 1 wei? (advisable yes)")
if w.readDefaultYesNo(true) {
// Add a batch of precompile balances to avoid them getting deleted
for i := int64(0); i < 256; i++ {
genesis.Alloc[common.BigToAddress(big.NewInt(i))] = core.GenesisAccount{Balance: big.NewInt(1)}
}
}
// Query the user for some custom extras
fmt.Println()
......@@ -130,53 +139,130 @@ func (w *wizard) makeGenesis() {
w.conf.flush()
}
// importGenesis imports a Geth genesis spec into puppeth.
func (w *wizard) importGenesis() {
// Request the genesis JSON spec URL from the user
fmt.Println()
fmt.Println("Where's the genesis file? (local file or http/https url)")
url := w.readURL()
// Convert the various allowed URLs to a reader stream
var reader io.Reader
switch url.Scheme {
case "http", "https":
// Remote web URL, retrieve it via an HTTP client
res, err := http.Get(url.String())
if err != nil {
log.Error("Failed to retrieve remote genesis", "err", err)
return
}
defer res.Body.Close()
reader = res.Body
case "":
// Schemaless URL, interpret as a local file
file, err := os.Open(url.String())
if err != nil {
log.Error("Failed to open local genesis", "err", err)
return
}
defer file.Close()
reader = file
default:
log.Error("Unsupported genesis URL scheme", "scheme", url.Scheme)
return
}
// Parse the genesis file and inject it successful
var genesis core.Genesis
if err := json.NewDecoder(reader).Decode(&genesis); err != nil {
log.Error("Invalid genesis spec: %v", err)
return
}
log.Info("Imported genesis block")
w.conf.Genesis = &genesis
w.conf.flush()
}
// manageGenesis permits the modification of chain configuration parameters in
// a genesis config and the export of the entire genesis spec.
func (w *wizard) manageGenesis() {
// Figure out whether to modify or export the genesis
fmt.Println()
fmt.Println(" 1. Modify existing fork rules")
fmt.Println(" 2. Export genesis configuration")
fmt.Println(" 2. Export genesis configurations")
fmt.Println(" 3. Remove genesis configuration")
choice := w.read()
switch {
case choice == "1":
switch choice {
case "1":
// Fork rule updating requested, iterate over each fork
fmt.Println()
fmt.Printf("Which block should Homestead come into effect? (default = %v)\n", w.conf.Genesis.Config.HomesteadBlock)
w.conf.Genesis.Config.HomesteadBlock = w.readDefaultBigInt(w.conf.Genesis.Config.HomesteadBlock)
fmt.Println()
fmt.Printf("Which block should EIP150 come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP150Block)
fmt.Printf("Which block should EIP150 (Tangerine Whistle) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP150Block)
w.conf.Genesis.Config.EIP150Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP150Block)
fmt.Println()
fmt.Printf("Which block should EIP155 come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP155Block)
fmt.Printf("Which block should EIP155 (Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP155Block)
w.conf.Genesis.Config.EIP155Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP155Block)
fmt.Println()
fmt.Printf("Which block should EIP158 come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP158Block)
fmt.Printf("Which block should EIP158/161 (also Spurious Dragon) come into effect? (default = %v)\n", w.conf.Genesis.Config.EIP158Block)
w.conf.Genesis.Config.EIP158Block = w.readDefaultBigInt(w.conf.Genesis.Config.EIP158Block)
fmt.Println()
fmt.Printf("Which block should Byzantium come into effect? (default = %v)\n", w.conf.Genesis.Config.ByzantiumBlock)
w.conf.Genesis.Config.ByzantiumBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ByzantiumBlock)
fmt.Println()
fmt.Printf("Which block should Constantinople come into effect? (default = %v)\n", w.conf.Genesis.Config.ConstantinopleBlock)
w.conf.Genesis.Config.ConstantinopleBlock = w.readDefaultBigInt(w.conf.Genesis.Config.ConstantinopleBlock)
out, _ := json.MarshalIndent(w.conf.Genesis.Config, "", " ")
fmt.Printf("Chain configuration updated:\n\n%s\n", out)
case choice == "2":
case "2":
// Save whatever genesis configuration we currently have
fmt.Println()
fmt.Printf("Which file to save the genesis into? (default = %s.json)\n", w.network)
fmt.Printf("Which folder to save the genesis specs into? (default = current)\n")
fmt.Printf(" Will create %s.json, %s-aleth.json, %s-harmony.json, %s-parity.json\n", w.network, w.network, w.network, w.network)
folder := w.readDefaultString(".")
if err := os.MkdirAll(folder, 0755); err != nil {
log.Error("Failed to create spec folder", "folder", folder, "err", err)
return
}
out, _ := json.MarshalIndent(w.conf.Genesis, "", " ")
if err := ioutil.WriteFile(w.readDefaultString(fmt.Sprintf("%s.json", w.network)), out, 0644); err != nil {
// Export the native genesis spec used by puppeth and Geth
gethJson := filepath.Join(folder, fmt.Sprintf("%s.json", w.network))
if err := ioutil.WriteFile((gethJson), out, 0644); err != nil {
log.Error("Failed to save genesis file", "err", err)
return
}
log.Info("Exported existing genesis block")
log.Info("Saved native genesis chain spec", "path", gethJson)
case choice == "3":
// Export the genesis spec used by Aleth (formerly C++ Ethereum)
if spec, err := newAlethGenesisSpec(w.network, w.conf.Genesis); err != nil {
log.Error("Failed to create Aleth chain spec", "err", err)
} else {
saveGenesis(folder, w.network, "aleth", spec)
}
// Export the genesis spec used by Parity
if spec, err := newParityChainSpec(w.network, w.conf.Genesis, []string{}); err != nil {
log.Error("Failed to create Parity chain spec", "err", err)
} else {
saveGenesis(folder, w.network, "parity", spec)
}
// Export the genesis spec used by Harmony (formerly EthereumJ
saveGenesis(folder, w.network, "harmony", w.conf.Genesis)
case "3":
// Make sure we don't have any services running
if len(w.conf.servers()) > 0 {
log.Error("Genesis reset requires all services and servers torn down")
......@@ -186,8 +272,20 @@ func (w *wizard) manageGenesis() {
w.conf.Genesis = nil
w.conf.flush()
default:
log.Error("That's not something I can do")
return
}
}
// saveGenesis JSON encodes an arbitrary genesis spec into a pre-defined file.
func saveGenesis(folder, network, client string, spec interface{}) {
path := filepath.Join(folder, fmt.Sprintf("%s-%s.json", network, client))
out, _ := json.Marshal(spec)
if err := ioutil.WriteFile(path, out, 0644); err != nil {
log.Error("Failed to save genesis file", "client", client, "err", err)
return
}
log.Info("Saved genesis chain spec", "client", client, "path", path)
}
......@@ -131,7 +131,20 @@ func (w *wizard) run() {
case choice == "2":
if w.conf.Genesis == nil {
w.makeGenesis()
fmt.Println()
fmt.Println("What would you like to do? (default = create)")
fmt.Println(" 1. Create new genesis from scratch")
fmt.Println(" 2. Import already existing genesis")
choice := w.read()
switch {
case choice == "" || choice == "1":
w.makeGenesis()
case choice == "2":
w.importGenesis()
default:
log.Error("That's not something I can do")
}
} else {
w.manageGenesis()
}
......@@ -149,7 +162,6 @@ func (w *wizard) run() {
} else {
w.manageComponents()
}
default:
log.Error("That's not something I can do")
}
......
......@@ -41,12 +41,12 @@ func (w *wizard) ensureVirtualHost(client *sshClient, port int, def string) (str
// Reverse proxy is not running, offer to deploy a new one
fmt.Println()
fmt.Println("Allow sharing the port with other services (y/n)? (default = yes)")
if w.readDefaultString("y") == "y" {
if w.readDefaultYesNo(true) {
nocache := false
if proxy != nil {
fmt.Println()
fmt.Printf("Should the reverse-proxy be rebuilt from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n"
nocache = w.readDefaultYesNo(false)
}
if out, err := deployNginx(client, w.network, port, nocache); err != nil {
log.Error("Failed to deploy reverse-proxy", "err", err)
......
......@@ -126,7 +126,7 @@ func (w *wizard) deployNode(boot bool) {
} else {
fmt.Println()
fmt.Printf("Reuse previous (%s) signing account (y/n)? (default = yes)\n", key.Address.Hex())
if w.readDefaultString("y") != "y" {
if !w.readDefaultYesNo(true) {
infos.keyJSON, infos.keyPass = "", ""
}
}
......@@ -165,7 +165,7 @@ func (w *wizard) deployNode(boot bool) {
if existed {
fmt.Println()
fmt.Printf("Should the node be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n"
nocache = w.readDefaultYesNo(false)
}
if out, err := deployNode(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
log.Error("Failed to deploy Ethereum node container", "err", err)
......
......@@ -96,7 +96,7 @@ func (w *wizard) deployWallet() {
if existed {
fmt.Println()
fmt.Printf("Should the wallet be built from scratch (y/n)? (default = no)\n")
nocache = w.readDefaultString("n") != "n"
nocache = w.readDefaultYesNo(false)
}
if out, err := deployWallet(client, w.network, w.conf.bootnodes, infos, nocache); err != nil {
log.Error("Failed to deploy wallet container", "err", err)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment