Răsfoiți Sursa

cmd/puppeth: implement chainspec converters

Martin Holst Swende 7 ani în urmă
părinte
comite
8698fbabf6

+ 241 - 145
cmd/puppeth/genesis.go

@@ -20,35 +20,41 @@ import (
 	"encoding/binary"
 	"errors"
 	"math"
+	"math/big"
+	"strings"
 
 	"github.com/ethereum/go-ethereum/common"
 	"github.com/ethereum/go-ethereum/common/hexutil"
+	math2 "github.com/ethereum/go-ethereum/common/math"
 	"github.com/ethereum/go-ethereum/consensus/ethash"
 	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/params"
 )
 
-// cppEthereumGenesisSpec represents the genesis specification format used by the
+// alethGenesisSpec represents the genesis specification format used by the
 // C++ Ethereum implementation.
-type cppEthereumGenesisSpec struct {
+type alethGenesisSpec struct {
 	SealEngine string `json:"sealEngine"`
 	Params     struct {
-		AccountStartNonce       hexutil.Uint64 `json:"accountStartNonce"`
-		HomesteadForkBlock      hexutil.Uint64 `json:"homesteadForkBlock"`
-		EIP150ForkBlock         hexutil.Uint64 `json:"EIP150ForkBlock"`
-		EIP158ForkBlock         hexutil.Uint64 `json:"EIP158ForkBlock"`
-		ByzantiumForkBlock      hexutil.Uint64 `json:"byzantiumForkBlock"`
-		ConstantinopleForkBlock hexutil.Uint64 `json:"constantinopleForkBlock"`
-		NetworkID               hexutil.Uint64 `json:"networkID"`
-		ChainID                 hexutil.Uint64 `json:"chainID"`
-		MaximumExtraDataSize    hexutil.Uint64 `json:"maximumExtraDataSize"`
-		MinGasLimit             hexutil.Uint64 `json:"minGasLimit"`
-		MaxGasLimit             hexutil.Uint64 `json:"maxGasLimit"`
-		GasLimitBoundDivisor    hexutil.Uint64 `json:"gasLimitBoundDivisor"`
-		MinimumDifficulty       *hexutil.Big   `json:"minimumDifficulty"`
-		DifficultyBoundDivisor  *hexutil.Big   `json:"difficultyBoundDivisor"`
-		DurationLimit           *hexutil.Big   `json:"durationLimit"`
-		BlockReward             *hexutil.Big   `json:"blockReward"`
+		AccountStartNonce       math2.HexOrDecimal64   `json:"accountStartNonce"`
+		MaximumExtraDataSize    hexutil.Uint64         `json:"maximumExtraDataSize"`
+		HomesteadForkBlock      hexutil.Uint64         `json:"homesteadForkBlock"`
+		DaoHardforkBlock        math2.HexOrDecimal64   `json:"daoHardforkBlock"`
+		EIP150ForkBlock         hexutil.Uint64         `json:"EIP150ForkBlock"`
+		EIP158ForkBlock         hexutil.Uint64         `json:"EIP158ForkBlock"`
+		ByzantiumForkBlock      hexutil.Uint64         `json:"byzantiumForkBlock"`
+		ConstantinopleForkBlock hexutil.Uint64         `json:"constantinopleForkBlock"`
+		MinGasLimit             hexutil.Uint64         `json:"minGasLimit"`
+		MaxGasLimit             hexutil.Uint64         `json:"maxGasLimit"`
+		TieBreakingGas          bool                   `json:"tieBreakingGas"`
+		GasLimitBoundDivisor    math2.HexOrDecimal64   `json:"gasLimitBoundDivisor"`
+		MinimumDifficulty       *hexutil.Big           `json:"minimumDifficulty"`
+		DifficultyBoundDivisor  *math2.HexOrDecimal256 `json:"difficultyBoundDivisor"`
+		DurationLimit           *math2.HexOrDecimal256 `json:"durationLimit"`
+		BlockReward             *hexutil.Big           `json:"blockReward"`
+		NetworkID               hexutil.Uint64         `json:"networkID"`
+		ChainID                 hexutil.Uint64         `json:"chainID"`
+		AllowFutureBlocks       bool                   `json:"allowFutureBlocks""`
 	} `json:"params"`
 
 	Genesis struct {
@@ -62,57 +68,68 @@ type cppEthereumGenesisSpec struct {
 		GasLimit   hexutil.Uint64 `json:"gasLimit"`
 	} `json:"genesis"`
 
-	Accounts map[common.Address]*cppEthereumGenesisSpecAccount `json:"accounts"`
+	Accounts map[common.UnprefixedAddress]*alethGenesisSpecAccount `json:"accounts"`
 }
 
-// cppEthereumGenesisSpecAccount is the prefunded genesis account and/or precompiled
+// alethGenesisSpecAccount is the prefunded genesis account and/or precompiled
 // contract definition.
-type cppEthereumGenesisSpecAccount struct {
-	Balance     *hexutil.Big                   `json:"balance"`
-	Nonce       uint64                         `json:"nonce,omitempty"`
-	Precompiled *cppEthereumGenesisSpecBuiltin `json:"precompiled,omitempty"`
+type alethGenesisSpecAccount struct {
+	Balance     *math2.HexOrDecimal256   `json:"balance"`
+	Nonce       uint64                   `json:"nonce,omitempty"`
+	Precompiled *alethGenesisSpecBuiltin `json:"precompiled,omitempty"`
 }
 
-// cppEthereumGenesisSpecBuiltin is the precompiled contract definition.
-type cppEthereumGenesisSpecBuiltin struct {
-	Name          string                               `json:"name,omitempty"`
-	StartingBlock hexutil.Uint64                       `json:"startingBlock,omitempty"`
-	Linear        *cppEthereumGenesisSpecLinearPricing `json:"linear,omitempty"`
+// alethGenesisSpecBuiltin is the precompiled contract definition.
+type alethGenesisSpecBuiltin struct {
+	Name          string                         `json:"name,omitempty"`
+	StartingBlock hexutil.Uint64                 `json:"startingBlock,omitempty"`
+	Linear        *alethGenesisSpecLinearPricing `json:"linear,omitempty"`
 }
 
-type cppEthereumGenesisSpecLinearPricing struct {
+type alethGenesisSpecLinearPricing struct {
 	Base uint64 `json:"base"`
 	Word uint64 `json:"word"`
 }
 
-// newCppEthereumGenesisSpec converts a go-ethereum genesis block into a Parity specific
+// newAlethGenesisSpec converts a go-ethereum genesis block into a Aleth-specific
 // chain specification format.
-func newCppEthereumGenesisSpec(network string, genesis *core.Genesis) (*cppEthereumGenesisSpec, error) {
-	// Only ethash is currently supported between go-ethereum and cpp-ethereum
+func newAlethGenesisSpec(network string, genesis *core.Genesis) (*alethGenesisSpec, error) {
+	// Only ethash is currently supported between go-ethereum and aleth
 	if genesis.Config.Ethash == nil {
 		return nil, errors.New("unsupported consensus engine")
 	}
-	// Reconstruct the chain spec in Parity's format
-	spec := &cppEthereumGenesisSpec{
+	// Reconstruct the chain spec in Aleth format
+	spec := &alethGenesisSpec{
 		SealEngine: "Ethash",
 	}
+	// Some defaults
 	spec.Params.AccountStartNonce = 0
+	spec.Params.TieBreakingGas = false
+	spec.Params.AllowFutureBlocks = false
+	spec.Params.DaoHardforkBlock = 0
+
 	spec.Params.HomesteadForkBlock = (hexutil.Uint64)(genesis.Config.HomesteadBlock.Uint64())
 	spec.Params.EIP150ForkBlock = (hexutil.Uint64)(genesis.Config.EIP150Block.Uint64())
 	spec.Params.EIP158ForkBlock = (hexutil.Uint64)(genesis.Config.EIP158Block.Uint64())
-	spec.Params.ByzantiumForkBlock = (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64())
-	spec.Params.ConstantinopleForkBlock = (hexutil.Uint64)(math.MaxUint64)
+
+	// Byzantium
+	if num := genesis.Config.ByzantiumBlock; num != nil {
+		spec.setByzantium(num)
+	}
+	// Constantinople
+	if num := genesis.Config.ConstantinopleBlock; num != nil {
+		spec.setConstantinople(num)
+	}
 
 	spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
 	spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
-
 	spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
 	spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
-	spec.Params.MaxGasLimit = (hexutil.Uint64)(math.MaxUint64)
+	spec.Params.MaxGasLimit = (hexutil.Uint64)(math.MaxInt64)
 	spec.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty)
-	spec.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor)
-	spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
-	spec.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit)
+	spec.Params.DifficultyBoundDivisor = (*math2.HexOrDecimal256)(params.DifficultyBoundDivisor)
+	spec.Params.GasLimitBoundDivisor = (math2.HexOrDecimal64)(params.GasLimitBoundDivisor)
+	spec.Params.DurationLimit = (*math2.HexOrDecimal256)(params.DurationLimit)
 	spec.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward)
 
 	spec.Genesis.Nonce = (hexutil.Bytes)(make([]byte, 8))
@@ -126,77 +143,104 @@ func newCppEthereumGenesisSpec(network string, genesis *core.Genesis) (*cppEther
 	spec.Genesis.ExtraData = (hexutil.Bytes)(genesis.ExtraData)
 	spec.Genesis.GasLimit = (hexutil.Uint64)(genesis.GasLimit)
 
-	spec.Accounts = make(map[common.Address]*cppEthereumGenesisSpecAccount)
 	for address, account := range genesis.Alloc {
-		spec.Accounts[address] = &cppEthereumGenesisSpecAccount{
-			Balance: (*hexutil.Big)(account.Balance),
-			Nonce:   account.Nonce,
-		}
+		spec.setAccount(address, account)
 	}
-	spec.Accounts[common.BytesToAddress([]byte{1})].Precompiled = &cppEthereumGenesisSpecBuiltin{
-		Name: "ecrecover", Linear: &cppEthereumGenesisSpecLinearPricing{Base: 3000},
-	}
-	spec.Accounts[common.BytesToAddress([]byte{2})].Precompiled = &cppEthereumGenesisSpecBuiltin{
-		Name: "sha256", Linear: &cppEthereumGenesisSpecLinearPricing{Base: 60, Word: 12},
+
+	spec.setPrecompile(1, &alethGenesisSpecBuiltin{Name: "ecrecover",
+		Linear: &alethGenesisSpecLinearPricing{Base: 3000}})
+	spec.setPrecompile(2, &alethGenesisSpecBuiltin{Name: "sha256",
+		Linear: &alethGenesisSpecLinearPricing{Base: 60, Word: 12}})
+	spec.setPrecompile(3, &alethGenesisSpecBuiltin{Name: "ripemd160",
+		Linear: &alethGenesisSpecLinearPricing{Base: 600, Word: 120}})
+	spec.setPrecompile(4, &alethGenesisSpecBuiltin{Name: "identity",
+		Linear: &alethGenesisSpecLinearPricing{Base: 15, Word: 3}})
+	if genesis.Config.ByzantiumBlock != nil {
+		spec.setPrecompile(5, &alethGenesisSpecBuiltin{Name: "modexp",
+			StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64())})
+		spec.setPrecompile(6, &alethGenesisSpecBuiltin{Name: "alt_bn128_G1_add",
+			StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()),
+			Linear:        &alethGenesisSpecLinearPricing{Base: 500}})
+		spec.setPrecompile(7, &alethGenesisSpecBuiltin{Name: "alt_bn128_G1_mul",
+			StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()),
+			Linear:        &alethGenesisSpecLinearPricing{Base: 40000}})
+		spec.setPrecompile(8, &alethGenesisSpecBuiltin{Name: "alt_bn128_pairing_product",
+			StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64())})
 	}
-	spec.Accounts[common.BytesToAddress([]byte{3})].Precompiled = &cppEthereumGenesisSpecBuiltin{
-		Name: "ripemd160", Linear: &cppEthereumGenesisSpecLinearPricing{Base: 600, Word: 120},
+	return spec, nil
+}
+
+func (spec *alethGenesisSpec) setPrecompile(address byte, data *alethGenesisSpecBuiltin) {
+	if spec.Accounts == nil {
+		spec.Accounts = make(map[common.UnprefixedAddress]*alethGenesisSpecAccount)
 	}
-	spec.Accounts[common.BytesToAddress([]byte{4})].Precompiled = &cppEthereumGenesisSpecBuiltin{
-		Name: "identity", Linear: &cppEthereumGenesisSpecLinearPricing{Base: 15, Word: 3},
+	spec.Accounts[common.UnprefixedAddress(common.BytesToAddress([]byte{address}))].Precompiled = data
+}
+
+func (spec *alethGenesisSpec) setAccount(address common.Address, account core.GenesisAccount) {
+	if spec.Accounts == nil {
+		spec.Accounts = make(map[common.UnprefixedAddress]*alethGenesisSpecAccount)
 	}
-	if genesis.Config.ByzantiumBlock != nil {
-		spec.Accounts[common.BytesToAddress([]byte{5})].Precompiled = &cppEthereumGenesisSpecBuiltin{
-			Name: "modexp", StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()),
-		}
-		spec.Accounts[common.BytesToAddress([]byte{6})].Precompiled = &cppEthereumGenesisSpecBuiltin{
-			Name: "alt_bn128_G1_add", StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()), Linear: &cppEthereumGenesisSpecLinearPricing{Base: 500},
-		}
-		spec.Accounts[common.BytesToAddress([]byte{7})].Precompiled = &cppEthereumGenesisSpecBuiltin{
-			Name: "alt_bn128_G1_mul", StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()), Linear: &cppEthereumGenesisSpecLinearPricing{Base: 40000},
-		}
-		spec.Accounts[common.BytesToAddress([]byte{8})].Precompiled = &cppEthereumGenesisSpecBuiltin{
-			Name: "alt_bn128_pairing_product", StartingBlock: (hexutil.Uint64)(genesis.Config.ByzantiumBlock.Uint64()),
-		}
+
+	a, exist := spec.Accounts[common.UnprefixedAddress(address)]
+	if !exist {
+		a = &alethGenesisSpecAccount{}
+		spec.Accounts[common.UnprefixedAddress(address)] = a
 	}
-	return spec, nil
+	a.Balance = (*math2.HexOrDecimal256)(account.Balance)
+	a.Nonce = account.Nonce
+
+}
+
+func (spec *alethGenesisSpec) setByzantium(num *big.Int) {
+	spec.Params.ByzantiumForkBlock = hexutil.Uint64(num.Uint64())
+}
+
+func (spec *alethGenesisSpec) setConstantinople(num *big.Int) {
+	spec.Params.ConstantinopleForkBlock = hexutil.Uint64(num.Uint64())
 }
 
 // parityChainSpec is the chain specification format used by Parity.
 type parityChainSpec struct {
-	Name   string `json:"name"`
-	Engine struct {
+	Name    string `json:"name"`
+	Datadir string `json:"dataDir"`
+	Engine  struct {
 		Ethash struct {
 			Params struct {
-				MinimumDifficulty      *hexutil.Big `json:"minimumDifficulty"`
-				DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"`
-				DurationLimit          *hexutil.Big `json:"durationLimit"`
-				BlockReward            *hexutil.Big `json:"blockReward"`
-				HomesteadTransition    uint64       `json:"homesteadTransition"`
-				EIP150Transition       uint64       `json:"eip150Transition"`
-				EIP160Transition       uint64       `json:"eip160Transition"`
-				EIP161abcTransition    uint64       `json:"eip161abcTransition"`
-				EIP161dTransition      uint64       `json:"eip161dTransition"`
-				EIP649Reward           *hexutil.Big `json:"eip649Reward"`
-				EIP100bTransition      uint64       `json:"eip100bTransition"`
-				EIP649Transition       uint64       `json:"eip649Transition"`
+				MinimumDifficulty      *hexutil.Big      `json:"minimumDifficulty"`
+				DifficultyBoundDivisor *hexutil.Big      `json:"difficultyBoundDivisor"`
+				DurationLimit          *hexutil.Big      `json:"durationLimit"`
+				BlockReward            map[string]string `json:"blockReward"`
+				DifficultyBombDelays   map[string]string `json:"difficultyBombDelays"`
+				HomesteadTransition    hexutil.Uint64    `json:"homesteadTransition"`
+				EIP100bTransition      hexutil.Uint64    `json:"eip100bTransition"`
 			} `json:"params"`
 		} `json:"Ethash"`
 	} `json:"engine"`
 
 	Params struct {
-		MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"`
-		MinGasLimit          hexutil.Uint64 `json:"minGasLimit"`
-		GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"`
-		NetworkID            hexutil.Uint64 `json:"networkID"`
-		MaxCodeSize          uint64         `json:"maxCodeSize"`
-		EIP155Transition     uint64         `json:"eip155Transition"`
-		EIP98Transition      uint64         `json:"eip98Transition"`
-		EIP86Transition      uint64         `json:"eip86Transition"`
-		EIP140Transition     uint64         `json:"eip140Transition"`
-		EIP211Transition     uint64         `json:"eip211Transition"`
-		EIP214Transition     uint64         `json:"eip214Transition"`
-		EIP658Transition     uint64         `json:"eip658Transition"`
+		AccountStartNonce     hexutil.Uint64       `json:"accountStartNonce"`
+		MaximumExtraDataSize  hexutil.Uint64       `json:"maximumExtraDataSize"`
+		MinGasLimit           hexutil.Uint64       `json:"minGasLimit"`
+		GasLimitBoundDivisor  math2.HexOrDecimal64 `json:"gasLimitBoundDivisor"`
+		NetworkID             hexutil.Uint64       `json:"networkID"`
+		ChainID               hexutil.Uint64       `json:"chainID"`
+		MaxCodeSize           hexutil.Uint64       `json:"maxCodeSize"`
+		MaxCodeSizeTransition hexutil.Uint64       `json:"maxCodeSizeTransition"`
+		EIP98Transition       hexutil.Uint64       `json:"eip98Transition"`
+		EIP150Transition      hexutil.Uint64       `json:"eip150Transition"`
+		EIP160Transition      hexutil.Uint64       `json:"eip160Transition"`
+		EIP161abcTransition   hexutil.Uint64       `json:"eip161abcTransition"`
+		EIP161dTransition     hexutil.Uint64       `json:"eip161dTransition"`
+		EIP155Transition      hexutil.Uint64       `json:"eip155Transition"`
+		EIP140Transition      hexutil.Uint64       `json:"eip140Transition"`
+		EIP211Transition      hexutil.Uint64       `json:"eip211Transition"`
+		EIP214Transition      hexutil.Uint64       `json:"eip214Transition"`
+		EIP658Transition      hexutil.Uint64       `json:"eip658Transition"`
+		EIP145Transition      hexutil.Uint64       `json:"eip145Transition"`
+		EIP1014Transition     hexutil.Uint64       `json:"eip1014Transition"`
+		EIP1052Transition     hexutil.Uint64       `json:"eip1052Transition"`
+		EIP1283Transition     hexutil.Uint64       `json:"eip1283Transition"`
 	} `json:"params"`
 
 	Genesis struct {
@@ -215,22 +259,22 @@ type parityChainSpec struct {
 		GasLimit   hexutil.Uint64 `json:"gasLimit"`
 	} `json:"genesis"`
 
-	Nodes    []string                                   `json:"nodes"`
-	Accounts map[common.Address]*parityChainSpecAccount `json:"accounts"`
+	Nodes    []string                                             `json:"nodes"`
+	Accounts map[common.UnprefixedAddress]*parityChainSpecAccount `json:"accounts"`
 }
 
 // parityChainSpecAccount is the prefunded genesis account and/or precompiled
 // contract definition.
 type parityChainSpecAccount struct {
-	Balance *hexutil.Big            `json:"balance"`
-	Nonce   uint64                  `json:"nonce,omitempty"`
+	Balance math2.HexOrDecimal256   `json:"balance"`
+	Nonce   math2.HexOrDecimal64    `json:"nonce,omitempty"`
 	Builtin *parityChainSpecBuiltin `json:"builtin,omitempty"`
 }
 
 // parityChainSpecBuiltin is the precompiled contract definition.
 type parityChainSpecBuiltin struct {
 	Name       string                  `json:"name,omitempty"`
-	ActivateAt uint64                  `json:"activate_at,omitempty"`
+	ActivateAt math2.HexOrDecimal64    `json:"activate_at,omitempty"`
 	Pricing    *parityChainSpecPricing `json:"pricing,omitempty"`
 }
 
@@ -265,34 +309,51 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
 	}
 	// Reconstruct the chain spec in Parity's format
 	spec := &parityChainSpec{
-		Name:  network,
-		Nodes: bootnodes,
+		Name:    network,
+		Nodes:   bootnodes,
+		Datadir: strings.ToLower(network),
 	}
+	spec.Engine.Ethash.Params.BlockReward = make(map[string]string)
+	spec.Engine.Ethash.Params.DifficultyBombDelays = make(map[string]string)
+	// Frontier
 	spec.Engine.Ethash.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty)
 	spec.Engine.Ethash.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor)
 	spec.Engine.Ethash.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit)
-	spec.Engine.Ethash.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward)
-	spec.Engine.Ethash.Params.HomesteadTransition = genesis.Config.HomesteadBlock.Uint64()
-	spec.Engine.Ethash.Params.EIP150Transition = genesis.Config.EIP150Block.Uint64()
-	spec.Engine.Ethash.Params.EIP160Transition = genesis.Config.EIP155Block.Uint64()
-	spec.Engine.Ethash.Params.EIP161abcTransition = genesis.Config.EIP158Block.Uint64()
-	spec.Engine.Ethash.Params.EIP161dTransition = genesis.Config.EIP158Block.Uint64()
-	spec.Engine.Ethash.Params.EIP649Reward = (*hexutil.Big)(ethash.ByzantiumBlockReward)
-	spec.Engine.Ethash.Params.EIP100bTransition = genesis.Config.ByzantiumBlock.Uint64()
-	spec.Engine.Ethash.Params.EIP649Transition = genesis.Config.ByzantiumBlock.Uint64()
+	spec.Engine.Ethash.Params.BlockReward["0x0"] = hexutil.EncodeBig(ethash.FrontierBlockReward)
+
+	// Homestead
+	spec.Engine.Ethash.Params.HomesteadTransition = hexutil.Uint64(genesis.Config.HomesteadBlock.Uint64())
+
+	// Tangerine Whistle : 150
+	// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-608.md
+	spec.Params.EIP150Transition = hexutil.Uint64(genesis.Config.EIP150Block.Uint64())
+
+	// Spurious Dragon: 155, 160, 161, 170
+	// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-607.md
+	spec.Params.EIP155Transition = hexutil.Uint64(genesis.Config.EIP155Block.Uint64())
+	spec.Params.EIP160Transition = hexutil.Uint64(genesis.Config.EIP155Block.Uint64())
+	spec.Params.EIP161abcTransition = hexutil.Uint64(genesis.Config.EIP158Block.Uint64())
+	spec.Params.EIP161dTransition = hexutil.Uint64(genesis.Config.EIP158Block.Uint64())
 
+	// Byzantium
+	if num := genesis.Config.ByzantiumBlock; num != nil {
+		spec.setByzantium(num)
+	}
+	// Constantinople
+	if num := genesis.Config.ConstantinopleBlock; num != nil {
+		spec.setConstantinople(num)
+	}
 	spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize)
 	spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit)
-	spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor)
+	spec.Params.GasLimitBoundDivisor = (math2.HexOrDecimal64)(params.GasLimitBoundDivisor)
 	spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
+	spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainID.Uint64())
 	spec.Params.MaxCodeSize = params.MaxCodeSize
-	spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64()
-	spec.Params.EIP98Transition = math.MaxUint64
-	spec.Params.EIP86Transition = math.MaxUint64
-	spec.Params.EIP140Transition = genesis.Config.ByzantiumBlock.Uint64()
-	spec.Params.EIP211Transition = genesis.Config.ByzantiumBlock.Uint64()
-	spec.Params.EIP214Transition = genesis.Config.ByzantiumBlock.Uint64()
-	spec.Params.EIP658Transition = genesis.Config.ByzantiumBlock.Uint64()
+	// geth has it set from zero
+	spec.Params.MaxCodeSizeTransition = 0
+
+	// Disable this one
+	spec.Params.EIP98Transition = math.MaxInt64
 
 	spec.Genesis.Seal.Ethereum.Nonce = (hexutil.Bytes)(make([]byte, 8))
 	binary.LittleEndian.PutUint64(spec.Genesis.Seal.Ethereum.Nonce[:], genesis.Nonce)
@@ -305,42 +366,77 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin
 	spec.Genesis.ExtraData = (hexutil.Bytes)(genesis.ExtraData)
 	spec.Genesis.GasLimit = (hexutil.Uint64)(genesis.GasLimit)
 
-	spec.Accounts = make(map[common.Address]*parityChainSpecAccount)
+	spec.Accounts = make(map[common.UnprefixedAddress]*parityChainSpecAccount)
 	for address, account := range genesis.Alloc {
-		spec.Accounts[address] = &parityChainSpecAccount{
-			Balance: (*hexutil.Big)(account.Balance),
-			Nonce:   account.Nonce,
+		bal := math2.HexOrDecimal256(*account.Balance)
+
+		spec.Accounts[common.UnprefixedAddress(address)] = &parityChainSpecAccount{
+			Balance: bal,
+			Nonce:   math2.HexOrDecimal64(account.Nonce),
 		}
 	}
-	spec.Accounts[common.BytesToAddress([]byte{1})].Builtin = &parityChainSpecBuiltin{
-		Name: "ecrecover", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 3000}},
-	}
-	spec.Accounts[common.BytesToAddress([]byte{2})].Builtin = &parityChainSpecBuiltin{
+	spec.setPrecompile(1, &parityChainSpecBuiltin{Name: "ecrecover",
+		Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 3000}}})
+
+	spec.setPrecompile(2, &parityChainSpecBuiltin{
 		Name: "sha256", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 60, Word: 12}},
-	}
-	spec.Accounts[common.BytesToAddress([]byte{3})].Builtin = &parityChainSpecBuiltin{
+	})
+	spec.setPrecompile(3, &parityChainSpecBuiltin{
 		Name: "ripemd160", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 600, Word: 120}},
-	}
-	spec.Accounts[common.BytesToAddress([]byte{4})].Builtin = &parityChainSpecBuiltin{
+	})
+	spec.setPrecompile(4, &parityChainSpecBuiltin{
 		Name: "identity", Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 15, Word: 3}},
-	}
+	})
 	if genesis.Config.ByzantiumBlock != nil {
-		spec.Accounts[common.BytesToAddress([]byte{5})].Builtin = &parityChainSpecBuiltin{
-			Name: "modexp", ActivateAt: genesis.Config.ByzantiumBlock.Uint64(), Pricing: &parityChainSpecPricing{ModExp: &parityChainSpecModExpPricing{Divisor: 20}},
-		}
-		spec.Accounts[common.BytesToAddress([]byte{6})].Builtin = &parityChainSpecBuiltin{
-			Name: "alt_bn128_add", ActivateAt: genesis.Config.ByzantiumBlock.Uint64(), Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 500}},
-		}
-		spec.Accounts[common.BytesToAddress([]byte{7})].Builtin = &parityChainSpecBuiltin{
-			Name: "alt_bn128_mul", ActivateAt: genesis.Config.ByzantiumBlock.Uint64(), Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 40000}},
-		}
-		spec.Accounts[common.BytesToAddress([]byte{8})].Builtin = &parityChainSpecBuiltin{
-			Name: "alt_bn128_pairing", ActivateAt: genesis.Config.ByzantiumBlock.Uint64(), Pricing: &parityChainSpecPricing{AltBnPairing: &parityChainSpecAltBnPairingPricing{Base: 100000, Pair: 80000}},
-		}
+		blnum := math2.HexOrDecimal64(genesis.Config.ByzantiumBlock.Uint64())
+		spec.setPrecompile(5, &parityChainSpecBuiltin{
+			Name: "modexp", ActivateAt: blnum, Pricing: &parityChainSpecPricing{ModExp: &parityChainSpecModExpPricing{Divisor: 20}},
+		})
+		spec.setPrecompile(6, &parityChainSpecBuiltin{
+			Name: "alt_bn128_add", ActivateAt: blnum, Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 500}},
+		})
+		spec.setPrecompile(7, &parityChainSpecBuiltin{
+			Name: "alt_bn128_mul", ActivateAt: blnum, Pricing: &parityChainSpecPricing{Linear: &parityChainSpecLinearPricing{Base: 40000}},
+		})
+		spec.setPrecompile(8, &parityChainSpecBuiltin{
+			Name: "alt_bn128_pairing", ActivateAt: blnum, Pricing: &parityChainSpecPricing{AltBnPairing: &parityChainSpecAltBnPairingPricing{Base: 100000, Pair: 80000}},
+		})
 	}
 	return spec, nil
 }
 
+func (spec *parityChainSpec) setPrecompile(address byte, data *parityChainSpecBuiltin) {
+	if spec.Accounts == nil {
+		spec.Accounts = make(map[common.UnprefixedAddress]*parityChainSpecAccount)
+	}
+	a := common.UnprefixedAddress(common.BytesToAddress([]byte{address}))
+	if _, exist := spec.Accounts[a]; !exist {
+		spec.Accounts[a] = &parityChainSpecAccount{}
+	}
+	spec.Accounts[a].Builtin = data
+}
+
+func (spec *parityChainSpec) setByzantium(num *big.Int) {
+	spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.ByzantiumBlockReward)
+	spec.Engine.Ethash.Params.DifficultyBombDelays[hexutil.EncodeBig(num)] = hexutil.EncodeUint64(3000000)
+	n := hexutil.Uint64(num.Uint64())
+	spec.Engine.Ethash.Params.EIP100bTransition = n
+	spec.Params.EIP140Transition = n
+	spec.Params.EIP211Transition = n
+	spec.Params.EIP214Transition = n
+	spec.Params.EIP658Transition = n
+}
+
+func (spec *parityChainSpec) setConstantinople(num *big.Int) {
+	spec.Engine.Ethash.Params.BlockReward[hexutil.EncodeBig(num)] = hexutil.EncodeBig(ethash.ConstantinopleBlockReward)
+	spec.Engine.Ethash.Params.DifficultyBombDelays[hexutil.EncodeBig(num)] = hexutil.EncodeUint64(2000000)
+	n := hexutil.Uint64(num.Uint64())
+	spec.Params.EIP145Transition = n
+	spec.Params.EIP1014Transition = n
+	spec.Params.EIP1052Transition = n
+	spec.Params.EIP1283Transition = n
+}
+
 // pyEthereumGenesisSpec represents the genesis specification format used by the
 // Python Ethereum implementation.
 type pyEthereumGenesisSpec struct {

+ 1 - 1
cmd/puppeth/module_dashboard.go

@@ -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
 		}

+ 32 - 0
cmd/puppeth/puppeth.go

@@ -18,11 +18,15 @@
 package main
 
 import (
+	"encoding/json"
+	"io/ioutil"
 	"math/rand"
 	"os"
 	"strings"
 	"time"
 
+	"github.com/ethereum/go-ethereum/cmd/utils"
+	"github.com/ethereum/go-ethereum/core"
 	"github.com/ethereum/go-ethereum/log"
 	"gopkg.in/urfave/cli.v1"
 )
@@ -43,6 +47,14 @@ func main() {
 			Usage: "log level to emit to the screen",
 		},
 	}
+	app.Commands = []cli.Command{
+		cli.Command{
+			Action:    utils.MigrateFlags(convert),
+			Name:      "convert",
+			Usage:     "Convert from geth genesis into chainspecs for other nodes.",
+			ArgsUsage: "<geth-genesis.json>",
+		},
+	}
 	app.Action = 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))))
@@ -58,3 +70,23 @@ func main() {
 	}
 	app.Run(os.Args)
 }
+
+func convert(ctx *cli.Context) error {
+	// Ensure we have a source genesis
+	log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stdout, log.TerminalFormat(true))))
+	if len(ctx.Args()) != 1 {
+		utils.Fatalf("No geth genesis provided")
+	}
+	blob, err := ioutil.ReadFile(ctx.Args().First())
+	if err != nil {
+		utils.Fatalf("Could not read file: %v", err)
+	}
+
+	var genesis core.Genesis
+	if err := json.Unmarshal(blob, &genesis); err != nil {
+		utils.Fatalf("Failed parsing genesis: %v", err)
+	}
+	basename := strings.TrimRight(ctx.Args().First(), ".json")
+	convertGenesis(&genesis, basename, basename, []string{})
+	return nil
+}

+ 91 - 0
cmd/puppeth/puppeth_test.go

@@ -0,0 +1,91 @@
+package main
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"reflect"
+	"strings"
+	"testing"
+
+	"github.com/davecgh/go-spew/spew"
+	"github.com/ethereum/go-ethereum/core"
+)
+
+func TestConverter_AlethStureby(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])
+			}
+		}
+	}
+}
+
+func TestConverter_ParityStureby(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])
+			}
+		}
+	}
+}

+ 112 - 0
cmd/puppeth/testdata/stureby_aleth.json

@@ -0,0 +1,112 @@
+{
+  "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"
+      }
+    }
+  }
+}

+ 47 - 0
cmd/puppeth/testdata/stureby_geth.json

@@ -0,0 +1,47 @@
+{
+  "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"
+    }
+  }
+}

+ 181 - 0
cmd/puppeth/testdata/stureby_parity.json

@@ -0,0 +1,181 @@
+{
+  "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
+          }
+        }
+      }
+    }
+  }
+}

+ 22 - 0
cmd/puppeth/wizard.go

@@ -104,6 +104,28 @@ func (w *wizard) readString() string {
 	}
 }
 
+// readYesNo reads a yes or no from stdin, returning boolean true for yes
+func (w *wizard) readYesNo(def bool) bool {
+	for {
+		fmt.Printf("> ")
+		text, err := w.in.ReadString('\n')
+		if err != nil {
+			log.Crit("Failed to read user input", "err", err)
+		}
+		text = strings.ToLower(strings.TrimSpace(text))
+		if text == "y" || text == "yes" {
+			return true
+		}
+		if text == "n" || text == "no" {
+			return false
+		}
+		if len(text) == 0 {
+			return def
+		}
+		fmt.Println("Valid answers: y, yes, n, no or leave empty for default")
+	}
+}
+
 // readDefaultString reads a single line from stdin, trimming if from spaces. If
 // an empty line is entered, the default value is returned.
 func (w *wizard) readDefaultString(def string) string {

+ 52 - 15
cmd/puppeth/wizard_genesis.go

@@ -114,9 +114,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.readYesNo(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()
@@ -136,47 +140,57 @@ 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.ByzantiumBlock)
+		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 base filename to save the genesis specifications into? (default = %s)\n", w.network)
 		out, _ := json.MarshalIndent(w.conf.Genesis, "", "  ")
-		if err := ioutil.WriteFile(w.readDefaultString(fmt.Sprintf("%s.json", w.network)), out, 0644); err != nil {
+		basename := w.readDefaultString(fmt.Sprintf("%s.json", w.network))
+
+		gethJson := fmt.Sprintf("%s.json", basename)
+		if err := ioutil.WriteFile((gethJson), out, 0644); err != nil {
 			log.Error("Failed to save genesis file", "err", err)
 		}
-		log.Info("Exported existing genesis block")
+		log.Info("Saved geth genesis as %v", gethJson)
+		if err := convertGenesis(w.conf.Genesis, basename, w.network, w.conf.bootnodes); err != nil {
+			log.Error("Conversion failed", "err", err)
+		}
 
-	case choice == "3":
+	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 +200,31 @@ func (w *wizard) manageGenesis() {
 
 		w.conf.Genesis = nil
 		w.conf.flush()
-
 	default:
 		log.Error("That's not something I can do")
 	}
 }
+
+func saveGenesis(basename, client string, spec interface{}) {
+	filename := fmt.Sprintf("%s-%s.json", basename, client)
+	out, _ := json.Marshal(spec)
+	if err := ioutil.WriteFile(filename, out, 0644); err != nil {
+		log.Error("failed to save genesis file", "client", client, "err", err)
+	}
+	log.Info("saved chainspec", "client", client, "filename", filename)
+}
+
+func convertGenesis(genesis *core.Genesis, basename string, network string, bootnodes []string) error {
+	if spec, err := newAlethGenesisSpec(network, genesis); err == nil {
+		saveGenesis(basename, "aleth", spec)
+	} else {
+		log.Error("failed to create chain spec", "client", "aleth", "err", err)
+	}
+	if spec, err := newParityChainSpec(network, genesis, []string{}); err == nil {
+		saveGenesis(basename, "parity", spec)
+	} else {
+		log.Error("failed to create chain spec", "client", "parity", "err", err)
+	}
+	saveGenesis(basename, "harmony", genesis)
+	return nil
+}