Commit 8771c306 authored by Péter Szilágyi's avatar Péter Szilágyi Committed by GitHub

Merge pull request #3794 from fjl/core-genesis-refactor

core: refactor genesis handling
parents 11e7a712 37dd9086
...@@ -37,9 +37,6 @@ import ( ...@@ -37,9 +37,6 @@ import (
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
) )
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
var chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend. // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
var _ bind.ContractBackend = (*SimulatedBackend)(nil) var _ bind.ContractBackend = (*SimulatedBackend)(nil)
...@@ -60,11 +57,12 @@ type SimulatedBackend struct { ...@@ -60,11 +57,12 @@ type SimulatedBackend struct {
// NewSimulatedBackend creates a new binding backend using a simulated blockchain // NewSimulatedBackend creates a new binding backend using a simulated blockchain
// for testing purposes. // for testing purposes.
func NewSimulatedBackend(accounts ...core.GenesisAccount) *SimulatedBackend { func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
database, _ := ethdb.NewMemDatabase() database, _ := ethdb.NewMemDatabase()
core.WriteGenesisBlockForTesting(database, accounts...) genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc}
blockchain, _ := core.NewBlockChain(database, chainConfig, new(pow.FakePow), new(event.TypeMux), vm.Config{}) genesis.MustCommit(database)
backend := &SimulatedBackend{database: database, blockchain: blockchain} blockchain, _ := core.NewBlockChain(database, genesis.Config, new(pow.FakePow), new(event.TypeMux), vm.Config{})
backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config}
backend.rollback() backend.rollback()
return backend return backend
} }
...@@ -90,7 +88,7 @@ func (b *SimulatedBackend) Rollback() { ...@@ -90,7 +88,7 @@ func (b *SimulatedBackend) Rollback() {
} }
func (b *SimulatedBackend) rollback() { func (b *SimulatedBackend) rollback() {
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {}) blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
b.pendingBlock = blocks[0] b.pendingBlock = blocks[0]
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database) b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
} }
...@@ -253,7 +251,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM ...@@ -253,7 +251,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain) evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain)
// Create a new environment which holds all relevant information // Create a new environment which holds all relevant information
// about the transaction and calling mechanisms. // about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, chainConfig, vm.Config{}) vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
gaspool := new(core.GasPool).AddGas(math.MaxBig256) gaspool := new(core.GasPool).AddGas(math.MaxBig256)
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
return ret, gasUsed, err return ret, gasUsed, err
...@@ -274,7 +272,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa ...@@ -274,7 +272,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)) panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
} }
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) { blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() { for _, tx := range b.pendingBlock.Transactions() {
block.AddTx(tx) block.AddTx(tx)
} }
......
...@@ -169,7 +169,7 @@ var bindTests = []struct { ...@@ -169,7 +169,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy an interaction tester contract and call a transaction on it // Deploy an interaction tester contract and call a transaction on it
_, _, interactor, err := DeployInteractor(auth, sim, "Deploy string") _, _, interactor, err := DeployInteractor(auth, sim, "Deploy string")
...@@ -210,7 +210,7 @@ var bindTests = []struct { ...@@ -210,7 +210,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a tuple tester contract and execute a structured call on it // Deploy a tuple tester contract and execute a structured call on it
_, _, getter, err := DeployGetter(auth, sim) _, _, getter, err := DeployGetter(auth, sim)
...@@ -242,7 +242,7 @@ var bindTests = []struct { ...@@ -242,7 +242,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a tuple tester contract and execute a structured call on it // Deploy a tuple tester contract and execute a structured call on it
_, _, tupler, err := DeployTupler(auth, sim) _, _, tupler, err := DeployTupler(auth, sim)
...@@ -284,7 +284,7 @@ var bindTests = []struct { ...@@ -284,7 +284,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a slice tester contract and execute a n array call on it // Deploy a slice tester contract and execute a n array call on it
_, _, slicer, err := DeploySlicer(auth, sim) _, _, slicer, err := DeploySlicer(auth, sim)
...@@ -318,7 +318,7 @@ var bindTests = []struct { ...@@ -318,7 +318,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a default method invoker contract and execute its default method // Deploy a default method invoker contract and execute its default method
_, _, defaulter, err := DeployDefaulter(auth, sim) _, _, defaulter, err := DeployDefaulter(auth, sim)
...@@ -351,7 +351,7 @@ var bindTests = []struct { ...@@ -351,7 +351,7 @@ var bindTests = []struct {
`[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`, `[{"constant":true,"inputs":[],"name":"String","outputs":[{"name":"","type":"string"}],"type":"function"}]`,
` `
// Create a simulator and wrap a non-deployed contract // Create a simulator and wrap a non-deployed contract
sim := backends.NewSimulatedBackend() sim := backends.NewSimulatedBackend(nil)
nonexistent, err := NewNonExistent(common.Address{}, sim) nonexistent, err := NewNonExistent(common.Address{}, sim)
if err != nil { if err != nil {
...@@ -387,7 +387,7 @@ var bindTests = []struct { ...@@ -387,7 +387,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a funky gas pattern contract // Deploy a funky gas pattern contract
_, _, limiter, err := DeployFunkyGasPattern(auth, sim) _, _, limiter, err := DeployFunkyGasPattern(auth, sim)
...@@ -423,7 +423,7 @@ var bindTests = []struct { ...@@ -423,7 +423,7 @@ var bindTests = []struct {
// Generate a new random account and a funded simulator // Generate a new random account and a funded simulator
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
sim := backends.NewSimulatedBackend(core.GenesisAccount{Address: auth.From, Balance: big.NewInt(10000000000)}) sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}})
// Deploy a sender tester contract and execute a structured call on it // Deploy a sender tester contract and execute a structured call on it
_, _, callfrom, err := DeployCallFrom(auth, sim) _, _, callfrom, err := DeployCallFrom(auth, sim)
...@@ -458,7 +458,7 @@ func TestBindings(t *testing.T) { ...@@ -458,7 +458,7 @@ func TestBindings(t *testing.T) {
t.Skip("go sdk not found for testing") t.Skip("go sdk not found for testing")
} }
// Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845) // Skip the test if the go-ethereum sources are symlinked (https://github.com/golang/go/issues/14845)
linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend())\n}") linkTestCode := fmt.Sprintf("package linktest\nfunc CheckSymlinks(){\nfmt.Println(backends.NewSimulatedBackend(nil))\n}")
linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil) linkTestDeps, err := imports.Process("", []byte(linkTestCode), nil)
if err != nil { if err != nil {
t.Fatalf("failed check for goimports symlink bug: %v", err) t.Fatalf("failed check for goimports symlink bug: %v", err)
......
...@@ -53,9 +53,8 @@ var waitDeployedTests = map[string]struct { ...@@ -53,9 +53,8 @@ var waitDeployedTests = map[string]struct {
func TestWaitDeployed(t *testing.T) { func TestWaitDeployed(t *testing.T) {
for name, test := range waitDeployedTests { for name, test := range waitDeployedTests {
backend := backends.NewSimulatedBackend(core.GenesisAccount{ backend := backends.NewSimulatedBackend(core.GenesisAlloc{
Address: crypto.PubkeyToAddress(testKey.PublicKey), crypto.PubkeyToAddress(testKey.PublicKey): {Balance: big.NewInt(10000000000)},
Balance: big.NewInt(10000000000),
}) })
// Create the transaction. // Create the transaction.
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"runtime" "runtime"
...@@ -110,17 +111,22 @@ func initGenesis(ctx *cli.Context) error { ...@@ -110,17 +111,22 @@ func initGenesis(ctx *cli.Context) error {
stack := makeFullNode(ctx) stack := makeFullNode(ctx)
chaindb := utils.MakeChainDatabase(ctx, stack) chaindb := utils.MakeChainDatabase(ctx, stack)
genesisFile, err := os.Open(genesisPath) file, err := os.Open(genesisPath)
if err != nil { if err != nil {
utils.Fatalf("failed to read genesis file: %v", err) utils.Fatalf("failed to read genesis file: %v", err)
} }
defer genesisFile.Close() defer file.Close()
block, err := core.WriteGenesisBlock(chaindb, genesisFile) genesis := new(core.Genesis)
if err := json.NewDecoder(file).Decode(genesis); err != nil {
utils.Fatalf("invalid genesis file: %v", err)
}
_, hash, err := core.SetupGenesisBlock(chaindb, genesis)
if err != nil { if err != nil {
utils.Fatalf("failed to write genesis block: %v", err) utils.Fatalf("failed to write genesis block: %v", err)
} }
log.Info("Successfully wrote genesis state", "hash", block.Hash()) log.Info("Successfully wrote genesis state", "hash", hash)
return nil return nil
} }
......
...@@ -786,7 +786,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) { ...@@ -786,7 +786,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
ethConf := &eth.Config{ ethConf := &eth.Config{
Etherbase: MakeEtherbase(ks, ctx), Etherbase: MakeEtherbase(ks, ctx),
ChainConfig: MakeChainConfig(ctx, stack),
FastSync: ctx.GlobalBool(FastSyncFlag.Name), FastSync: ctx.GlobalBool(FastSyncFlag.Name),
LightMode: ctx.GlobalBool(LightModeFlag.Name), LightMode: ctx.GlobalBool(LightModeFlag.Name),
LightServ: ctx.GlobalInt(LightServFlag.Name), LightServ: ctx.GlobalInt(LightServFlag.Name),
...@@ -822,7 +821,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) { ...@@ -822,7 +821,6 @@ func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) {
ethConf.NetworkId = 3 ethConf.NetworkId = 3
} }
ethConf.Genesis = core.DefaultTestnetGenesisBlock() ethConf.Genesis = core.DefaultTestnetGenesisBlock()
case ctx.GlobalBool(DevModeFlag.Name): case ctx.GlobalBool(DevModeFlag.Name):
ethConf.Genesis = core.DevGenesisBlock() ethConf.Genesis = core.DevGenesisBlock()
if !ctx.GlobalIsSet(GasPriceFlag.Name) { if !ctx.GlobalIsSet(GasPriceFlag.Name) {
...@@ -884,67 +882,6 @@ func SetupNetwork(ctx *cli.Context) { ...@@ -884,67 +882,6 @@ func SetupNetwork(ctx *cli.Context) {
params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name)) params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name))
} }
// MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
func MakeChainConfig(ctx *cli.Context, stack *node.Node) *params.ChainConfig {
db := MakeChainDatabase(ctx, stack)
defer db.Close()
return MakeChainConfigFromDb(ctx, db)
}
// MakeChainConfigFromDb reads the chain configuration from the given database.
func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainConfig {
// If the chain is already initialized, use any existing chain configs
config := new(params.ChainConfig)
genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0)
if genesis != nil {
storedConfig, err := core.GetChainConfig(db, genesis.Hash())
switch err {
case nil:
config = storedConfig
case core.ChainConfigNotFoundErr:
// No configs found, use empty, will populate below
default:
Fatalf("Could not make chain configuration: %v", err)
}
}
// set chain id in case it's zero.
if config.ChainId == nil {
config.ChainId = new(big.Int)
}
// Check whether we are allowed to set default config params or not:
// - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`)
// - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet)
defaults := genesis == nil ||
(genesis.Hash() == params.MainNetGenesisHash && !ctx.GlobalBool(TestNetFlag.Name)) ||
(genesis.Hash() == params.TestNetGenesisHash && ctx.GlobalBool(TestNetFlag.Name))
if defaults {
if ctx.GlobalBool(TestNetFlag.Name) {
config = params.TestnetChainConfig
} else if ctx.GlobalBool(DevModeFlag.Name) {
config = params.AllProtocolChanges
} else {
// Homestead fork
config.HomesteadBlock = params.MainNetHomesteadBlock
// DAO fork
config.DAOForkBlock = params.MainNetDAOForkBlock
config.DAOForkSupport = true
// DoS reprice fork
config.EIP150Block = params.MainNetHomesteadGasRepriceBlock
config.EIP150Hash = params.MainNetHomesteadGasRepriceHash
// DoS state cleanup fork
config.EIP155Block = params.MainNetSpuriousDragon
config.EIP158Block = params.MainNetSpuriousDragon
config.ChainId = params.MainNetChainID
}
}
return config
}
func ChainDbName(ctx *cli.Context) string { func ChainDbName(ctx *cli.Context) string {
if ctx.GlobalBool(LightModeFlag.Name) { if ctx.GlobalBool(LightModeFlag.Name) {
return "lightchaindata" return "lightchaindata"
...@@ -968,26 +905,34 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { ...@@ -968,26 +905,34 @@ func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
return chainDb return chainDb
} }
func MakeGenesis(ctx *cli.Context) *core.Genesis {
var genesis *core.Genesis
switch {
case ctx.GlobalBool(TestNetFlag.Name):
genesis = core.DefaultTestnetGenesisBlock()
case ctx.GlobalBool(DevModeFlag.Name):
genesis = core.DevGenesisBlock()
}
return genesis
}
// MakeChain creates a chain manager from set command line flags. // MakeChain creates a chain manager from set command line flags.
func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
var err error var err error
chainDb = MakeChainDatabase(ctx, stack) chainDb = MakeChainDatabase(ctx, stack)
if ctx.GlobalBool(TestNetFlag.Name) {
_, err := core.WriteTestNetGenesisBlock(chainDb)
if err != nil {
Fatalf("Failed to write testnet genesis: %v", err)
}
}
chainConfig := MakeChainConfigFromDb(ctx, chainDb)
seal := pow.PoW(pow.FakePow{}) seal := pow.PoW(pow.FakePow{})
if !ctx.GlobalBool(FakePoWFlag.Name) { if !ctx.GlobalBool(FakePoWFlag.Name) {
seal = pow.NewFullEthash("", 1, 0, "", 1, 0) seal = pow.NewFullEthash("", 1, 0, "", 1, 0)
} }
chain, err = core.NewBlockChain(chainDb, chainConfig, seal, new(event.TypeMux), vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}) config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
if err != nil {
Fatalf("%v", err)
}
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
chain, err = core.NewBlockChain(chainDb, config, seal, new(event.TypeMux), vmcfg)
if err != nil { if err != nil {
Fatalf("Could not start chainmanager: %v", err) Fatalf("Can't create BlockChain: %v", err)
} }
return chain, chainDb return chain, chainDb
} }
......
...@@ -51,7 +51,7 @@ func (b *Bytes) UnmarshalJSON(input []byte) error { ...@@ -51,7 +51,7 @@ func (b *Bytes) UnmarshalJSON(input []byte) error {
// UnmarshalText implements encoding.TextUnmarshaler. // UnmarshalText implements encoding.TextUnmarshaler.
func (b *Bytes) UnmarshalText(input []byte) error { func (b *Bytes) UnmarshalText(input []byte) error {
raw, err := checkText(input) raw, err := checkText(input, true)
if err != nil { if err != nil {
return err return err
} }
...@@ -73,7 +73,28 @@ func (b Bytes) String() string { ...@@ -73,7 +73,28 @@ func (b Bytes) String() string {
// determines the required input length. This function is commonly used to implement the // determines the required input length. This function is commonly used to implement the
// UnmarshalText method for fixed-size types. // UnmarshalText method for fixed-size types.
func UnmarshalFixedText(typname string, input, out []byte) error { func UnmarshalFixedText(typname string, input, out []byte) error {
raw, err := checkText(input) raw, err := checkText(input, true)
if err != nil {
return err
}
if len(raw)/2 != len(out) {
return fmt.Errorf("hex string has length %d, want %d for %s", len(raw), len(out)*2, typname)
}
// Pre-verify syntax before modifying out.
for _, b := range raw {
if decodeNibble(b) == badNibble {
return ErrSyntax
}
}
hex.Decode(out, raw)
return nil
}
// UnmarshalFixedUnprefixedText decodes the input as a string with optional 0x prefix. The
// length of out determines the required input length. This function is commonly used to
// implement the UnmarshalText method for fixed-size types.
func UnmarshalFixedUnprefixedText(typname string, input, out []byte) error {
raw, err := checkText(input, false)
if err != nil { if err != nil {
return err return err
} }
...@@ -243,14 +264,15 @@ func bytesHave0xPrefix(input []byte) bool { ...@@ -243,14 +264,15 @@ func bytesHave0xPrefix(input []byte) bool {
return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') return len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X')
} }
func checkText(input []byte) ([]byte, error) { func checkText(input []byte, wantPrefix bool) ([]byte, error) {
if len(input) == 0 { if len(input) == 0 {
return nil, nil // empty strings are allowed return nil, nil // empty strings are allowed
} }
if !bytesHave0xPrefix(input) { if bytesHave0xPrefix(input) {
input = input[2:]
} else if wantPrefix {
return nil, ErrMissingPrefix return nil, ErrMissingPrefix
} }
input = input[2:]
if len(input)%2 != 0 { if len(input)%2 != 0 {
return nil, ErrOddLength return nil, ErrOddLength
} }
......
...@@ -337,3 +337,38 @@ func TestUnmarshalUint(t *testing.T) { ...@@ -337,3 +337,38 @@ func TestUnmarshalUint(t *testing.T) {
} }
} }
} }
func TestUnmarshalFixedUnprefixedText(t *testing.T) {
tests := []struct {
input string
want []byte
wantErr error
}{
{input: "0x2", wantErr: ErrOddLength},
{input: "2", wantErr: ErrOddLength},
{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
{input: "4444", wantErr: errors.New("hex string has length 4, want 8 for x")},
// check that output is not modified for partially correct input
{input: "444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
{input: "0x444444gg", wantErr: ErrSyntax, want: []byte{0, 0, 0, 0}},
// valid inputs
{input: "44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
{input: "0x44444444", want: []byte{0x44, 0x44, 0x44, 0x44}},
}
for _, test := range tests {
out := make([]byte, 4)
err := UnmarshalFixedUnprefixedText("x", []byte(test.input), out)
switch {
case err == nil && test.wantErr != nil:
t.Errorf("%q: got no error, expected %q", test.input, test.wantErr)
case err != nil && test.wantErr == nil:
t.Errorf("%q: unexpected error %q", test.input, err)
case err != nil && err.Error() != test.wantErr.Error():
t.Errorf("%q: error mismatch: got %q, want %q", test.input, err, test.wantErr)
}
if test.want != nil && !bytes.Equal(out, test.want) {
t.Errorf("%q: output mismatch: got %x, want %x", test.input, out, test.want)
}
}
}
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
package math package math
import ( import (
"fmt"
"math/big" "math/big"
) )
...@@ -35,6 +36,24 @@ const ( ...@@ -35,6 +36,24 @@ const (
wordBytes = wordBits / 8 wordBytes = wordBits / 8
) )
// HexOrDecimal256 marshals big.Int as hex or decimal.
type HexOrDecimal256 big.Int
// UnmarshalText implements encoding.TextUnmarshaler.
func (i *HexOrDecimal256) UnmarshalText(input []byte) error {
bigint, ok := ParseBig256(string(input))
if !ok {
return fmt.Errorf("invalid hex or decimal integer %q", input)
}
*i = HexOrDecimal256(*bigint)
return nil
}
// MarshalText implements encoding.TextMarshaler.
func (i *HexOrDecimal256) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%#x", (*big.Int)(i))), nil
}
// ParseBig256 parses s as a 256 bit integer in decimal or hexadecimal syntax. // ParseBig256 parses s as a 256 bit integer in decimal or hexadecimal syntax.
// Leading zeros are accepted. The empty string parses as zero. // Leading zeros are accepted. The empty string parses as zero.
func ParseBig256(s string) (*big.Int, bool) { func ParseBig256(s string) (*big.Int, bool) {
......
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
"testing" "testing"
) )
func TestParseBig256(t *testing.T) { func TestHexOrDecimal256(t *testing.T) {
tests := []struct { tests := []struct {
input string input string
num *big.Int num *big.Int
...@@ -47,13 +47,14 @@ func TestParseBig256(t *testing.T) { ...@@ -47,13 +47,14 @@ func TestParseBig256(t *testing.T) {
{"115792089237316195423570985008687907853269984665640564039457584007913129639936", nil, false}, {"115792089237316195423570985008687907853269984665640564039457584007913129639936", nil, false},
} }
for _, test := range tests { for _, test := range tests {
num, ok := ParseBig256(test.input) var num HexOrDecimal256
if ok != test.ok { err := num.UnmarshalText([]byte(test.input))
t.Errorf("ParseBig(%q) -> ok = %t, want %t", test.input, ok, test.ok) if (err == nil) != test.ok {
t.Errorf("ParseBig(%q) -> (err == nil) == %t, want %t", test.input, err == nil, test.ok)
continue continue
} }
if num != nil && test.num != nil && num.Cmp(test.num) != 0 { if test.num != nil && (*big.Int)(&num).Cmp(test.num) != 0 {
t.Errorf("ParseBig(%q) -> %d, want %d", test.input, num, test.num) t.Errorf("ParseBig(%q) -> %d, want %d", test.input, (*big.Int)(&num), test.num)
} }
} }
} }
......
...@@ -16,7 +16,10 @@ ...@@ -16,7 +16,10 @@
package math package math
import "strconv" import (
"fmt"
"strconv"
)
const ( const (
// Integer limit values. // Integer limit values.
...@@ -34,6 +37,24 @@ const ( ...@@ -34,6 +37,24 @@ const (
MaxUint64 = 1<<64 - 1 MaxUint64 = 1<<64 - 1
) )
// HexOrDecimal64 marshals uint64 as hex or decimal.
type HexOrDecimal64 uint64
// UnmarshalText implements encoding.TextUnmarshaler.
func (i *HexOrDecimal64) UnmarshalText(input []byte) error {
int, ok := ParseUint64(string(input))
if !ok {
return fmt.Errorf("invalid hex or decimal integer %q", input)
}
*i = HexOrDecimal64(int)
return nil
}
// MarshalText implements encoding.TextMarshaler.
func (i HexOrDecimal64) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%#x", uint64(i))), nil
}
// ParseUint64 parses s as an integer in decimal or hexadecimal syntax. // ParseUint64 parses s as an integer in decimal or hexadecimal syntax.
// Leading zeros are accepted. The empty string parses as zero. // Leading zeros are accepted. The empty string parses as zero.
func ParseUint64(s string) (uint64, bool) { func ParseUint64(s string) (uint64, bool) {
......
...@@ -65,7 +65,7 @@ func TestOverflow(t *testing.T) { ...@@ -65,7 +65,7 @@ func TestOverflow(t *testing.T) {
} }
} }
func TestParseUint64(t *testing.T) { func TestHexOrDecimal64(t *testing.T) {
tests := []struct { tests := []struct {
input string input string
num uint64 num uint64
...@@ -88,12 +88,13 @@ func TestParseUint64(t *testing.T) { ...@@ -88,12 +88,13 @@ func TestParseUint64(t *testing.T) {
{"18446744073709551617", 0, false}, {"18446744073709551617", 0, false},
} }
for _, test := range tests { for _, test := range tests {
num, ok := ParseUint64(test.input) var num HexOrDecimal64
if ok != test.ok { err := num.UnmarshalText([]byte(test.input))
t.Errorf("ParseUint64(%q) -> ok = %t, want %t", test.input, ok, test.ok) if (err == nil) != test.ok {
t.Errorf("ParseUint64(%q) -> (err == nil) = %t, want %t", test.input, err == nil, test.ok)
continue continue
} }
if ok && num != test.num { if err == nil && uint64(num) != test.num {
t.Errorf("ParseUint64(%q) -> %d, want %d", test.input, num, test.num) t.Errorf("ParseUint64(%q) -> %d, want %d", test.input, num, test.num)
} }
} }
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package common package common
import ( import (
"encoding/hex"
"fmt" "fmt"
"math/big" "math/big"
"math/rand" "math/rand"
...@@ -30,13 +31,8 @@ const ( ...@@ -30,13 +31,8 @@ const (
AddressLength = 20 AddressLength = 20
) )
type ( // Hash represents the 32 byte Keccak256 hash of arbitrary data.
// Hash represents the 32 byte Keccak256 hash of arbitrary data. type Hash [HashLength]byte
Hash [HashLength]byte
// Address represents the 20 byte address of an Ethereum account.
Address [AddressLength]byte
)
func BytesToHash(b []byte) Hash { func BytesToHash(b []byte) Hash {
var h Hash var h Hash
...@@ -113,7 +109,24 @@ func EmptyHash(h Hash) bool { ...@@ -113,7 +109,24 @@ func EmptyHash(h Hash) bool {
return h == Hash{} return h == Hash{}
} }
// UnprefixedHash allows marshaling a Hash without 0x prefix.
type UnprefixedHash Hash
// UnmarshalText decodes the hash from hex. The 0x prefix is optional.
func (h *UnprefixedHash) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedUnprefixedText("UnprefixedHash", input, h[:])
}
// MarshalText encodes the hash as hex.
func (h UnprefixedHash) MarshalText() ([]byte, error) {
return []byte(hex.EncodeToString(h[:])), nil
}
/////////// Address /////////// Address
// Address represents the 20 byte address of an Ethereum account.
type Address [AddressLength]byte
func BytesToAddress(b []byte) Address { func BytesToAddress(b []byte) Address {
var a Address var a Address
a.SetBytes(b) a.SetBytes(b)
...@@ -181,12 +194,15 @@ func (a *Address) UnmarshalText(input []byte) error { ...@@ -181,12 +194,15 @@ func (a *Address) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedText("Address", input, a[:]) return hexutil.UnmarshalFixedText("Address", input, a[:])
} }
// PP Pretty Prints a byte slice in the following format: // UnprefixedHash allows marshaling an Address without 0x prefix.
// hex(value[:4])...(hex[len(value)-4:]) type UnprefixedAddress Address
func PP(value []byte) string {
if len(value) <= 8 { // UnmarshalText decodes the address from hex. The 0x prefix is optional.
return Bytes2Hex(value) func (a *UnprefixedAddress) UnmarshalText(input []byte) error {
} return hexutil.UnmarshalFixedUnprefixedText("UnprefixedAddress", input, a[:])
}
return fmt.Sprintf("%x...%x", value[:4], value[len(value)-4]) // MarshalText encodes the address as hex.
func (a UnprefixedAddress) MarshalText() ([]byte, error) {
return []byte(hex.EncodeToString(a[:])), nil
} }
...@@ -21,17 +21,16 @@ import ( ...@@ -21,17 +21,16 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big"
"os" "os"
"strings" "strings"
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/internal/jsre" "github.com/ethereum/go-ethereum/internal/jsre"
"github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
) )
const ( const (
...@@ -97,9 +96,9 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester { ...@@ -97,9 +96,9 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
t.Fatalf("failed to create node: %v", err) t.Fatalf("failed to create node: %v", err)
} }
ethConf := &eth.Config{ ethConf := &eth.Config{
ChainConfig: &params.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)}, Genesis: core.DevGenesisBlock(),
Etherbase: common.HexToAddress(testAddress), Etherbase: common.HexToAddress(testAddress),
PowTest: true, PowTest: true,
} }
if confOverride != nil { if confOverride != nil {
confOverride(ethConf) confOverride(ethConf)
......
...@@ -42,11 +42,11 @@ var ( ...@@ -42,11 +42,11 @@ var (
) )
func newTestBackend() *backends.SimulatedBackend { func newTestBackend() *backends.SimulatedBackend {
return backends.NewSimulatedBackend( return backends.NewSimulatedBackend(core.GenesisAlloc{
core.GenesisAccount{Address: addr0, Balance: big.NewInt(1000000000)}, addr0: {Balance: big.NewInt(1000000000)},
core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000000)}, addr1: {Balance: big.NewInt(1000000000)},
core.GenesisAccount{Address: addr2, Balance: big.NewInt(1000000000)}, addr2: {Balance: big.NewInt(1000000000)},
) })
} }
func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) { func deploy(prvKey *ecdsa.PrivateKey, amount *big.Int, backend *backends.SimulatedBackend) (common.Address, error) {
......
...@@ -34,7 +34,7 @@ var ( ...@@ -34,7 +34,7 @@ var (
) )
func TestENS(t *testing.T) { func TestENS(t *testing.T) {
contractBackend := backends.NewSimulatedBackend(core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000000)}) contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}})
transactOpts := bind.NewKeyedTransactor(key) transactOpts := bind.NewKeyedTransactor(key)
// Workaround for bug estimating gas in the call to Register // Workaround for bug estimating gas in the call to Register
transactOpts.GasLimit = big.NewInt(1000000) transactOpts.GasLimit = big.NewInt(1000000)
......
...@@ -35,11 +35,11 @@ func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.Privat ...@@ -35,11 +35,11 @@ func setupReleaseTest(t *testing.T, prefund ...*ecdsa.PrivateKey) (*ecdsa.Privat
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
auth := bind.NewKeyedTransactor(key) auth := bind.NewKeyedTransactor(key)
accounts := []core.GenesisAccount{{Address: auth.From, Balance: big.NewInt(10000000000)}} alloc := core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}
for _, key := range prefund { for _, key := range prefund {
accounts = append(accounts, core.GenesisAccount{Address: crypto.PubkeyToAddress(key.PublicKey), Balance: big.NewInt(10000000000)}) alloc[crypto.PubkeyToAddress(key.PublicKey)] = core.GenesisAccount{Balance: big.NewInt(10000000000)}
} }
sim := backends.NewSimulatedBackend(accounts...) sim := backends.NewSimulatedBackend(alloc)
// Deploy a version oracle contract, commit and return // Deploy a version oracle contract, commit and return
_, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From}) _, _, oracle, err := DeployReleaseOracle(auth, sim, []common.Address{auth.From})
......
...@@ -166,13 +166,17 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { ...@@ -166,13 +166,17 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
// Generate a chain of b.N blocks using the supplied block // Generate a chain of b.N blocks using the supplied block
// generator function. // generator function.
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds}) gspec := Genesis{
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, b.N, gen) Config: params.TestChainConfig,
Alloc: GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}},
}
genesis := gspec.MustCommit(db)
chain, _ := GenerateChain(gspec.Config, genesis, db, b.N, gen)
// Time the insertion of the new chain. // Time the insertion of the new chain.
// State and blocks are stored in the same DB. // State and blocks are stored in the same DB.
evmux := new(event.TypeMux) evmux := new(event.TypeMux)
chainman, _ := NewBlockChain(db, &params.ChainConfig{HomesteadBlock: new(big.Int)}, pow.FakePow{}, evmux, vm.Config{}) chainman, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
defer chainman.Stop() defer chainman.Stop()
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
...@@ -282,7 +286,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { ...@@ -282,7 +286,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
if err != nil { if err != nil {
b.Fatalf("error opening database at %v: %v", dir, err) b.Fatalf("error opening database at %v: %v", dir, err)
} }
chain, err := NewBlockChain(db, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) chain, err := NewBlockChain(db, params.TestChainConfig, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if err != nil { if err != nil {
b.Fatalf("error creating chain: %v", err) b.Fatalf("error creating chain: %v", err)
} }
......
...@@ -17,51 +17,36 @@ ...@@ -17,51 +17,36 @@
package core package core
import ( import (
"fmt"
"math/big" "math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
) )
func testChainConfig() *params.ChainConfig { func testGenesis(account common.Address, balance *big.Int) *Genesis {
return params.TestChainConfig return &Genesis{
//return &params.ChainConfig{HomesteadBlock: big.NewInt(0)} Config: params.TestChainConfig,
} Alloc: GenesisAlloc{account: {Balance: balance}},
func proc() (Validator, *BlockChain) {
db, _ := ethdb.NewMemDatabase()
var mux event.TypeMux
WriteTestNetGenesisBlock(db)
blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &mux, vm.Config{})
if err != nil {
fmt.Println(err)
} }
return blockchain.validator, blockchain
} }
func TestNumber(t *testing.T) { func TestNumber(t *testing.T) {
_, chain := proc() chain := newTestBlockChain()
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb) statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
cfg := testChainConfig() header := makeHeader(chain.config, chain.Genesis(), statedb)
header := makeHeader(cfg, chain.Genesis(), statedb)
header.Number = big.NewInt(3) header.Number = big.NewInt(3)
err := ValidateHeader(cfg, pow.FakePow{}, header, chain.Genesis().Header(), false, false) err := ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
if err != BlockNumberErr { if err != BlockNumberErr {
t.Errorf("expected block number error, got %q", err) t.Errorf("expected block number error, got %q", err)
} }
header = makeHeader(cfg, chain.Genesis(), statedb) header = makeHeader(chain.config, chain.Genesis(), statedb)
err = ValidateHeader(cfg, pow.FakePow{}, header, chain.Genesis().Header(), false, false) err = ValidateHeader(chain.config, pow.FakePow{}, header, chain.Genesis().Header(), false, false)
if err == BlockNumberErr { if err == BlockNumberErr {
t.Errorf("didn't expect block number error") t.Errorf("didn't expect block number error")
} }
......
This diff is collapsed.
...@@ -30,19 +30,6 @@ import ( ...@@ -30,19 +30,6 @@ import (
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
) )
/*
* TODO: move this to another package.
*/
// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
func MakeChainConfig() *params.ChainConfig {
return &params.ChainConfig{
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
}
}
// So we can deterministically seed different blockchains // So we can deterministically seed different blockchains
var ( var (
canonicalSeed = 1 canonicalSeed = 1
...@@ -154,7 +141,7 @@ func (b *BlockGen) OffsetTime(seconds int64) { ...@@ -154,7 +141,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
if b.header.Time.Cmp(b.parent.Header().Time) <= 0 { if b.header.Time.Cmp(b.parent.Header().Time) <= 0 {
panic("block time out of range") panic("block time out of range")
} }
b.header.Difficulty = CalcDifficulty(MakeChainConfig(), b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty()) b.header.Difficulty = CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty())
} }
// GenerateChain creates a chain of n blocks. The first block's // GenerateChain creates a chain of n blocks. The first block's
...@@ -170,14 +157,13 @@ func (b *BlockGen) OffsetTime(seconds int64) { ...@@ -170,14 +157,13 @@ func (b *BlockGen) OffsetTime(seconds int64) {
// values. Inserting them into BlockChain requires use of FakePow or // values. Inserting them into BlockChain requires use of FakePow or
// a similar non-validating proof of work implementation. // a similar non-validating proof of work implementation.
func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) { func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
if config == nil {
config = params.TestChainConfig
}
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n) blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) { genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config} b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config}
// Mutate the state and block according to any hard-fork specs // Mutate the state and block according to any hard-fork specs
if config == nil {
config = MakeChainConfig()
}
if daoBlock := config.DAOForkBlock; daoBlock != nil { if daoBlock := config.DAOForkBlock; daoBlock != nil {
limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange)
if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 { if h.Number.Cmp(daoBlock) >= 0 && h.Number.Cmp(limit) < 0 {
...@@ -226,7 +212,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St ...@@ -226,7 +212,7 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
Root: state.IntermediateRoot(config.IsEIP158(parent.Number())), Root: state.IntermediateRoot(config.IsEIP158(parent.Number())),
ParentHash: parent.Hash(), ParentHash: parent.Hash(),
Coinbase: parent.Coinbase(), Coinbase: parent.Coinbase(),
Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()), Difficulty: CalcDifficulty(config, time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
GasLimit: CalcGasLimit(parent), GasLimit: CalcGasLimit(parent),
GasUsed: new(big.Int), GasUsed: new(big.Int),
Number: new(big.Int).Add(parent.Number(), common.Big1), Number: new(big.Int).Add(parent.Number(), common.Big1),
...@@ -238,14 +224,12 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St ...@@ -238,14 +224,12 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St
// chain. Depending on the full flag, if creates either a full block chain or a // chain. Depending on the full flag, if creates either a full block chain or a
// header only chain. // header only chain.
func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) { func newCanonical(n int, full bool) (ethdb.Database, *BlockChain, error) {
// Create the new chain database
db, _ := ethdb.NewMemDatabase()
evmux := &event.TypeMux{}
// Initialize a fresh chain with only a genesis block // Initialize a fresh chain with only a genesis block
genesis, _ := WriteTestNetGenesisBlock(db) gspec := new(Genesis)
db, _ := ethdb.NewMemDatabase()
genesis := gspec.MustCommit(db)
blockchain, _ := NewBlockChain(db, MakeChainConfig(), pow.FakePow{}, evmux, vm.Config{}) blockchain, _ := NewBlockChain(db, params.AllProtocolChanges, pow.FakePow{}, new(event.TypeMux), vm.Config{})
// Create and inject the requested chain // Create and inject the requested chain
if n == 0 { if n == 0 {
return db, blockchain, nil return db, blockchain, nil
......
...@@ -30,9 +30,6 @@ import ( ...@@ -30,9 +30,6 @@ import (
) )
func ExampleGenerateChain() { func ExampleGenerateChain() {
params.MinGasLimit = big.NewInt(125000) // Minimum the gas limit may ever be.
params.GenesisGasLimit = big.NewInt(3141592) // Gas limit of the Genesis block.
var ( var (
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
...@@ -41,19 +38,20 @@ func ExampleGenerateChain() { ...@@ -41,19 +38,20 @@ func ExampleGenerateChain() {
addr2 = crypto.PubkeyToAddress(key2.PublicKey) addr2 = crypto.PubkeyToAddress(key2.PublicKey)
addr3 = crypto.PubkeyToAddress(key3.PublicKey) addr3 = crypto.PubkeyToAddress(key3.PublicKey)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
signer = types.HomesteadSigner{}
) )
chainConfig := &params.ChainConfig{
HomesteadBlock: new(big.Int),
}
// Ensure that key1 has some funds in the genesis block. // Ensure that key1 has some funds in the genesis block.
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)}) gspec := &Genesis{
Config: &params.ChainConfig{HomesteadBlock: new(big.Int)},
Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
}
genesis := gspec.MustCommit(db)
// This call generates a chain of 5 blocks. The function runs for // This call generates a chain of 5 blocks. The function runs for
// each block and adds different features to gen based on the // each block and adds different features to gen based on the
// block index. // block index.
chain, _ := GenerateChain(chainConfig, genesis, db, 5, func(i int, gen *BlockGen) { signer := types.HomesteadSigner{}
chain, _ := GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
// In block 1, addr1 sends addr2 some ether. // In block 1, addr1 sends addr2 some ether.
...@@ -83,7 +81,7 @@ func ExampleGenerateChain() { ...@@ -83,7 +81,7 @@ func ExampleGenerateChain() {
// Import the chain. This runs all block validation rules. // Import the chain. This runs all block validation rules.
evmux := &event.TypeMux{} evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, chainConfig, pow.FakePow{}, evmux, vm.Config{}) blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
if i, err := blockchain.InsertChain(chain); err != nil { if i, err := blockchain.InsertChain(chain); err != nil {
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err) fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
return return
......
...@@ -67,7 +67,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) { ...@@ -67,7 +67,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
} }
// Move every DAO account and extra-balance account funds into the refund contract // Move every DAO account and extra-balance account funds into the refund contract
for _, addr := range params.DAODrainList { for _, addr := range params.DAODrainList() {
statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr)) statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
statedb.SetBalance(addr, new(big.Int)) statedb.SetBalance(addr, new(big.Int))
} }
......
...@@ -34,17 +34,18 @@ func TestDAOForkRangeExtradata(t *testing.T) { ...@@ -34,17 +34,18 @@ func TestDAOForkRangeExtradata(t *testing.T) {
// Generate a common prefix for both pro-forkers and non-forkers // Generate a common prefix for both pro-forkers and non-forkers
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
genesis := WriteGenesisBlockForTesting(db) gspec := new(Genesis)
genesis := gspec.MustCommit(db)
prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
// Create the concurrent, conflicting two nodes // Create the concurrent, conflicting two nodes
proDb, _ := ethdb.NewMemDatabase() proDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(proDb) gspec.MustCommit(proDb)
proConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true} proConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) proBc, _ := NewBlockChain(proDb, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
conDb, _ := ethdb.NewMemDatabase() conDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(conDb) gspec.MustCommit(conDb)
conConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false} conConf := &params.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
conBc, _ := NewBlockChain(conDb, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) conBc, _ := NewBlockChain(conDb, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
...@@ -58,7 +59,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { ...@@ -58,7 +59,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ {
// Create a pro-fork block, and try to feed into the no-fork chain // Create a pro-fork block, and try to feed into the no-fork chain
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db) gspec.MustCommit(db)
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1)) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
...@@ -79,7 +80,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { ...@@ -79,7 +80,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
} }
// Create a no-fork block, and try to feed into the pro-fork chain // Create a no-fork block, and try to feed into the pro-fork chain
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db) gspec.MustCommit(db)
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1)) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
...@@ -101,7 +102,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { ...@@ -101,7 +102,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
} }
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes // Verify that contra-forkers accept pro-fork extra-datas after forking finishes
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db) gspec.MustCommit(db)
bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) bc, _ := NewBlockChain(db, conConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1)) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()+1))
...@@ -117,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { ...@@ -117,7 +118,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
} }
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes // Verify that pro-forkers accept contra-fork extra-datas after forking finishes
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(db) gspec.MustCommit(db)
bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{}) bc, _ = NewBlockChain(db, proConf, new(pow.FakePow), new(event.TypeMux), vm.Config{})
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1)) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()+1))
......
...@@ -562,7 +562,7 @@ func TestMipmapChain(t *testing.T) { ...@@ -562,7 +562,7 @@ func TestMipmapChain(t *testing.T) {
) )
defer db.Close() defer db.Close()
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)}) genesis := testGenesis(addr, big.NewInt(1000000)).MustCommit(db)
chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) { chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
// generated by github.com/fjl/gencodec, do not edit.
package core
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/params"
)
func (g *Genesis) MarshalJSON() ([]byte, error) {
type GenesisJSON struct {
ChainConfig *params.ChainConfig `json:"config" optional:"true"`
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
Timestamp *math.HexOrDecimal64 `json:"timestamp" optional:"true"`
ParentHash *common.Hash `json:"parentHash" optional:"true"`
ExtraData hexutil.Bytes `json:"extraData" optional:"true"`
GasLimit *math.HexOrDecimal64 `json:"gasLimit"`
Difficulty *math.HexOrDecimal256 `json:"difficulty"`
Mixhash *common.Hash `json:"mixHash" optional:"true"`
Coinbase *common.Address `json:"coinbase" optional:"true"`
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc"`
}
var enc GenesisJSON
enc.ChainConfig = g.Config
enc.Nonce = (*math.HexOrDecimal64)(&g.Nonce)
enc.Timestamp = (*math.HexOrDecimal64)(&g.Timestamp)
enc.ParentHash = &g.ParentHash
if g.ExtraData != nil {
enc.ExtraData = g.ExtraData
}
enc.GasLimit = (*math.HexOrDecimal64)(&g.GasLimit)
enc.Difficulty = (*math.HexOrDecimal256)(g.Difficulty)
enc.Mixhash = &g.Mixhash
enc.Coinbase = &g.Coinbase
if g.Alloc != nil {
enc.Alloc = make(map[common.UnprefixedAddress]GenesisAccount, len(g.Alloc))
for k, v := range g.Alloc {
enc.Alloc[common.UnprefixedAddress(k)] = v
}
}
return json.Marshal(&enc)
}
func (g *Genesis) UnmarshalJSON(input []byte) error {
type GenesisJSON struct {
ChainConfig *params.ChainConfig `json:"config" optional:"true"`
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
Timestamp *math.HexOrDecimal64 `json:"timestamp" optional:"true"`
ParentHash *common.Hash `json:"parentHash" optional:"true"`
ExtraData hexutil.Bytes `json:"extraData" optional:"true"`
GasLimit *math.HexOrDecimal64 `json:"gasLimit"`
Difficulty *math.HexOrDecimal256 `json:"difficulty"`
Mixhash *common.Hash `json:"mixHash" optional:"true"`
Coinbase *common.Address `json:"coinbase" optional:"true"`
Alloc map[common.UnprefixedAddress]GenesisAccount `json:"alloc"`
}
var dec GenesisJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
var x Genesis
if dec.ChainConfig != nil {
x.Config = dec.ChainConfig
}
if dec.Nonce != nil {
x.Nonce = uint64(*dec.Nonce)
}
if dec.Timestamp != nil {
x.Timestamp = uint64(*dec.Timestamp)
}
if dec.ParentHash != nil {
x.ParentHash = *dec.ParentHash
}
if dec.ExtraData != nil {
x.ExtraData = dec.ExtraData
}
if dec.GasLimit == nil {
return errors.New("missing required field 'gasLimit' for Genesis")
}
x.GasLimit = uint64(*dec.GasLimit)
if dec.Difficulty == nil {
return errors.New("missing required field 'difficulty' for Genesis")
}
x.Difficulty = (*big.Int)(dec.Difficulty)
if dec.Mixhash != nil {
x.Mixhash = *dec.Mixhash
}
if dec.Coinbase != nil {
x.Coinbase = *dec.Coinbase
}
if dec.Alloc == nil {
return errors.New("missing required field 'alloc' for Genesis")
}
x.Alloc = make(GenesisAlloc, len(dec.Alloc))
for k, v := range dec.Alloc {
x.Alloc[common.Address(k)] = v
}
*g = x
return nil
}
// generated by github.com/fjl/gencodec, do not edit.
package core
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
)
func (g *GenesisAccount) MarshalJSON() ([]byte, error) {
type GenesisAccountJSON struct {
Code hexutil.Bytes `json:"code" optional:"true"`
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
Balance *math.HexOrDecimal256 `json:"balance"`
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
}
var enc GenesisAccountJSON
if g.Code != nil {
enc.Code = g.Code
}
if g.Storage != nil {
enc.Storage = g.Storage
}
enc.Balance = (*math.HexOrDecimal256)(g.Balance)
enc.Nonce = (*math.HexOrDecimal64)(&g.Nonce)
return json.Marshal(&enc)
}
func (g *GenesisAccount) UnmarshalJSON(input []byte) error {
type GenesisAccountJSON struct {
Code hexutil.Bytes `json:"code" optional:"true"`
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
Balance *math.HexOrDecimal256 `json:"balance"`
Nonce *math.HexOrDecimal64 `json:"nonce" optional:"true"`
}
var dec GenesisAccountJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
var x GenesisAccount
if dec.Code != nil {
x.Code = dec.Code
}
if dec.Storage != nil {
x.Storage = dec.Storage
}
if dec.Balance == nil {
return errors.New("missing required field 'balance' for GenesisAccount")
}
x.Balance = (*big.Int)(dec.Balance)
if dec.Nonce != nil {
x.Nonce = uint64(*dec.Nonce)
}
*g = x
return nil
}
This diff is collapsed.
This diff is collapsed.
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"math/big"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow"
)
func TestDefaultGenesisBlock(t *testing.T) {
block, _ := DefaultGenesisBlock().ToBlock()
if block.Hash() != params.MainNetGenesisHash {
t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainNetGenesisHash)
}
block, _ = DefaultTestnetGenesisBlock().ToBlock()
if block.Hash() != params.TestNetGenesisHash {
t.Errorf("wrong testnet genesis hash, got %v, want %v", block.Hash(), params.TestNetGenesisHash)
}
}
func TestSetupGenesis(t *testing.T) {
var (
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
customg = Genesis{
Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
Alloc: GenesisAlloc{
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
},
}
oldcustomg = customg
)
oldcustomg.Config = &params.ChainConfig{HomesteadBlock: big.NewInt(2)}
tests := []struct {
name string
fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
wantConfig *params.ChainConfig
wantHash common.Hash
wantErr error
}{
{
name: "genesis without ChainConfig",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, new(Genesis))
},
wantErr: errGenesisNoConfig,
wantConfig: params.AllProtocolChanges,
},
{
name: "no block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainNetGenesisHash,
wantConfig: params.MainnetChainConfig,
},
{
name: "mainnet block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
DefaultGenesisBlock().MustCommit(db)
return SetupGenesisBlock(db, nil)
},
wantHash: params.MainNetGenesisHash,
wantConfig: params.MainnetChainConfig,
},
{
name: "custom block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
customg.MustCommit(db)
return SetupGenesisBlock(db, nil)
},
wantHash: customghash,
wantConfig: customg.Config,
},
{
name: "custom block in DB, genesis == testnet",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
customg.MustCommit(db)
return SetupGenesisBlock(db, DefaultTestnetGenesisBlock())
},
wantErr: &GenesisMismatchError{Stored: customghash, New: params.TestNetGenesisHash},
wantHash: params.TestNetGenesisHash,
wantConfig: params.TestnetChainConfig,
},
{
name: "compatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
oldcustomg.MustCommit(db)
return SetupGenesisBlock(db, &customg)
},
wantHash: customghash,
wantConfig: customg.Config,
},
{
name: "incompatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
// Commit the 'old' genesis block with Homestead transition at #2.
// Advance to block #4, past the homestead transition block of customg.
genesis := oldcustomg.MustCommit(db)
bc, _ := NewBlockChain(db, oldcustomg.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
bc.SetValidator(bproc{})
bc.InsertChain(makeBlockChainWithDiff(genesis, []int{2, 3, 4, 5}, 0))
bc.CurrentBlock()
// This should return a compatibility error.
return SetupGenesisBlock(db, &customg)
},
wantHash: customghash,
wantConfig: customg.Config,
wantErr: &params.ConfigCompatError{
What: "Homestead fork block",
StoredConfig: big.NewInt(2),
NewConfig: big.NewInt(3),
RewindTo: 1,
},
},
}
for _, test := range tests {
db, _ := ethdb.NewMemDatabase()
config, hash, err := test.fn(db)
// Check the return values.
if !reflect.DeepEqual(err, test.wantErr) {
spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
}
if !reflect.DeepEqual(config, test.wantConfig) {
t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig)
}
if hash != test.wantHash {
t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
} else if err == nil {
// Check database content.
stored := GetBlock(db, test.wantHash, 0)
if stored.Hash() != test.wantHash {
t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
}
}
}
}
...@@ -97,12 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValid ...@@ -97,12 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValid
hc.genesisHeader = hc.GetHeaderByNumber(0) hc.genesisHeader = hc.GetHeaderByNumber(0)
if hc.genesisHeader == nil { if hc.genesisHeader == nil {
genesisBlock, err := WriteDefaultGenesisBlock(chainDb) return nil, ErrNoGenesis
if err != nil {
return nil, err
}
log.Warn("Wrote default Ethereum genesis block")
hc.genesisHeader = genesisBlock.Header()
} }
hc.currentHeader = hc.genesisHeader hc.currentHeader = hc.genesisHeader
......
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
// +build none
/*
The mkalloc tool creates the genesis allocation constants in genesis_alloc.go
It outputs a const declaration that contains an RLP-encoded list of (address, balance) tuples.
go run mkalloc.go genesis.json
*/
package main
import (
"encoding/json"
"fmt"
"math/big"
"os"
"sort"
"strconv"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/rlp"
)
type allocItem struct{ Addr, Balance *big.Int }
type allocList []allocItem
func (a allocList) Len() int { return len(a) }
func (a allocList) Less(i, j int) bool { return a[i].Addr.Cmp(a[j].Addr) < 0 }
func (a allocList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func makelist(g *core.Genesis) allocList {
a := make(allocList, 0, len(g.Alloc))
for addr, account := range g.Alloc {
if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
panic(fmt.Sprintf("can't encode account %x", addr))
}
a = append(a, allocItem{addr.Big(), account.Balance})
}
sort.Sort(a)
return a
}
func makealloc(g *core.Genesis) string {
a := makelist(g)
data, err := rlp.EncodeToBytes(a)
if err != nil {
panic(err)
}
return strconv.QuoteToASCII(string(data))
}
func main() {
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "Usage: mkalloc genesis.json")
os.Exit(1)
}
g := new(core.Genesis)
file, err := os.Open(os.Args[1])
if err != nil {
panic(err)
}
if err := json.NewDecoder(file).Decode(g); err != nil {
panic(err)
}
fmt.Println("const allocData =", makealloc(g))
}
...@@ -611,7 +611,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) ...@@ -611,7 +611,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
// the root hash stored in a block. // the root hash stored in a block.
func (s *StateDB) CommitBatch(deleteEmptyObjects bool) (root common.Hash, batch ethdb.Batch) { func (s *StateDB) CommitBatch(deleteEmptyObjects bool) (root common.Hash, batch ethdb.Batch) {
batch = s.db.NewBatch() batch = s.db.NewBatch()
root, _ = s.commit(batch, deleteEmptyObjects) root, _ = s.CommitTo(batch, deleteEmptyObjects)
log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads()) log.Debug("Trie cache stats after commit", "misses", trie.CacheMisses(), "unloads", trie.CacheUnloads())
return root, batch return root, batch
...@@ -623,7 +623,8 @@ func (s *StateDB) clearJournalAndRefund() { ...@@ -623,7 +623,8 @@ func (s *StateDB) clearJournalAndRefund() {
s.refund = new(big.Int) s.refund = new(big.Int)
} }
func (s *StateDB) commit(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) { // CommitTo writes the state to the given database.
func (s *StateDB) CommitTo(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
defer s.clearJournalAndRefund() defer s.clearJournalAndRefund()
// Commit objects to the trie. // Commit objects to the trie.
......
...@@ -42,7 +42,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { ...@@ -42,7 +42,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
statedb, _ := state.New(common.Hash{}, db) statedb, _ := state.New(common.Hash{}, db)
key, _ := crypto.GenerateKey() key, _ := crypto.GenerateKey()
newPool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) newPool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
newPool.resetState() newPool.resetState()
return newPool, key return newPool, key
...@@ -91,7 +91,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) { ...@@ -91,7 +91,7 @@ func TestStateChangeDuringPoolReset(t *testing.T) {
gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) } gasLimitFunc := func() *big.Int { return big.NewInt(1000000000) }
txpool := NewTxPool(testChainConfig(), mux, stateFunc, gasLimitFunc) txpool := NewTxPool(params.TestChainConfig, mux, stateFunc, gasLimitFunc)
txpool.resetState() txpool.resetState()
nonce := txpool.State().GetNonce(address) nonce := txpool.State().GetNonce(address)
...@@ -564,7 +564,7 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) { ...@@ -564,7 +564,7 @@ func TestTransactionQueueGlobalLimiting(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db) statedb, _ := state.New(common.Hash{}, db)
pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState() pool.resetState()
// Create a number of test accounts and fund them // Create a number of test accounts and fund them
...@@ -713,7 +713,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { ...@@ -713,7 +713,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db) statedb, _ := state.New(common.Hash{}, db)
pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState() pool.resetState()
// Create a number of test accounts and fund them // Create a number of test accounts and fund them
...@@ -759,7 +759,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { ...@@ -759,7 +759,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, db) statedb, _ := state.New(common.Hash{}, db)
pool := NewTxPool(testChainConfig(), new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) }) pool := NewTxPool(params.TestChainConfig, new(event.TypeMux), func() (*state.StateDB, error) { return statedb, nil }, func() *big.Int { return big.NewInt(1000000) })
pool.resetState() pool.resetState()
// Create a number of test accounts and fund them // Create a number of test accounts and fund them
......
...@@ -27,7 +27,6 @@ import ( ...@@ -27,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
...@@ -119,19 +118,6 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice ...@@ -119,19 +118,6 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice
return &Transaction{data: d} return &Transaction{data: d}
} }
func pickSigner(rules params.Rules) Signer {
var signer Signer
switch {
case rules.IsEIP155:
signer = NewEIP155Signer(rules.ChainId)
case rules.IsHomestead:
signer = HomesteadSigner{}
default:
signer = FrontierSigner{}
}
return signer
}
// ChainId returns which chain id this transaction was signed for (if at all) // ChainId returns which chain id this transaction was signed for (if at all)
func (tx *Transaction) ChainId() *big.Int { func (tx *Transaction) ChainId() *big.Int {
return deriveChainId(tx.data.V) return deriveChainId(tx.data.V)
......
...@@ -112,6 +112,9 @@ type EIP155Signer struct { ...@@ -112,6 +112,9 @@ type EIP155Signer struct {
} }
func NewEIP155Signer(chainId *big.Int) EIP155Signer { func NewEIP155Signer(chainId *big.Int) EIP155Signer {
if chainId == nil {
chainId = new(big.Int)
}
return EIP155Signer{ return EIP155Signer{
chainId: chainId, chainId: chainId,
chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)), chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)),
......
...@@ -18,11 +18,9 @@ ...@@ -18,11 +18,9 @@
package eth package eth
import ( import (
"errors"
"fmt" "fmt"
"math/big" "math/big"
"regexp" "regexp"
"strings"
"sync" "sync"
"time" "time"
...@@ -60,15 +58,17 @@ var ( ...@@ -60,15 +58,17 @@ var (
) )
type Config struct { type Config struct {
ChainConfig *params.ChainConfig // chain configuration // The genesis block, which is inserted if the database is empty.
// If nil, the Ethereum main net block is used.
Genesis *core.Genesis
NetworkId int // Network ID to use for selecting peers to connect to NetworkId int // Network ID to use for selecting peers to connect to
Genesis string // Genesis JSON to seed the chain database with
FastSync bool // Enables the state download based fast synchronisation algorithm FastSync bool // Enables the state download based fast synchronisation algorithm
LightMode bool // Running in light client mode LightMode bool // Running in light client mode
LightServ int // Maximum percentage of time allowed for serving LES requests LightServ int // Maximum percentage of time allowed for serving LES requests
LightPeers int // Maximum number of LES client peers LightPeers int // Maximum number of LES client peers
MaxPeers int // Maximum number of global peers MaxPeers int // Maximum number of global peers
SkipBcVersionCheck bool // e.g. blockchain export SkipBcVersionCheck bool // e.g. blockchain export
DatabaseCache int DatabaseCache int
...@@ -100,9 +100,6 @@ type Config struct { ...@@ -100,9 +100,6 @@ type Config struct {
GpobaseCorrectionFactor int GpobaseCorrectionFactor int
EnablePreimageRecording bool EnablePreimageRecording bool
TestGenesisBlock *types.Block // Genesis block to seed the chain database with (testing only!)
TestGenesisState ethdb.Database // Genesis state to seed the database with (testing only!)
} }
type LesServer interface { type LesServer interface {
...@@ -155,11 +152,15 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { ...@@ -155,11 +152,15 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
return nil, err return nil, err
} }
stopDbUpgrade := upgradeSequentialKeys(chainDb) stopDbUpgrade := upgradeSequentialKeys(chainDb)
if err := SetupGenesisBlock(&chainDb, config); err != nil { chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
return nil, err if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr
} }
log.Info("Initialised chain configuration", "config", chainConfig)
eth := &Ethereum{ eth := &Ethereum{
chainDb: chainDb, chainDb: chainDb,
chainConfig: chainConfig,
eventMux: ctx.EventMux, eventMux: ctx.EventMux,
accountManager: ctx.AccountManager, accountManager: ctx.AccountManager,
pow: CreatePoW(ctx, config), pow: CreatePoW(ctx, config),
...@@ -184,33 +185,18 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { ...@@ -184,33 +185,18 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
core.WriteBlockChainVersion(chainDb, core.BlockChainVersion) core.WriteBlockChainVersion(chainDb, core.BlockChainVersion)
} }
// load the genesis block or write a new one if no genesis vmConfig := vm.Config{EnablePreimageRecording: config.EnablePreimageRecording}
// block is prenent in the database. eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.eventMux, vmConfig)
genesis := core.GetBlock(chainDb, core.GetCanonicalHash(chainDb, 0), 0)
if genesis == nil {
genesis, err = core.WriteDefaultGenesisBlock(chainDb)
if err != nil {
return nil, err
}
log.Warn("Wrote default Ethereum genesis block")
}
if config.ChainConfig == nil {
return nil, errors.New("missing chain config")
}
core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
eth.chainConfig = config.ChainConfig
log.Info("Initialised chain configuration", "config", eth.chainConfig)
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux(), vm.Config{EnablePreimageRecording: config.EnablePreimageRecording})
if err != nil { if err != nil {
if err == core.ErrNoGenesis {
return nil, fmt.Errorf(`No chain found. Please initialise a new chain using the "init" subcommand.`)
}
return nil, err return nil, err
} }
// Rewind the chain in case of an incompatible config upgrade.
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
eth.blockchain.SetHead(compat.RewindTo)
core.WriteChainConfig(chainDb, genesisHash, chainConfig)
}
newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit) newPool := core.NewTxPool(eth.chainConfig, eth.EventMux(), eth.blockchain.State, eth.blockchain.GasLimit)
eth.txPool = newPool eth.txPool = newPool
...@@ -255,29 +241,6 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data ...@@ -255,29 +241,6 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data
return db, err return db, err
} }
// SetupGenesisBlock initializes the genesis block for an Ethereum service
func SetupGenesisBlock(chainDb *ethdb.Database, config *Config) error {
// Load up any custom genesis block if requested
if len(config.Genesis) > 0 {
block, err := core.WriteGenesisBlock(*chainDb, strings.NewReader(config.Genesis))
if err != nil {
return err
}
log.Info("Successfully wrote custom genesis block", "hash", block.Hash())
}
// Load up a test setup if directly injected
if config.TestGenesisState != nil {
*chainDb = config.TestGenesisState
}
if config.TestGenesisBlock != nil {
core.WriteTd(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64(), config.TestGenesisBlock.Difficulty())
core.WriteBlock(*chainDb, config.TestGenesisBlock)
core.WriteCanonicalHash(*chainDb, config.TestGenesisBlock.Hash(), config.TestGenesisBlock.NumberU64())
core.WriteHeadBlockHash(*chainDb, config.TestGenesisBlock.Hash())
}
return nil
}
// CreatePoW creates the required type of PoW instance for an Ethereum service // CreatePoW creates the required type of PoW instance for an Ethereum service
func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW { func CreatePoW(ctx *node.ServiceContext, config *Config) pow.PoW {
switch { switch {
......
...@@ -30,7 +30,7 @@ import ( ...@@ -30,7 +30,7 @@ import (
func TestMipmapUpgrade(t *testing.T) { func TestMipmapUpgrade(t *testing.T) {
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
addr := common.BytesToAddress([]byte("jeff")) addr := common.BytesToAddress([]byte("jeff"))
genesis := core.WriteGenesisBlockForTesting(db) genesis := new(core.Genesis).MustCommit(db)
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
......
...@@ -72,12 +72,11 @@ func TestBlockSubscription(t *testing.T) { ...@@ -72,12 +72,11 @@ func TestBlockSubscription(t *testing.T) {
t.Parallel() t.Parallel()
var ( var (
mux = new(event.TypeMux) mux = new(event.TypeMux)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
backend = &testBackend{mux, db} backend = &testBackend{mux, db}
api = NewPublicFilterAPI(backend, false) api = NewPublicFilterAPI(backend, false)
genesis = new(core.Genesis).MustCommit(db)
genesis = core.WriteGenesisBlockForTesting(db)
chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {}) chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
chainEvents = []core.ChainEvent{} chainEvents = []core.ChainEvent{}
) )
......
...@@ -60,7 +60,7 @@ func BenchmarkMipmaps(b *testing.B) { ...@@ -60,7 +60,7 @@ func BenchmarkMipmaps(b *testing.B) {
) )
defer db.Close() defer db.Close()
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)}) genesis := core.GenesisBlockForTesting(db, addr1, big.NewInt(1000000))
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
...@@ -112,7 +112,7 @@ func BenchmarkMipmaps(b *testing.B) { ...@@ -112,7 +112,7 @@ func BenchmarkMipmaps(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
logs, _ := filter.Find(context.Background()) logs, _ := filter.Find(context.Background())
if len(logs) != 4 { if len(logs) != 4 {
b.Fatal("expected 4 log, got", len(logs)) b.Fatal("expected 4 logs, got", len(logs))
} }
} }
} }
...@@ -138,7 +138,7 @@ func TestFilters(t *testing.T) { ...@@ -138,7 +138,7 @@ func TestFilters(t *testing.T) {
) )
defer db.Close() defer db.Close()
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)}) genesis := core.GenesisBlockForTesting(db, addr, big.NewInt(1000000))
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) { chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) {
var receipts types.Receipts var receipts types.Receipts
switch i { switch i {
......
...@@ -315,12 +315,12 @@ func testGetNodeData(t *testing.T, protocol int) { ...@@ -315,12 +315,12 @@ func testGetNodeData(t *testing.T, protocol int) {
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // In block 1, the test bank sends account #1 some ether.
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // acc1Addr passes it on to account #2.
tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
block.AddTx(tx1) block.AddTx(tx1)
block.AddTx(tx2) block.AddTx(tx2)
...@@ -372,7 +372,7 @@ func testGetNodeData(t *testing.T, protocol int) { ...@@ -372,7 +372,7 @@ func testGetNodeData(t *testing.T, protocol int) {
for i := 0; i < len(data); i++ { for i := 0; i < len(data); i++ {
statedb.Put(hashes[i].Bytes(), data[i]) statedb.Put(hashes[i].Bytes(), data[i])
} }
accounts := []common.Address{testBank.Address, acc1Addr, acc2Addr} accounts := []common.Address{testBank, acc1Addr, acc2Addr}
for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb) trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb)
...@@ -407,12 +407,12 @@ func testGetReceipt(t *testing.T, protocol int) { ...@@ -407,12 +407,12 @@ func testGetReceipt(t *testing.T, protocol int) {
switch i { switch i {
case 0: case 0:
// In block 1, the test bank sends account #1 some ether. // In block 1, the test bank sends account #1 some ether.
tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey)
block.AddTx(tx) block.AddTx(tx)
case 1: case 1:
// In block 2, the test bank sends some more ether to account #1. // In block 2, the test bank sends some more ether to account #1.
// acc1Addr passes it on to account #2. // acc1Addr passes it on to account #2.
tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey)
tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key)
block.AddTx(tx1) block.AddTx(tx1)
block.AddTx(tx2) block.AddTx(tx2)
...@@ -471,8 +471,9 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool ...@@ -471,8 +471,9 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
evmux = new(event.TypeMux) evmux = new(event.TypeMux)
pow = new(pow.FakePow) pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db)
config = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked} config = &params.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
gspec = &core.Genesis{Config: config}
genesis = gspec.MustCommit(db)
blockchain, _ = core.NewBlockChain(db, config, pow, evmux, vm.Config{}) blockchain, _ = core.NewBlockChain(db, config, pow, evmux, vm.Config{})
) )
pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db) pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)
......
...@@ -42,10 +42,7 @@ import ( ...@@ -42,10 +42,7 @@ import (
var ( var (
testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testBank = core.GenesisAccount{ testBank = crypto.PubkeyToAddress(testBankKey.PublicKey)
Address: crypto.PubkeyToAddress(testBankKey.PublicKey),
Balance: big.NewInt(1000000),
}
) )
// newTestProtocolManager creates a new protocol manager for testing purposes, // newTestProtocolManager creates a new protocol manager for testing purposes,
...@@ -53,19 +50,22 @@ var ( ...@@ -53,19 +50,22 @@ var (
// channels for different events. // channels for different events.
func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) { func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core.BlockGen), newtx chan<- []*types.Transaction) (*ProtocolManager, error) {
var ( var (
evmux = new(event.TypeMux) evmux = new(event.TypeMux)
pow = new(pow.FakePow) pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db, testBank) gspec = &core.Genesis{
chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker Config: params.TestChainConfig,
blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{}) Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
}
genesis = gspec.MustCommit(db)
blockchain, _ = core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
) )
chain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator) chain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(chain); err != nil { if _, err := blockchain.InsertChain(chain); err != nil {
panic(err) panic(err)
} }
pm, err := NewProtocolManager(chainConfig, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db) pm, err := NewProtocolManager(gspec.Config, fastSync, NetworkId, 1000, evmux, &testTxPool{added: newtx}, pow, blockchain, db)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
package les package les
import ( import (
"errors"
"fmt" "fmt"
"time" "time"
...@@ -74,15 +73,19 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { ...@@ -74,15 +73,19 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := eth.SetupGenesisBlock(&chainDb, config); err != nil { chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
return nil, err if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
return nil, genesisErr
} }
log.Info("Initialised chain configuration", "config", chainConfig)
odr := NewLesOdr(chainDb) odr := NewLesOdr(chainDb)
relay := NewLesTxRelay() relay := NewLesTxRelay()
eth := &LightEthereum{ eth := &LightEthereum{
odr: odr, odr: odr,
relay: relay, relay: relay,
chainDb: chainDb, chainDb: chainDb,
chainConfig: chainConfig,
eventMux: ctx.EventMux, eventMux: ctx.EventMux,
accountManager: ctx.AccountManager, accountManager: ctx.AccountManager,
pow: eth.CreatePoW(ctx, config), pow: eth.CreatePoW(ctx, config),
...@@ -91,17 +94,16 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) { ...@@ -91,17 +94,16 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
solcPath: config.SolcPath, solcPath: config.SolcPath,
} }
if config.ChainConfig == nil {
return nil, errors.New("missing chain config")
}
eth.chainConfig = config.ChainConfig
eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux) eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
if err != nil { if err != nil {
if err == core.ErrNoGenesis {
return nil, fmt.Errorf(`Genesis block not found. Please supply a genesis block with the "--genesis /path/to/file" argument`)
}
return nil, err return nil, err
} }
// Rewind the chain in case of an incompatible config upgrade.
if compat, ok := genesisErr.(*params.ConfigCompatError); ok {
log.Warn("Rewinding chain to upgrade configuration", "err", compat)
eth.blockchain.SetHead(compat.RewindTo)
core.WriteChainConfig(chainDb, genesisHash, chainConfig)
}
eth.txPool = light.NewTxPool(eth.chainConfig, eth.eventMux, eth.blockchain, eth.relay) eth.txPool = light.NewTxPool(eth.chainConfig, eth.eventMux, eth.blockchain, eth.relay)
if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.LightMode, config.NetworkId, eth.eventMux, eth.pow, eth.blockchain, nil, chainDb, odr, relay); err != nil { if eth.protocolManager, err = NewProtocolManager(eth.chainConfig, config.LightMode, config.NetworkId, eth.eventMux, eth.pow, eth.blockchain, nil, chainDb, odr, relay); err != nil {
......
...@@ -134,28 +134,31 @@ func testRCL() RequestCostList { ...@@ -134,28 +134,31 @@ func testRCL() RequestCostList {
// channels for different events. // channels for different events.
func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen)) (*ProtocolManager, ethdb.Database, *LesOdr, error) { func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *core.BlockGen)) (*ProtocolManager, ethdb.Database, *LesOdr, error) {
var ( var (
evmux = new(event.TypeMux) evmux = new(event.TypeMux)
pow = new(pow.FakePow) pow = new(pow.FakePow)
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds}) gspec = core.Genesis{
chainConfig = &params.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker Config: params.TestChainConfig,
odr *LesOdr Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
chain BlockChain }
genesis = gspec.MustCommit(db)
odr *LesOdr
chain BlockChain
) )
if lightSync { if lightSync {
odr = NewLesOdr(db) odr = NewLesOdr(db)
chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux) chain, _ = light.NewLightChain(odr, gspec.Config, pow, evmux)
} else { } else {
blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux, vm.Config{}) blockchain, _ := core.NewBlockChain(db, gspec.Config, pow, evmux, vm.Config{})
gchain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator) gchain, _ := core.GenerateChain(gspec.Config, genesis, db, blocks, generator)
if _, err := blockchain.InsertChain(gchain); err != nil { if _, err := blockchain.InsertChain(gchain); err != nil {
panic(err) panic(err)
} }
chain = blockchain chain = blockchain
} }
pm, err := NewProtocolManager(chainConfig, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil) pm, err := NewProtocolManager(gspec.Config, lightSync, NetworkId, evmux, pow, chain, nil, db, odr, nil)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }
......
...@@ -45,7 +45,7 @@ type LesServer struct { ...@@ -45,7 +45,7 @@ type LesServer struct {
} }
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
pm, err := NewProtocolManager(config.ChainConfig, false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil) pm, err := NewProtocolManager(eth.BlockChain().Config(), false, config.NetworkId, eth.EventMux(), eth.Pow(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -96,11 +96,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux ...@@ -96,11 +96,7 @@ func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux
bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0) bc.genesisBlock, _ = bc.GetBlockByNumber(NoOdr, 0)
if bc.genesisBlock == nil { if bc.genesisBlock == nil {
bc.genesisBlock, err = core.WriteDefaultGenesisBlock(odr.Database()) return nil, core.ErrNoGenesis
if err != nil {
return nil, err
}
log.Warn("Wrote default ethereum genesis block")
} }
if bc.genesisBlock.Hash() == params.MainNetGenesisHash { if bc.genesisBlock.Hash() == params.MainNetGenesisHash {
......
...@@ -20,7 +20,6 @@ import ( ...@@ -20,7 +20,6 @@ import (
"context" "context"
"fmt" "fmt"
"math/big" "math/big"
"runtime"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
...@@ -30,7 +29,6 @@ import ( ...@@ -30,7 +29,6 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/pow"
"github.com/hashicorp/golang-lru"
) )
// So we can deterministically seed different blockchains // So we can deterministically seed different blockchains
...@@ -59,14 +57,10 @@ func testChainConfig() *params.ChainConfig { ...@@ -59,14 +57,10 @@ func testChainConfig() *params.ChainConfig {
// chain. Depending on the full flag, if creates either a full block chain or a // chain. Depending on the full flag, if creates either a full block chain or a
// header only chain. // header only chain.
func newCanonical(n int) (ethdb.Database, *LightChain, error) { func newCanonical(n int) (ethdb.Database, *LightChain, error) {
// Create te new chain database
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
evmux := &event.TypeMux{} gspec := core.Genesis{Config: testChainConfig()}
genesis := gspec.MustCommit(db)
// Initialize a fresh chain with only a genesis block blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.FakePow{}, new(event.TypeMux))
genesis, _ := core.WriteTestNetGenesisBlock(db)
blockchain, _ := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.FakePow{}, evmux)
// Create and inject the requested chain // Create and inject the requested chain
if n == 0 { if n == 0 {
return db, blockchain, nil return db, blockchain, nil
...@@ -77,21 +71,20 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) { ...@@ -77,21 +71,20 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) {
return db, blockchain, err return db, blockchain, err
} }
func init() { // newTestLightChain creates a LightChain that doesn't validate anything.
runtime.GOMAXPROCS(runtime.NumCPU()) func newTestLightChain() *LightChain {
} db, _ := ethdb.NewMemDatabase()
gspec := &core.Genesis{
func theLightChain(db ethdb.Database, t *testing.T) *LightChain { Difficulty: big.NewInt(1),
var eventMux event.TypeMux Config: testChainConfig(),
core.WriteTestNetGenesisBlock(db) }
LightChain, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.NewTestEthash(), &eventMux) gspec.MustCommit(db)
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
if err != nil { if err != nil {
t.Error("failed creating LightChain:", err) panic(err)
t.FailNow()
return nil
} }
lc.SetValidator(bproc{})
return LightChain return lc
} }
// Test fork of length N starting from block i // Test fork of length N starting from block i
...@@ -302,20 +295,6 @@ func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error { ...@@ -302,20 +295,6 @@ func (odr *dummyOdr) Retrieve(ctx context.Context, req OdrRequest) error {
return nil return nil
} }
func chm(genesis *types.Block, db ethdb.Database) *LightChain {
odr := &dummyOdr{db: db}
var eventMux event.TypeMux
bc := &LightChain{odr: odr, chainDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: pow.FakePow{}}
bc.hc, _ = core.NewHeaderChain(db, testChainConfig(), bc.Validator, bc.getProcInterrupt)
bc.bodyCache, _ = lru.New(100)
bc.bodyRLPCache, _ = lru.New(100)
bc.blockCache, _ = lru.New(100)
bc.SetValidator(bproc{})
bc.ResetWithGenesisBlock(genesis)
return bc
}
// Tests that reorganizing a long difficult chain after a short easy one // Tests that reorganizing a long difficult chain after a short easy one
// overwrites the canonical numbers and links in the database. // overwrites the canonical numbers and links in the database.
func TestReorgLongHeaders(t *testing.T) { func TestReorgLongHeaders(t *testing.T) {
...@@ -329,14 +308,11 @@ func TestReorgShortHeaders(t *testing.T) { ...@@ -329,14 +308,11 @@ func TestReorgShortHeaders(t *testing.T) {
} }
func testReorg(t *testing.T, first, second []int, td int64) { func testReorg(t *testing.T, first, second []int, td int64) {
// Create a pristine block chain bc := newTestLightChain()
db, _ := ethdb.NewMemDatabase()
genesis, _ := core.WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
// Insert an easy and a difficult chain afterwards // Insert an easy and a difficult chain afterwards
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1) bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1) bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
// Check that the chain is valid number and link wise // Check that the chain is valid number and link wise
prev := bc.CurrentHeader() prev := bc.CurrentHeader()
for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) { for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) {
...@@ -345,7 +321,7 @@ func testReorg(t *testing.T, first, second []int, td int64) { ...@@ -345,7 +321,7 @@ func testReorg(t *testing.T, first, second []int, td int64) {
} }
} }
// Make sure the chain total difficulty is the correct one // Make sure the chain total difficulty is the correct one
want := new(big.Int).Add(genesis.Difficulty(), big.NewInt(td)) want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))
if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 { if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 {
t.Errorf("total difficulty mismatch: have %v, want %v", have, want) t.Errorf("total difficulty mismatch: have %v, want %v", have, want)
} }
...@@ -353,14 +329,11 @@ func testReorg(t *testing.T, first, second []int, td int64) { ...@@ -353,14 +329,11 @@ func testReorg(t *testing.T, first, second []int, td int64) {
// Tests that the insertion functions detect banned hashes. // Tests that the insertion functions detect banned hashes.
func TestBadHeaderHashes(t *testing.T) { func TestBadHeaderHashes(t *testing.T) {
// Create a pristine block chain bc := newTestLightChain()
db, _ := ethdb.NewMemDatabase()
genesis, _ := core.WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
// Create a chain, ban a hash and try to import // Create a chain, ban a hash and try to import
var err error var err error
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10) headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
core.BadHashes[headers[2].Hash()] = true core.BadHashes[headers[2].Hash()] = true
_, err = bc.InsertHeaderChain(headers, 1) _, err = bc.InsertHeaderChain(headers, 1)
if !core.IsBadHashError(err) { if !core.IsBadHashError(err) {
...@@ -371,13 +344,10 @@ func TestBadHeaderHashes(t *testing.T) { ...@@ -371,13 +344,10 @@ func TestBadHeaderHashes(t *testing.T) {
// Tests that bad hashes are detected on boot, and the chan rolled back to a // Tests that bad hashes are detected on boot, and the chan rolled back to a
// good state prior to the bad hash. // good state prior to the bad hash.
func TestReorgBadHeaderHashes(t *testing.T) { func TestReorgBadHeaderHashes(t *testing.T) {
// Create a pristine block chain bc := newTestLightChain()
db, _ := ethdb.NewMemDatabase()
genesis, _ := core.WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
// Create a chain, import and ban aferwards // Create a chain, import and ban aferwards
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10) headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
if _, err := bc.InsertHeaderChain(headers, 1); err != nil { if _, err := bc.InsertHeaderChain(headers, 1); err != nil {
t.Fatalf("failed to import headers: %v", err) t.Fatalf("failed to import headers: %v", err)
...@@ -387,8 +357,9 @@ func TestReorgBadHeaderHashes(t *testing.T) { ...@@ -387,8 +357,9 @@ func TestReorgBadHeaderHashes(t *testing.T) {
} }
core.BadHashes[headers[3].Hash()] = true core.BadHashes[headers[3].Hash()] = true
defer func() { delete(core.BadHashes, headers[3].Hash()) }() defer func() { delete(core.BadHashes, headers[3].Hash()) }()
// Create a new chain manager and check it rolled back the state
ncm, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.FakePow{}, new(event.TypeMux)) // Create a new LightChain and check that it rolled back the state.
ncm, err := NewLightChain(&dummyOdr{db: bc.chainDb}, testChainConfig(), pow.FakePow{}, new(event.TypeMux))
if err != nil { if err != nil {
t.Fatalf("failed to create new chain manager: %v", err) t.Fatalf("failed to create new chain manager: %v", err)
} }
......
...@@ -251,9 +251,10 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { ...@@ -251,9 +251,10 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
pow = new(pow.FakePow) pow = new(pow.FakePow)
sdb, _ = ethdb.NewMemDatabase() sdb, _ = ethdb.NewMemDatabase()
ldb, _ = ethdb.NewMemDatabase() ldb, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(sdb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds}) gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(sdb)
) )
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds}) gspec.MustCommit(ldb)
// Assemble the test environment // Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{}) blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)} chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}
......
...@@ -86,9 +86,10 @@ func TestTxPool(t *testing.T) { ...@@ -86,9 +86,10 @@ func TestTxPool(t *testing.T) {
pow = new(pow.FakePow) pow = new(pow.FakePow)
sdb, _ = ethdb.NewMemDatabase() sdb, _ = ethdb.NewMemDatabase()
ldb, _ = ethdb.NewMemDatabase() ldb, _ = ethdb.NewMemDatabase()
genesis = core.WriteGenesisBlockForTesting(sdb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds}) gspec = core.Genesis{Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}}}
genesis = gspec.MustCommit(sdb)
) )
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds}) gspec.MustCommit(ldb)
// Assemble the test environment // Assemble the test environment
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{}) blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux, vm.Config{})
chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)} chainConfig := &params.ChainConfig{HomesteadBlock: new(big.Int)}
......
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
package geth package geth
import ( import (
"encoding/json"
"fmt" "fmt"
"math/big" "math/big"
"path/filepath" "path/filepath"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethstats" "github.com/ethereum/go-ethereum/ethstats"
...@@ -92,6 +94,18 @@ func NewNodeConfig() *NodeConfig { ...@@ -92,6 +94,18 @@ func NewNodeConfig() *NodeConfig {
return &config return &config
} }
// SetMainnet sets up the node for use on the Ethereum mainnet.
func (cfg *NodeConfig) SetMainnet() {
cfg.EthereumGenesis = ""
cfg.EthereumChainConfig = MainnetChainConfig()
}
// SetTestnet sets up the node for use on the Ethereum testnet.
func (cfg *NodeConfig) SetTestnet() {
cfg.EthereumGenesis = TestnetGenesis()
cfg.EthereumChainConfig = TestnetChainConfig()
}
// Node represents a Geth Ethereum node instance. // Node represents a Geth Ethereum node instance.
type Node struct { type Node struct {
node *node.Node node *node.Node
...@@ -127,20 +141,34 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) { ...@@ -127,20 +141,34 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var genesis *core.Genesis
if config.EthereumGenesis != "" {
genesis = new(core.Genesis)
if err := json.Unmarshal([]byte(config.EthereumGenesis), genesis); err != nil {
return nil, fmt.Errorf("invalid EthereumGenesis: %v", err)
}
}
if config.EthereumChainConfig != nil {
if genesis == nil {
genesis = core.DefaultGenesisBlock()
}
genesis.Config = &params.ChainConfig{
ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
EIP150Block: big.NewInt(config.EthereumChainConfig.EIP150Block),
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
}
}
// Register the Ethereum protocol if requested // Register the Ethereum protocol if requested
if config.EthereumEnabled { if config.EthereumEnabled {
ethConf := &eth.Config{ ethConf := &eth.Config{
ChainConfig: &params.ChainConfig{ Genesis: genesis,
ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
DAOForkSupport: config.EthereumChainConfig.DAOForkSupport,
EIP150Block: big.NewInt(config.EthereumChainConfig.EIP150Block),
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
},
Genesis: config.EthereumGenesis,
LightMode: true, LightMode: true,
DatabaseCache: config.EthereumDatabaseCache, DatabaseCache: config.EthereumDatabaseCache,
NetworkId: config.EthereumNetworkID, NetworkId: config.EthereumNetworkID,
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
package geth package geth
import ( import (
"encoding/json"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/p2p/discv5" "github.com/ethereum/go-ethereum/p2p/discv5"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
...@@ -60,7 +62,11 @@ func TestnetChainConfig() *ChainConfig { ...@@ -60,7 +62,11 @@ func TestnetChainConfig() *ChainConfig {
// TestnetGenesis returns the JSON spec to use for the Ethereum test network. // TestnetGenesis returns the JSON spec to use for the Ethereum test network.
func TestnetGenesis() string { func TestnetGenesis() string {
return core.DefaultTestnetGenesisBlock() enc, err := json.Marshal(core.DefaultTestnetGenesisBlock())
if err != nil {
panic(err)
}
return string(enc)
} }
// ChainConfig is the core config which determines the blockchain settings. // ChainConfig is the core config which determines the blockchain settings.
......
...@@ -23,39 +23,43 @@ import ( ...@@ -23,39 +23,43 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
// MainnetChainConfig is the chain parameters to run a node on the main network. var (
var MainnetChainConfig = &ChainConfig{ // MainnetChainConfig is the chain parameters to run a node on the main network.
ChainId: MainNetChainID, MainnetChainConfig = &ChainConfig{
HomesteadBlock: MainNetHomesteadBlock, ChainId: MainNetChainID,
DAOForkBlock: MainNetDAOForkBlock, HomesteadBlock: MainNetHomesteadBlock,
DAOForkSupport: true, DAOForkBlock: MainNetDAOForkBlock,
EIP150Block: MainNetHomesteadGasRepriceBlock, DAOForkSupport: true,
EIP150Hash: MainNetHomesteadGasRepriceHash, EIP150Block: MainNetHomesteadGasRepriceBlock,
EIP155Block: MainNetSpuriousDragon, EIP150Hash: MainNetHomesteadGasRepriceHash,
EIP158Block: MainNetSpuriousDragon, EIP155Block: MainNetSpuriousDragon,
} EIP158Block: MainNetSpuriousDragon,
}
// TestnetChainConfig is the chain parameters to run a node on the test network.
var TestnetChainConfig = &ChainConfig{ // TestnetChainConfig contains the chain parameters to run a node on the ropsten test network.
ChainId: big.NewInt(3), TestnetChainConfig = &ChainConfig{
HomesteadBlock: big.NewInt(0), ChainId: big.NewInt(3),
DAOForkBlock: nil, HomesteadBlock: big.NewInt(0),
DAOForkSupport: true, DAOForkBlock: nil,
EIP150Block: big.NewInt(0), DAOForkSupport: true,
EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(10), EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
EIP158Block: big.NewInt(10), EIP155Block: big.NewInt(10),
} EIP158Block: big.NewInt(10),
}
// AllProtocolChanges contains every protocol change (EIPs)
// introduced and accepted by the Ethereum core developers. // AllProtocolChanges contains every protocol change (EIPs)
// // introduced and accepted by the Ethereum core developers.
// This configuration is intentionally not using keyed fields. // TestChainConfig is like AllProtocolChanges but has chain ID 1.
// This configuration must *always* have all forks enabled, which //
// means that all fields must be set at all times. This forces // This configuration is intentionally not using keyed fields.
// anyone adding flags to the config to also have to set these // This configuration must *always* have all forks enabled, which
// fields. // means that all fields must be set at all times. This forces
var AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)} // anyone adding flags to the config to also have to set these
// fields.
AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)}
)
// ChainConfig is the core config which determines the blockchain settings. // ChainConfig is the core config which determines the blockchain settings.
// //
...@@ -77,7 +81,7 @@ type ChainConfig struct { ...@@ -77,7 +81,7 @@ type ChainConfig struct {
EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block
} }
// String implements the Stringer interface. // String implements the fmt.Stringer interface.
func (c *ChainConfig) String() string { func (c *ChainConfig) String() string {
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}", return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}",
c.ChainId, c.ChainId,
...@@ -90,17 +94,26 @@ func (c *ChainConfig) String() string { ...@@ -90,17 +94,26 @@ func (c *ChainConfig) String() string {
) )
} }
var (
TestChainConfig = &ChainConfig{big.NewInt(1), new(big.Int), new(big.Int), true, new(big.Int), common.Hash{}, new(big.Int), new(big.Int)}
TestRules = TestChainConfig.Rules(new(big.Int))
)
// IsHomestead returns whether num is either equal to the homestead block or greater. // IsHomestead returns whether num is either equal to the homestead block or greater.
func (c *ChainConfig) IsHomestead(num *big.Int) bool { func (c *ChainConfig) IsHomestead(num *big.Int) bool {
if c.HomesteadBlock == nil || num == nil { return isForked(c.HomesteadBlock, num)
return false }
}
return num.Cmp(c.HomesteadBlock) >= 0 // IsDAO returns whether num is either equal to the DAO fork block or greater.
func (c *ChainConfig) IsDAOFork(num *big.Int) bool {
return isForked(c.DAOForkBlock, num)
}
func (c *ChainConfig) IsEIP150(num *big.Int) bool {
return isForked(c.EIP150Block, num)
}
func (c *ChainConfig) IsEIP155(num *big.Int) bool {
return isForked(c.EIP155Block, num)
}
func (c *ChainConfig) IsEIP158(num *big.Int) bool {
return isForked(c.EIP158Block, num)
} }
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
...@@ -110,51 +123,110 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable { ...@@ -110,51 +123,110 @@ func (c *ChainConfig) GasTable(num *big.Int) GasTable {
if num == nil { if num == nil {
return GasTableHomestead return GasTableHomestead
} }
switch { switch {
case c.EIP158Block != nil && num.Cmp(c.EIP158Block) >= 0: case c.IsEIP158(num):
return GasTableEIP158 return GasTableEIP158
case c.EIP150Block != nil && num.Cmp(c.EIP150Block) >= 0: case c.IsEIP150(num):
return GasTableHomesteadGasRepriceFork return GasTableHomesteadGasRepriceFork
default: default:
return GasTableHomestead return GasTableHomestead
} }
} }
func (c *ChainConfig) IsEIP150(num *big.Int) bool { // CheckCompatible checks whether scheduled fork transitions have been imported
if c.EIP150Block == nil || num == nil { // with a mismatching chain configuration.
return false func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError {
bhead := new(big.Int).SetUint64(height)
// Iterate checkCompatible to find the lowest conflict.
var lasterr *ConfigCompatError
for {
err := c.checkCompatible(newcfg, bhead)
if err == nil || (lasterr != nil && err.RewindTo == lasterr.RewindTo) {
break
}
lasterr = err
bhead.SetUint64(err.RewindTo)
} }
return num.Cmp(c.EIP150Block) >= 0 return lasterr
} }
func (c *ChainConfig) IsEIP155(num *big.Int) bool { func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
if c.EIP155Block == nil || num == nil { if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
return false return newCompatError("Homestead fork block", c.HomesteadBlock, newcfg.HomesteadBlock)
}
if isForkIncompatible(c.DAOForkBlock, newcfg.DAOForkBlock, head) {
return newCompatError("DAO fork block", c.DAOForkBlock, newcfg.DAOForkBlock)
} }
return num.Cmp(c.EIP155Block) >= 0 if c.IsDAOFork(head) && c.DAOForkSupport != newcfg.DAOForkSupport {
return newCompatError("DAO fork support flag", c.DAOForkBlock, newcfg.DAOForkBlock)
}
if isForkIncompatible(c.EIP150Block, newcfg.EIP150Block, head) {
return newCompatError("EIP150 fork block", c.EIP150Block, newcfg.EIP150Block)
}
if isForkIncompatible(c.EIP155Block, newcfg.EIP155Block, head) {
return newCompatError("EIP155 fork block", c.EIP155Block, newcfg.EIP155Block)
}
if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) {
return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block)
}
if c.IsEIP158(head) && !configNumEqual(c.ChainId, newcfg.ChainId) {
return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block)
}
return nil
}
// isForkIncompatible returns true if a fork scheduled at s1 cannot be rescheduled to
// block s2 because head is already past the fork.
func isForkIncompatible(s1, s2, head *big.Int) bool {
return (isForked(s1, head) || isForked(s2, head)) && !configNumEqual(s1, s2)
} }
func (c *ChainConfig) IsEIP158(num *big.Int) bool { // isForked returns whether a fork scheduled at block s is active at the given head block.
if c.EIP158Block == nil || num == nil { func isForked(s, head *big.Int) bool {
if s == nil || head == nil {
return false return false
} }
return num.Cmp(c.EIP158Block) >= 0 return s.Cmp(head) <= 0
}
func configNumEqual(x, y *big.Int) bool {
if x == nil {
return y == nil
}
if y == nil {
return x == nil
}
return x.Cmp(y) == 0
} }
// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions // ConfigCompatError is raised if the locally-stored blockchain is initialised with a
// that do not have or require information about the block. // ChainConfig that would alter the past.
// type ConfigCompatError struct {
// Rules is a one time interface meaning that it shouldn't be used in between transition What string
// phases. // block numbers of the stored and new configurations
type Rules struct { StoredConfig, NewConfig *big.Int
ChainId *big.Int // the block number to which the local chain must be rewound to correct the error
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool RewindTo uint64
}
func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
var rew *big.Int
switch {
case storedblock == nil:
rew = newblock
case newblock == nil || storedblock.Cmp(newblock) < 0:
rew = storedblock
default:
rew = newblock
}
err := &ConfigCompatError{what, storedblock, newblock, 0}
if rew != nil && rew.Sign() > 0 {
err.RewindTo = rew.Uint64() - 1
}
return err
} }
func (c *ChainConfig) Rules(num *big.Int) Rules { func (err *ConfigCompatError) Error() string {
return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num)} return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo)
} }
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package params
import (
"math/big"
"reflect"
"testing"
)
func TestCheckCompatible(t *testing.T) {
type test struct {
stored, new *ChainConfig
head uint64
wantErr *ConfigCompatError
}
tests := []test{
{stored: AllProtocolChanges, new: AllProtocolChanges, head: 0, wantErr: nil},
{stored: AllProtocolChanges, new: AllProtocolChanges, head: 100, wantErr: nil},
{
stored: &ChainConfig{EIP150Block: big.NewInt(10)},
new: &ChainConfig{EIP150Block: big.NewInt(20)},
head: 9,
wantErr: nil,
},
{
stored: AllProtocolChanges,
new: &ChainConfig{HomesteadBlock: nil},
head: 3,
wantErr: &ConfigCompatError{
What: "Homestead fork block",
StoredConfig: big.NewInt(0),
NewConfig: nil,
RewindTo: 0,
},
},
{
stored: AllProtocolChanges,
new: &ChainConfig{HomesteadBlock: big.NewInt(1)},
head: 3,
wantErr: &ConfigCompatError{
What: "Homestead fork block",
StoredConfig: big.NewInt(0),
NewConfig: big.NewInt(1),
RewindTo: 0,
},
},
{
stored: &ChainConfig{HomesteadBlock: big.NewInt(30), EIP150Block: big.NewInt(10)},
new: &ChainConfig{HomesteadBlock: big.NewInt(25), EIP150Block: big.NewInt(20)},
head: 25,
wantErr: &ConfigCompatError{
What: "EIP150 fork block",
StoredConfig: big.NewInt(10),
NewConfig: big.NewInt(20),
RewindTo: 9,
},
},
}
for _, test := range tests {
err := test.stored.CheckCompatible(test.new, test.head)
if !reflect.DeepEqual(err, test.wantErr) {
t.Errorf("error mismatch:\nstored: %v\nnew: %v\nhead: %v\nerr: %v\nwant: %v", test.stored, test.new, test.head, err, test.wantErr)
}
}
}
This diff is collapsed.
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