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

core: refactor genesis handling
This commit is contained in:
Péter Szilágyi 2017-03-23 17:36:38 +02:00 committed by GitHub
commit 8771c3061f
54 changed files with 1531 additions and 1308 deletions

View File

@ -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 {
// 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() {
} }
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
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
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)
} }

View File

@ -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 {
// 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 {
// 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 {
// 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 {
// 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 {
`[{"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 {
// 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 {
// 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) {
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)

View File

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

View File

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

View File

@ -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) {
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) {
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 {
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 { if err != nil {
Fatalf("Could not start chainmanager: %v", err) 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 {
Fatalf("Can't create BlockChain: %v", err)
} }
return chain, chainDb return chain, chainDb
} }

View File

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

View File

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

View File

@ -18,6 +18,7 @@
package math package math
import ( import (
"fmt"
"math/big" "math/big"
) )
@ -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) {

View File

@ -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) {
{"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)
} }
} }
} }

View File

@ -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 (
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) {

View File

@ -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) {
{"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)
} }
} }

View File

@ -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 (
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.
Hash [HashLength]byte type 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 {
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 {
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
} }

View File

@ -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,7 +96,7 @@ 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,
} }

View File

@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

@ -20,10 +20,6 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"math/rand" "math/rand"
"os"
"path/filepath"
"runtime"
"strconv"
"testing" "testing"
"time" "time"
@ -36,24 +32,21 @@ 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/ethereum/go-ethereum/rlp"
"github.com/hashicorp/golang-lru"
) )
func init() { // newTestBlockChain creates a blockchain without validation.
runtime.GOMAXPROCS(runtime.NumCPU()) func newTestBlockChain() *BlockChain {
db, _ := ethdb.NewMemDatabase()
gspec := &Genesis{
Config: params.TestChainConfig,
Difficulty: big.NewInt(1),
} }
gspec.MustCommit(db)
func theBlockChain(db ethdb.Database, t *testing.T) *BlockChain { blockchain, err := NewBlockChain(db, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
var eventMux event.TypeMux
WriteTestNetGenesisBlock(db)
blockchain, err := NewBlockChain(db, testChainConfig(), pow.NewTestEthash(), &eventMux, vm.Config{})
if err != nil { if err != nil {
t.Error("failed creating blockchain:", err) panic(err)
t.FailNow()
return nil
} }
blockchain.SetValidator(bproc{})
return blockchain return blockchain
} }
@ -171,21 +164,6 @@ func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error
return nil return nil
} }
func loadChain(fn string, t *testing.T) (types.Blocks, error) {
fh, err := os.OpenFile(filepath.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm)
if err != nil {
return nil, err
}
defer fh.Close()
var chain types.Blocks
if err := rlp.Decode(fh, &chain); err != nil {
return nil, err
}
return chain, nil
}
func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) { func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) {
_, err := blockchain.InsertChain(chain) _, err := blockchain.InsertChain(chain)
if err != nil { if err != nil {
@ -196,12 +174,10 @@ func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *
} }
func TestLastBlock(t *testing.T) { func TestLastBlock(t *testing.T) {
db, _ := ethdb.NewMemDatabase() bchain := newTestBlockChain()
block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0]
bchain := theBlockChain(db, t)
block := makeBlockChain(bchain.CurrentBlock(), 1, db, 0)[0]
bchain.insert(block) bchain.insert(block)
if block.Hash() != GetHeadBlockHash(db) { if block.Hash() != GetHeadBlockHash(bchain.chainDb) {
t.Errorf("Write/Get HeadBlockHash failed") t.Errorf("Write/Get HeadBlockHash failed")
} }
} }
@ -340,88 +316,6 @@ func testBrokenChain(t *testing.T, full bool) {
} }
} }
func TestChainInsertions(t *testing.T) {
t.Skip("Skipped: outdated test files")
db, _ := ethdb.NewMemDatabase()
chain1, err := loadChain("valid1", t)
if err != nil {
fmt.Println(err)
t.FailNow()
}
chain2, err := loadChain("valid2", t)
if err != nil {
fmt.Println(err)
t.FailNow()
}
blockchain := theBlockChain(db, t)
const max = 2
done := make(chan bool, max)
go insertChain(done, blockchain, chain1, t)
go insertChain(done, blockchain, chain2, t)
for i := 0; i < max; i++ {
<-done
}
if chain2[len(chain2)-1].Hash() != blockchain.CurrentBlock().Hash() {
t.Error("chain2 is canonical and shouldn't be")
}
if chain1[len(chain1)-1].Hash() != blockchain.CurrentBlock().Hash() {
t.Error("chain1 isn't canonical and should be")
}
}
func TestChainMultipleInsertions(t *testing.T) {
t.Skip("Skipped: outdated test files")
db, _ := ethdb.NewMemDatabase()
const max = 4
chains := make([]types.Blocks, max)
var longest int
for i := 0; i < max; i++ {
var err error
name := "valid" + strconv.Itoa(i+1)
chains[i], err = loadChain(name, t)
if len(chains[i]) >= len(chains[longest]) {
longest = i
}
fmt.Println("loaded", name, "with a length of", len(chains[i]))
if err != nil {
fmt.Println(err)
t.FailNow()
}
}
blockchain := theBlockChain(db, t)
done := make(chan bool, max)
for i, chain := range chains {
// XXX the go routine would otherwise reference the same (chain[3]) variable and fail
i := i
chain := chain
go func() {
insertChain(done, blockchain, chain, t)
fmt.Println(i, "done")
}()
}
for i := 0; i < max; i++ {
<-done
}
if chains[longest][len(chains[longest])-1].Hash() != blockchain.CurrentBlock().Hash() {
t.Error("Invalid canonical chain")
}
}
type bproc struct{} type bproc struct{}
func (bproc) ValidateBlock(*types.Block) error { return nil } func (bproc) ValidateBlock(*types.Block) error { return nil }
@ -452,6 +346,7 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
UncleHash: types.EmptyUncleHash, UncleHash: types.EmptyUncleHash,
TxHash: types.EmptyRootHash, TxHash: types.EmptyRootHash,
ReceiptHash: types.EmptyRootHash, ReceiptHash: types.EmptyRootHash,
Time: big.NewInt(int64(i) + 1),
} }
if i == 0 { if i == 0 {
header.ParentHash = genesis.Hash() header.ParentHash = genesis.Hash()
@ -464,29 +359,6 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
return chain return chain
} }
func chm(genesis *types.Block, db ethdb.Database) *BlockChain {
var eventMux event.TypeMux
bc := &BlockChain{
chainDb: db,
genesisBlock: genesis,
eventMux: &eventMux,
pow: pow.FakePow{},
config: testChainConfig(),
}
valFn := func() HeaderValidator { return bc.Validator() }
bc.hc, _ = NewHeaderChain(db, testChainConfig(), valFn, bc.getProcInterrupt)
bc.bodyCache, _ = lru.New(100)
bc.bodyRLPCache, _ = lru.New(100)
bc.blockCache, _ = lru.New(100)
bc.futureBlocks, _ = lru.New(100)
bc.badBlocks, _ = lru.New(10)
bc.SetValidator(bproc{})
bc.SetProcessor(bproc{})
bc.ResetWithGenesisBlock(genesis)
return bc
}
// Tests that reorganising a long difficult chain after a short easy one // Tests that reorganising 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) { testReorgLong(t, false) } func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) }
@ -506,18 +378,15 @@ func testReorgShort(t *testing.T, full bool) {
} }
func testReorg(t *testing.T, first, second []int, td int64, full bool) { func testReorg(t *testing.T, first, second []int, td int64, full bool) {
// Create a pristine block chain bc := newTestBlockChain()
db, _ := ethdb.NewMemDatabase()
genesis, _ := WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
// Insert an easy and a difficult chain afterwards // Insert an easy and a difficult chain afterwards
if full { if full {
bc.InsertChain(makeBlockChainWithDiff(genesis, first, 11)) bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11))
bc.InsertChain(makeBlockChainWithDiff(genesis, second, 22)) bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22))
} else { } else {
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
if full { if full {
@ -536,7 +405,7 @@ func testReorg(t *testing.T, first, second []int, td int64, full bool) {
} }
} }
// 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 full { if full {
if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 { if have := bc.GetTdByHash(bc.CurrentBlock().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)
@ -553,19 +422,16 @@ func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) }
func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) }
func testBadHashes(t *testing.T, full bool) { func testBadHashes(t *testing.T, full bool) {
// Create a pristine block chain bc := newTestBlockChain()
db, _ := ethdb.NewMemDatabase()
genesis, _ := 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
if full { if full {
blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 4}, 10) blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
BadHashes[blocks[2].Header().Hash()] = true BadHashes[blocks[2].Header().Hash()] = true
_, err = bc.InsertChain(blocks) _, err = bc.InsertChain(blocks)
} else { } else {
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 4}, 10) headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)
BadHashes[headers[2].Hash()] = true BadHashes[headers[2].Hash()] = true
_, err = bc.InsertHeaderChain(headers, 1) _, err = bc.InsertHeaderChain(headers, 1)
} }
@ -580,14 +446,11 @@ func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) }
func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) }
func testReorgBadHashes(t *testing.T, full bool) { func testReorgBadHashes(t *testing.T, full bool) {
// Create a pristine block chain bc := newTestBlockChain()
db, _ := ethdb.NewMemDatabase()
genesis, _ := WriteTestNetGenesisBlock(db)
bc := chm(genesis, db)
// Create a chain, import and ban afterwards // Create a chain, import and ban afterwards
headers := makeHeaderChainWithDiff(genesis, []int{1, 2, 3, 4}, 10) headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
blocks := makeBlockChainWithDiff(genesis, []int{1, 2, 3, 4}, 10) blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)
if full { if full {
if _, err := bc.InsertChain(blocks); err != nil { if _, err := bc.InsertChain(blocks); err != nil {
@ -608,8 +471,9 @@ func testReorgBadHashes(t *testing.T, full bool) {
BadHashes[headers[3].Hash()] = true BadHashes[headers[3].Hash()] = true
defer func() { delete(BadHashes, headers[3].Hash()) }() defer func() { delete(BadHashes, headers[3].Hash()) }()
} }
// Create a new chain manager and check it rolled back the state
ncm, err := NewBlockChain(db, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) // Create a new BlockChain and check that it rolled back the state.
ncm, err := NewBlockChain(bc.chainDb, bc.config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
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)
} }
@ -663,7 +527,7 @@ func testInsertNonceError(t *testing.T, full bool) {
failHash = headers[failAt].Hash() failHash = headers[failAt].Hash()
blockchain.pow = failPow{failNum} blockchain.pow = failPow{failNum}
blockchain.validator = NewBlockValidator(testChainConfig(), blockchain, failPow{failNum}) blockchain.validator = NewBlockValidator(params.TestChainConfig, blockchain, failPow{failNum})
failRes, err = blockchain.InsertHeaderChain(headers, 1) failRes, err = blockchain.InsertHeaderChain(headers, 1)
} }
@ -705,10 +569,11 @@ func TestFastVsFullChains(t *testing.T) {
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
genesis = GenesisBlockForTesting(gendb, address, funds) gspec = testGenesis(address, funds)
signer = types.NewEIP155Signer(big.NewInt(1)) genesis = gspec.MustCommit(gendb)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
) )
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) { blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, 1024, func(i int, block *BlockGen) {
block.SetCoinbase(common.Address{0x00}) block.SetCoinbase(common.Address{0x00})
// If the block number is multiple of 3, send a few bonus transactions to the miner // If the block number is multiple of 3, send a few bonus transactions to the miner
@ -728,17 +593,17 @@ func TestFastVsFullChains(t *testing.T) {
}) })
// Import the chain as an archive node for the comparison baseline // Import the chain as an archive node for the comparison baseline
archiveDb, _ := ethdb.NewMemDatabase() archiveDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds}) gspec.MustCommit(archiveDb)
archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{})
if n, err := archive.InsertChain(blocks); err != nil { if n, err := archive.InsertChain(blocks); err != nil {
t.Fatalf("failed to process block %d: %v", n, err) t.Fatalf("failed to process block %d: %v", n, err)
} }
// Fast import the chain as a non-archive node to test // Fast import the chain as a non-archive node to test
fastDb, _ := ethdb.NewMemDatabase() fastDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds}) gspec.MustCommit(fastDb)
fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {
@ -788,10 +653,11 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
genesis = GenesisBlockForTesting(gendb, address, funds) gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
genesis = gspec.MustCommit(gendb)
) )
height := uint64(1024) height := uint64(1024)
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, int(height), nil) blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, int(height), nil)
// Configure a subchain to roll back // Configure a subchain to roll back
remove := []common.Hash{} remove := []common.Hash{}
@ -812,9 +678,9 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
} }
// Import the chain as an archive node and ensure all pointers are updated // Import the chain as an archive node and ensure all pointers are updated
archiveDb, _ := ethdb.NewMemDatabase() archiveDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(archiveDb, GenesisAccount{address, funds}) gspec.MustCommit(archiveDb)
archive, _ := NewBlockChain(archiveDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) archive, _ := NewBlockChain(archiveDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if n, err := archive.InsertChain(blocks); err != nil { if n, err := archive.InsertChain(blocks); err != nil {
t.Fatalf("failed to process block %d: %v", n, err) t.Fatalf("failed to process block %d: %v", n, err)
@ -825,8 +691,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Import the chain as a non-archive node and ensure all pointers are updated // Import the chain as a non-archive node and ensure all pointers are updated
fastDb, _ := ethdb.NewMemDatabase() fastDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(fastDb, GenesisAccount{address, funds}) gspec.MustCommit(fastDb)
fast, _ := NewBlockChain(fastDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) fast, _ := NewBlockChain(fastDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
headers := make([]*types.Header, len(blocks)) headers := make([]*types.Header, len(blocks))
for i, block := range blocks { for i, block := range blocks {
@ -844,8 +710,8 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Import the chain as a light node and ensure all pointers are updated // Import the chain as a light node and ensure all pointers are updated
lightDb, _ := ethdb.NewMemDatabase() lightDb, _ := ethdb.NewMemDatabase()
WriteGenesisBlockForTesting(lightDb, GenesisAccount{address, funds}) gspec.MustCommit(lightDb)
light, _ := NewBlockChain(lightDb, testChainConfig(), pow.FakePow{}, new(event.TypeMux), vm.Config{}) light, _ := NewBlockChain(lightDb, gspec.Config, pow.FakePow{}, new(event.TypeMux), vm.Config{})
if n, err := light.InsertHeaderChain(headers, 1); err != nil { if n, err := light.InsertHeaderChain(headers, 1); err != nil {
t.Fatalf("failed to insert header %d: %v", n, err) t.Fatalf("failed to insert header %d: %v", n, err)
@ -857,9 +723,6 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
// Tests that chain reorganisations handle transaction removals and reinsertions. // Tests that chain reorganisations handle transaction removals and reinsertions.
func TestChainTxReorgs(t *testing.T) { func TestChainTxReorgs(t *testing.T) {
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")
@ -868,13 +731,19 @@ func TestChainTxReorgs(t *testing.T) {
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.NewEIP155Signer(big.NewInt(1)) gspec = &Genesis{
) Config: params.TestChainConfig,
genesis := WriteGenesisBlockForTesting(db, GasLimit: 3141592,
GenesisAccount{addr1, big.NewInt(1000000)}, Alloc: GenesisAlloc{
GenesisAccount{addr2, big.NewInt(1000000)}, addr1: {Balance: big.NewInt(1000000)},
GenesisAccount{addr3, big.NewInt(1000000)}, addr2: {Balance: big.NewInt(1000000)},
addr3: {Balance: big.NewInt(1000000)},
},
}
genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
) )
// Create two transactions shared between the chains: // Create two transactions shared between the chains:
// - postponed: transaction included at a later block in the forked chain // - postponed: transaction included at a later block in the forked chain
// - swapped: transaction included at the same block number in the forked chain // - swapped: transaction included at the same block number in the forked chain
@ -892,7 +761,7 @@ func TestChainTxReorgs(t *testing.T) {
// - futureAdd: transaction added after the reorg has already finished // - futureAdd: transaction added after the reorg has already finished
var pastAdd, freshAdd, futureAdd *types.Transaction var pastAdd, freshAdd, futureAdd *types.Transaction
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) { chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2) pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)
@ -911,13 +780,13 @@ func TestChainTxReorgs(t *testing.T) {
}) })
// 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, testChainConfig(), 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 {
t.Fatalf("failed to insert original chain[%d]: %v", i, err) t.Fatalf("failed to insert original chain[%d]: %v", i, err)
} }
// overwrite the old chain // overwrite the old chain
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) { chain, _ = GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {
switch i { switch i {
case 0: case 0:
pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3) pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)
@ -969,8 +838,6 @@ func TestChainTxReorgs(t *testing.T) {
} }
func TestLogReorgs(t *testing.T) { func TestLogReorgs(t *testing.T) {
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")
@ -978,14 +845,13 @@ func TestLogReorgs(t *testing.T) {
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
// this code generates a log // this code generates a log
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
signer = types.NewEIP155Signer(big.NewInt(1)) gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}
) genesis = gspec.MustCommit(db)
genesis := WriteGenesisBlockForTesting(db, signer = types.NewEIP155Signer(gspec.Config.ChainId)
GenesisAccount{addr1, big.NewInt(10000000000000)},
) )
evmux := &event.TypeMux{} var evmux event.TypeMux
blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{}) blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &evmux, vm.Config{})
subs := evmux.Subscribe(RemovedLogsEvent{}) subs := evmux.Subscribe(RemovedLogsEvent{})
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) { chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
@ -1017,19 +883,20 @@ func TestReorgSideEvent(t *testing.T) {
db, _ = ethdb.NewMemDatabase() db, _ = ethdb.NewMemDatabase()
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey) addr1 = crypto.PubkeyToAddress(key1.PublicKey)
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)}) gspec = testGenesis(addr1, big.NewInt(10000000000000))
signer = types.NewEIP155Signer(big.NewInt(1)) genesis = gspec.MustCommit(db)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
) )
evmux := &event.TypeMux{} evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{}) blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, evmux, vm.Config{})
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {}) chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {})
if _, err := blockchain.InsertChain(chain); err != nil { if _, err := blockchain.InsertChain(chain); err != nil {
t.Fatalf("failed to insert chain: %v", err) t.Fatalf("failed to insert chain: %v", err)
} }
replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) { replacementBlocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1) tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)
if i == 2 { if i == 2 {
gen.OffsetTime(-1) gen.OffsetTime(-1)
@ -1092,28 +959,21 @@ done:
// Tests if the canonical block can be fetched from the database during chain insertion. // Tests if the canonical block can be fetched from the database during chain insertion.
func TestCanonicalBlockRetrieval(t *testing.T) { func TestCanonicalBlockRetrieval(t *testing.T) {
var ( bc := newTestBlockChain()
db, _ = ethdb.NewMemDatabase() chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {})
genesis = WriteGenesisBlockForTesting(db)
)
evmux := &event.TypeMux{}
blockchain, _ := NewBlockChain(db, testChainConfig(), pow.FakePow{}, evmux, vm.Config{})
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
for i := range chain { for i := range chain {
go func(block *types.Block) { go func(block *types.Block) {
// try to retrieve a block by its canonical hash and see if the block data can be retrieved. // try to retrieve a block by its canonical hash and see if the block data can be retrieved.
for { for {
ch := GetCanonicalHash(db, block.NumberU64()) ch := GetCanonicalHash(bc.chainDb, block.NumberU64())
if ch == (common.Hash{}) { if ch == (common.Hash{}) {
continue // busy wait for canonical hash to be written continue // busy wait for canonical hash to be written
} }
if ch != block.Hash() { if ch != block.Hash() {
t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex()) t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())
} }
fb := GetBlock(db, ch, block.NumberU64()) fb := GetBlock(bc.chainDb, ch, block.NumberU64())
if fb == nil { if fb == nil {
t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex()) t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())
} }
@ -1124,7 +984,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
} }
}(chain[i]) }(chain[i])
blockchain.InsertChain(types.Blocks{chain[i]}) bc.InsertChain(types.Blocks{chain[i]})
} }
} }
@ -1136,13 +996,16 @@ func TestEIP155Transition(t *testing.T) {
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
deleteAddr = common.Address{1} deleteAddr = common.Address{1}
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds}, GenesisAccount{deleteAddr, new(big.Int)}) gspec = &Genesis{
config = &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} Config: &params.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
}
genesis = gspec.MustCommit(db)
mux event.TypeMux mux event.TypeMux
) )
blockchain, _ := NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{}) blockchain, _ := NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) { blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) {
var ( var (
tx *types.Transaction tx *types.Transaction
err error err error
@ -1164,7 +1027,7 @@ func TestEIP155Transition(t *testing.T) {
} }
block.AddTx(tx) block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(config.ChainId)) tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1176,7 +1039,7 @@ func TestEIP155Transition(t *testing.T) {
} }
block.AddTx(tx) block.AddTx(tx)
tx, err = basicTx(types.NewEIP155Signer(config.ChainId)) tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1204,7 +1067,7 @@ func TestEIP155Transition(t *testing.T) {
} }
// generate an invalid chain id transaction // generate an invalid chain id transaction
config = &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} config := &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) { blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
var ( var (
tx *types.Transaction tx *types.Transaction
@ -1236,22 +1099,24 @@ func TestEIP161AccountRemoval(t *testing.T) {
address = crypto.PubkeyToAddress(key.PublicKey) address = crypto.PubkeyToAddress(key.PublicKey)
funds = big.NewInt(1000000000) funds = big.NewInt(1000000000)
theAddr = common.Address{1} theAddr = common.Address{1}
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds}) gspec = &Genesis{
config = &params.ChainConfig{ Config: &params.ChainConfig{
ChainId: big.NewInt(1), ChainId: big.NewInt(1),
HomesteadBlock: new(big.Int), HomesteadBlock: new(big.Int),
EIP155Block: new(big.Int), EIP155Block: new(big.Int),
EIP158Block: big.NewInt(2), EIP158Block: big.NewInt(2),
},
Alloc: GenesisAlloc{address: {Balance: funds}},
} }
genesis = gspec.MustCommit(db)
mux event.TypeMux mux event.TypeMux
blockchain, _ = NewBlockChain(db, gspec.Config, pow.FakePow{}, &mux, vm.Config{})
blockchain, _ = NewBlockChain(db, config, pow.FakePow{}, &mux, vm.Config{})
) )
blocks, _ := GenerateChain(config, genesis, db, 3, func(i int, block *BlockGen) { blocks, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, block *BlockGen) {
var ( var (
tx *types.Transaction tx *types.Transaction
err error err error
signer = types.NewEIP155Signer(config.ChainId) signer = types.NewEIP155Signer(gspec.Config.ChainId)
) )
switch i { switch i {
case 0: case 0:
@ -1279,7 +1144,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if blockchain.stateCache.Exist(theAddr) { if blockchain.stateCache.Exist(theAddr) {
t.Error("account should not expect") t.Error("account should not exist")
} }
// account musn't be created post eip 161 // account musn't be created post eip 161
@ -1287,6 +1152,6 @@ func TestEIP161AccountRemoval(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if blockchain.stateCache.Exist(theAddr) { if blockchain.stateCache.Exist(theAddr) {
t.Error("account should not expect") t.Error("account should not exist")
} }
} }

View File

@ -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) {
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) {
// 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
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
// 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

View File

@ -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() {
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() {
// 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

View File

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

View File

@ -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) {
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) {
} }
// 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) {
} }
// 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) {
} }
// 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))

View File

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

File diff suppressed because one or more lines are too long

106
core/gen_genesis.go Normal file
View File

@ -0,0 +1,106 @@
// 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
}

View File

@ -0,0 +1,61 @@
// 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
}

View File

@ -17,230 +17,286 @@
package core package core
import ( import (
"compress/bzip2" "errors"
"compress/gzip"
"encoding/base64"
"encoding/json"
"fmt" "fmt"
"io"
"io/ioutil"
"math/big" "math/big"
"strings" "strings"
"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/math" "github.com/ethereum/go-ethereum/common/math"
"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/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
) )
// WriteGenesisBlock writes the genesis block to the database as block number 0 //go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go
func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block, error) { //go:generate gencodec -type GenesisAccount -field-override genesisAccountMarshaling -out gen_genesis_account.go
contents, err := ioutil.ReadAll(reader)
var errGenesisNoConfig = errors.New("genesis has no chain configuration")
// Genesis specifies the header fields, state of a genesis block. It also defines hard
// fork switch-over blocks through the chain configuration.
type Genesis struct {
Config *params.ChainConfig `json:"config" optional:"true"`
Nonce uint64 `json:"nonce" optional:"true"`
Timestamp uint64 `json:"timestamp" optional:"true"`
ParentHash common.Hash `json:"parentHash" optional:"true"`
ExtraData []byte `json:"extraData" optional:"true"`
GasLimit uint64 `json:"gasLimit"`
Difficulty *big.Int `json:"difficulty"`
Mixhash common.Hash `json:"mixHash" optional:"true"`
Coinbase common.Address `json:"coinbase" optional:"true"`
Alloc GenesisAlloc `json:"alloc"`
}
// GenesisAlloc specifies the initial state that is part of the genesis block.
type GenesisAlloc map[common.Address]GenesisAccount
// GenesisAccount is an account in the state of the genesis block.
type GenesisAccount struct {
Code []byte `json:"code" optional:"true"`
Storage map[common.Hash]common.Hash `json:"storage" optional:"true"`
Balance *big.Int `json:"balance"`
Nonce uint64 `json:"nonce" optional:"true"`
}
// field type overrides for gencodec
type genesisSpecMarshaling struct {
Nonce math.HexOrDecimal64
Timestamp math.HexOrDecimal64
ExtraData hexutil.Bytes
GasLimit math.HexOrDecimal64
Difficulty *math.HexOrDecimal256
Alloc map[common.UnprefixedAddress]GenesisAccount
}
type genesisAccountMarshaling struct {
Code hexutil.Bytes
Balance *math.HexOrDecimal256
Nonce math.HexOrDecimal64
}
// GenesisMismatchError is raised when trying to overwrite an existing
// genesis block with an incompatible one.
type GenesisMismatchError struct {
Stored, New common.Hash
}
func (e *GenesisMismatchError) Error() string {
return fmt.Sprintf("wrong genesis block in database (have %x, new %x)", e.Stored[:8], e.New[:8])
}
// SetupGenesisBlock writes or updates the genesis block in db.
// The block that will be used is:
//
// genesis == nil genesis != nil
// +------------------------------------------
// db has no genesis | main-net default | genesis
// db has genesis | from DB | genesis (if compatible)
//
// The stored chain configuration will be updated if it is compatible (i.e. does not
// specify a fork block below the local head block). In case of a conflict, the
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
//
// The returned chain configuration is never nil.
func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
if genesis != nil && genesis.Config == nil {
return params.AllProtocolChanges, common.Hash{}, errGenesisNoConfig
}
// Just commit the new block if there is no stored genesis block.
stored := GetCanonicalHash(db, 0)
if (stored == common.Hash{}) {
if genesis == nil {
log.Info("Writing default main-net genesis block")
genesis = DefaultGenesisBlock()
} else {
log.Info("Writing custom genesis block")
}
block, err := genesis.Commit(db)
return genesis.Config, block.Hash(), err
}
// Check whether the genesis block is already written.
if genesis != nil {
block, _ := genesis.ToBlock()
hash := block.Hash()
if hash != stored {
return genesis.Config, block.Hash(), &GenesisMismatchError{stored, hash}
}
}
// Get the existing chain configuration.
newcfg := genesis.configOrDefault(stored)
storedcfg, err := GetChainConfig(db, stored)
if err != nil { if err != nil {
return nil, err if err == ChainConfigNotFoundErr {
// This case happens if a genesis write was interrupted.
log.Warn("Found genesis block without chain config")
err = WriteChainConfig(db, stored, newcfg)
}
return newcfg, stored, err
}
// Special case: don't change the existing config of a non-mainnet chain if no new
// config is supplied. These chains would get AllProtocolChanges (and a compat error)
// if we just continued here.
if genesis == nil && stored != params.MainNetGenesisHash {
return storedcfg, stored, nil
} }
var genesis struct { // Check config compatibility and write the config. Compatibility errors
ChainConfig *params.ChainConfig `json:"config"` // are returned to the caller unless we're already at block zero.
Nonce string height := GetBlockNumber(db, GetHeadHeaderHash(db))
Timestamp string if height == missingNumber {
ParentHash string return newcfg, stored, fmt.Errorf("missing block number for head header hash")
ExtraData string }
GasLimit string compatErr := storedcfg.CheckCompatible(newcfg, height)
Difficulty string if compatErr != nil && height != 0 && compatErr.RewindTo != 0 {
Mixhash string return newcfg, stored, compatErr
Coinbase string }
Alloc map[string]struct { return newcfg, stored, WriteChainConfig(db, stored, newcfg)
Code string }
Storage map[string]string
Balance string func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
Nonce string switch {
case g != nil:
return g.Config
case ghash == params.MainNetGenesisHash:
return params.MainnetChainConfig
case ghash == params.TestNetGenesisHash:
return params.TestnetChainConfig
default:
return params.AllProtocolChanges
} }
} }
if err := json.Unmarshal(contents, &genesis); err != nil { // ToBlock creates the block and state of a genesis specification.
return nil, err func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) {
} db, _ := ethdb.NewMemDatabase()
if genesis.ChainConfig == nil { statedb, _ := state.New(common.Hash{}, db)
genesis.ChainConfig = params.AllProtocolChanges for addr, account := range g.Alloc {
} statedb.AddBalance(addr, account.Balance)
statedb.SetCode(addr, account.Code)
// creating with empty hash always works statedb.SetNonce(addr, account.Nonce)
statedb, _ := state.New(common.Hash{}, chainDb)
for addr, account := range genesis.Alloc {
balance, ok := math.ParseBig256(account.Balance)
if !ok {
return nil, fmt.Errorf("invalid balance for account %s: %q", addr, account.Balance)
}
nonce, ok := math.ParseUint64(account.Nonce)
if !ok {
return nil, fmt.Errorf("invalid nonce for account %s: %q", addr, account.Nonce)
}
address := common.HexToAddress(addr)
statedb.AddBalance(address, balance)
statedb.SetCode(address, common.FromHex(account.Code))
statedb.SetNonce(address, nonce)
for key, value := range account.Storage { for key, value := range account.Storage {
statedb.SetState(address, common.HexToHash(key), common.HexToHash(value)) statedb.SetState(addr, key, value)
} }
} }
root, stateBatch := statedb.CommitBatch(false) root := statedb.IntermediateRoot(false)
head := &types.Header{
difficulty, ok := math.ParseBig256(genesis.Difficulty) Nonce: types.EncodeNonce(g.Nonce),
if !ok { Time: new(big.Int).SetUint64(g.Timestamp),
return nil, fmt.Errorf("invalid difficulty: %q", genesis.Difficulty) ParentHash: g.ParentHash,
} Extra: g.ExtraData,
gaslimit, ok := math.ParseUint64(genesis.GasLimit) GasLimit: new(big.Int).SetUint64(g.GasLimit),
if !ok { Difficulty: g.Difficulty,
return nil, fmt.Errorf("invalid gas limit: %q", genesis.GasLimit) MixDigest: g.Mixhash,
} Coinbase: g.Coinbase,
nonce, ok := math.ParseUint64(genesis.Nonce)
if !ok {
return nil, fmt.Errorf("invalid nonce: %q", genesis.Nonce)
}
timestamp, ok := math.ParseBig256(genesis.Timestamp)
if !ok {
return nil, fmt.Errorf("invalid timestamp: %q", genesis.Timestamp)
}
block := types.NewBlock(&types.Header{
Nonce: types.EncodeNonce(nonce),
Time: timestamp,
ParentHash: common.HexToHash(genesis.ParentHash),
Extra: common.FromHex(genesis.ExtraData),
GasLimit: new(big.Int).SetUint64(gaslimit),
Difficulty: difficulty,
MixDigest: common.HexToHash(genesis.Mixhash),
Coinbase: common.HexToAddress(genesis.Coinbase),
Root: root, Root: root,
}, nil, nil, nil)
if block := GetBlock(chainDb, block.Hash(), block.NumberU64()); block != nil {
log.Info("Genesis block known, writing canonical number")
err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
if err != nil {
return nil, err
} }
return block, nil if g.GasLimit == 0 {
head.GasLimit = params.GenesisGasLimit
}
if g.Difficulty == nil {
head.Difficulty = params.GenesisDifficulty
}
return types.NewBlock(head, nil, nil, nil), statedb
} }
if err := stateBatch.Write(); err != nil { // Commit writes the block and state of a genesis specification to the database.
// The block is committed as the canonical head block.
func (g *Genesis) Commit(db ethdb.Database) (*types.Block, error) {
block, statedb := g.ToBlock()
if _, err := statedb.CommitTo(db, false); err != nil {
return nil, fmt.Errorf("cannot write state: %v", err) return nil, fmt.Errorf("cannot write state: %v", err)
} }
if err := WriteTd(chainDb, block.Hash(), block.NumberU64(), difficulty); err != nil { if err := WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty); err != nil {
return nil, err return nil, err
} }
if err := WriteBlock(chainDb, block); err != nil { if err := WriteBlock(db, block); err != nil {
return nil, err return nil, err
} }
if err := WriteBlockReceipts(chainDb, block.Hash(), block.NumberU64(), nil); err != nil { if err := WriteBlockReceipts(db, block.Hash(), block.NumberU64(), nil); err != nil {
return nil, err return nil, err
} }
if err := WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64()); err != nil { if err := WriteCanonicalHash(db, block.Hash(), block.NumberU64()); err != nil {
return nil, err return nil, err
} }
if err := WriteHeadBlockHash(chainDb, block.Hash()); err != nil { if err := WriteHeadBlockHash(db, block.Hash()); err != nil {
return nil, err return nil, err
} }
if err := WriteChainConfig(chainDb, block.Hash(), genesis.ChainConfig); err != nil { if err := WriteHeadHeaderHash(db, block.Hash()); err != nil {
return nil, err return nil, err
} }
return block, nil config := g.Config
if config == nil {
config = params.AllProtocolChanges
}
return block, WriteChainConfig(db, block.Hash(), config)
} }
// GenesisBlockForTesting creates a block in which addr has the given wei balance. // MustCommit writes the genesis block and state to db, panicking on error.
// The state trie of the block is written to db. the passed db needs to contain a state root // The block is committed as the canonical head block.
func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block { func (g *Genesis) MustCommit(db ethdb.Database) *types.Block {
statedb, _ := state.New(common.Hash{}, db) block, err := g.Commit(db)
obj := statedb.GetOrNewStateObject(addr)
obj.SetBalance(balance)
root, err := statedb.Commit(false)
if err != nil {
panic(fmt.Sprintf("cannot write state: %v", err))
}
block := types.NewBlock(&types.Header{
Difficulty: params.GenesisDifficulty,
GasLimit: params.GenesisGasLimit,
Root: root,
}, nil, nil, nil)
return block
}
type GenesisAccount struct {
Address common.Address
Balance *big.Int
}
func WriteGenesisBlockForTesting(db ethdb.Database, accounts ...GenesisAccount) *types.Block {
accountJson := "{"
for i, account := range accounts {
if i != 0 {
accountJson += ","
}
accountJson += fmt.Sprintf(`"0x%x":{"balance":"%d"}`, account.Address, account.Balance)
}
accountJson += "}"
testGenesis := fmt.Sprintf(`{
"nonce":"0x%x",
"gasLimit":"0x%x",
"difficulty":"0x%x",
"alloc": %s
}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), accountJson)
block, err := WriteGenesisBlock(db, strings.NewReader(testGenesis))
if err != nil { if err != nil {
panic(err) panic(err)
} }
return block return block
} }
// WriteDefaultGenesisBlock assembles the official Ethereum genesis block and // GenesisBlockForTesting creates and writes a block in which addr has the given wei balance.
// writes it - along with all associated state - into a chain database. func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big.Int) *types.Block {
func WriteDefaultGenesisBlock(chainDb ethdb.Database) (*types.Block, error) { g := Genesis{Alloc: GenesisAlloc{addr: {Balance: balance}}}
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultGenesisBlock())) return g.MustCommit(db)
} }
// WriteTestNetGenesisBlock assembles the test network genesis block and // DefaultGenesisBlock returns the Ethereum main net genesis block.
// writes it - along with all associated state - into a chain database. func DefaultGenesisBlock() *Genesis {
func WriteTestNetGenesisBlock(chainDb ethdb.Database) (*types.Block, error) { return &Genesis{
return WriteGenesisBlock(chainDb, strings.NewReader(DefaultTestnetGenesisBlock())) Config: params.MainnetChainConfig,
Nonce: 66,
ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"),
GasLimit: 5000,
Difficulty: big.NewInt(17179869184),
Alloc: decodePrealloc(mainnetAllocData),
}
} }
// DefaultGenesisBlock assembles a JSON string representing the default Ethereum // DefaultTestnetGenesisBlock returns the Ropsten network genesis block.
// genesis block. func DefaultTestnetGenesisBlock() *Genesis {
func DefaultGenesisBlock() string { return &Genesis{
reader, err := gzip.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultGenesisBlock))) Config: params.TestnetChainConfig,
if err != nil { Nonce: 66,
panic(fmt.Sprintf("failed to access default genesis: %v", err)) ExtraData: hexutil.MustDecode("0x3535353535353535353535353535353535353535353535353535353535353535"),
GasLimit: 16777216,
Difficulty: big.NewInt(1048576),
Alloc: decodePrealloc(testnetAllocData),
} }
blob, err := ioutil.ReadAll(reader)
if err != nil {
panic(fmt.Sprintf("failed to load default genesis: %v", err))
}
return string(blob)
} }
// DefaultTestnetGenesisBlock assembles a JSON string representing the default Ethereum // DevGenesisBlock returns the 'geth --dev' genesis block.
// test network genesis block. func DevGenesisBlock() *Genesis {
func DefaultTestnetGenesisBlock() string { return &Genesis{
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultTestnetGenesisBlock))) Config: params.AllProtocolChanges,
blob, err := ioutil.ReadAll(reader) Nonce: 42,
if err != nil { GasLimit: 4712388,
panic(fmt.Sprintf("failed to load default genesis: %v", err)) Difficulty: big.NewInt(131072),
Alloc: decodePrealloc(devAllocData),
} }
return string(blob)
} }
// DevGenesisBlock assembles a JSON string representing a local dev genesis block. func decodePrealloc(data string) GenesisAlloc {
func DevGenesisBlock() string { var p []struct{ Addr, Balance *big.Int }
reader := bzip2.NewReader(base64.NewDecoder(base64.StdEncoding, strings.NewReader(defaultDevnetGenesisBlock))) if err := rlp.NewStream(strings.NewReader(data), 0).Decode(&p); err != nil {
blob, err := ioutil.ReadAll(reader) panic(err)
if err != nil {
panic(fmt.Sprintf("failed to load dev genesis: %v", err))
} }
return string(blob) ga := make(GenesisAlloc, len(p))
for _, account := range p {
ga[common.BigToAddress(account.Addr)] = GenesisAccount{Balance: account.Balance}
}
return ga
} }

25
core/genesis_alloc.go Normal file

File diff suppressed because one or more lines are too long

161
core/genesis_test.go Normal file
View File

@ -0,0 +1,161 @@
// 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)
}
}
}
}

View File

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

85
core/mkalloc.go Normal file
View File

@ -0,0 +1,85 @@
// 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))
}

View File

@ -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() {
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.

View File

@ -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) {
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) {
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) {
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) {
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

View File

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

View File

@ -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)),

View File

@ -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,10 +58,12 @@ 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
@ -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) {
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) {
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 { if err != nil {
return nil, err return nil, err
} }
log.Warn("Wrote default Ethereum genesis block") // 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)
} }
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 == core.ErrNoGenesis {
return nil, fmt.Errorf(`No chain found. Please initialise a new chain using the "init" subcommand.`)
}
return nil, err
}
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
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 {

View File

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

View File

@ -76,8 +76,7 @@ func TestBlockSubscription(t *testing.T) {
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{}
) )

View File

@ -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) {
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) {
) )
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 {

View File

@ -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) {
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) {
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
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)

View File

@ -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,
@ -56,16 +53,19 @@ func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core
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
} }

View File

@ -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) {
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) {
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 {

View File

@ -137,25 +137,28 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
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,
Alloc: core.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
}
genesis = gspec.MustCommit(db)
odr *LesOdr odr *LesOdr
chain BlockChain 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
} }

View File

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

View File

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

View File

@ -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 (
"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 {
// 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) {
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{
Difficulty: big.NewInt(1),
Config: testChainConfig(),
} }
gspec.MustCommit(db)
func theLightChain(db ethdb.Database, t *testing.T) *LightChain { lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
var eventMux event.TypeMux
core.WriteTestNetGenesisBlock(db)
LightChain, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.NewTestEthash(), &eventMux)
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 {
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) {
} }
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) {
} }
} }
// 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) {
// 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) {
// 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) {
} }
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)
} }

View File

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

View File

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

View File

@ -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 {
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,10 +141,19 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Register the Ethereum protocol if requested
if config.EthereumEnabled { var genesis *core.Genesis
ethConf := &eth.Config{ if config.EthereumGenesis != "" {
ChainConfig: &params.ChainConfig{ 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), ChainId: big.NewInt(config.EthereumChainConfig.ChainID),
HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock), HomesteadBlock: big.NewInt(config.EthereumChainConfig.HomesteadBlock),
DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock), DAOForkBlock: big.NewInt(config.EthereumChainConfig.DAOForkBlock),
@ -139,8 +162,13 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash, EIP150Hash: config.EthereumChainConfig.EIP150Hash.hash,
EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block), EIP155Block: big.NewInt(config.EthereumChainConfig.EIP155Block),
EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block), EIP158Block: big.NewInt(config.EthereumChainConfig.EIP158Block),
}, }
Genesis: config.EthereumGenesis, }
// Register the Ethereum protocol if requested
if config.EthereumEnabled {
ethConf := &eth.Config{
Genesis: genesis,
LightMode: true, LightMode: true,
DatabaseCache: config.EthereumDatabaseCache, DatabaseCache: config.EthereumDatabaseCache,
NetworkId: config.EthereumNetworkID, NetworkId: config.EthereumNetworkID,

View File

@ -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 {
// 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.

View File

@ -23,8 +23,9 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
var (
// MainnetChainConfig is the chain parameters to run a node on the main network. // MainnetChainConfig is the chain parameters to run a node on the main network.
var MainnetChainConfig = &ChainConfig{ MainnetChainConfig = &ChainConfig{
ChainId: MainNetChainID, ChainId: MainNetChainID,
HomesteadBlock: MainNetHomesteadBlock, HomesteadBlock: MainNetHomesteadBlock,
DAOForkBlock: MainNetDAOForkBlock, DAOForkBlock: MainNetDAOForkBlock,
@ -35,8 +36,8 @@ var MainnetChainConfig = &ChainConfig{
EIP158Block: MainNetSpuriousDragon, EIP158Block: MainNetSpuriousDragon,
} }
// TestnetChainConfig is the chain parameters to run a node on the test network. // TestnetChainConfig contains the chain parameters to run a node on the ropsten test network.
var TestnetChainConfig = &ChainConfig{ TestnetChainConfig = &ChainConfig{
ChainId: big.NewInt(3), ChainId: big.NewInt(3),
HomesteadBlock: big.NewInt(0), HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil, DAOForkBlock: nil,
@ -49,13 +50,16 @@ var TestnetChainConfig = &ChainConfig{
// AllProtocolChanges contains every protocol change (EIPs) // AllProtocolChanges contains every protocol change (EIPs)
// introduced and accepted by the Ethereum core developers. // introduced and accepted by the Ethereum core developers.
// TestChainConfig is like AllProtocolChanges but has chain ID 1.
// //
// This configuration is intentionally not using keyed fields. // This configuration is intentionally not using keyed fields.
// This configuration must *always* have all forks enabled, which // This configuration must *always* have all forks enabled, which
// means that all fields must be set at all times. This forces // means that all fields must be set at all times. This forces
// anyone adding flags to the config to also have to set these // anyone adding flags to the config to also have to set these
// fields. // fields.
var AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)} 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 {
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 {
) )
} }
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 {
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.
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 lasterr
}
func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *ConfigCompatError {
if isForkIncompatible(c.HomesteadBlock, newcfg.HomesteadBlock, head) {
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)
}
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)
}
// isForked returns whether a fork scheduled at block s is active at the given head block.
func isForked(s, head *big.Int) bool {
if s == nil || head == nil {
return false return false
} }
return num.Cmp(c.EIP150Block) >= 0 return s.Cmp(head) <= 0
} }
func (c *ChainConfig) IsEIP155(num *big.Int) bool { func configNumEqual(x, y *big.Int) bool {
if c.EIP155Block == nil || num == nil { if x == nil {
return false return y == nil
} }
return num.Cmp(c.EIP155Block) >= 0 if y == nil {
return x == nil
}
return x.Cmp(y) == 0
} }
func (c *ChainConfig) IsEIP158(num *big.Int) bool { // ConfigCompatError is raised if the locally-stored blockchain is initialised with a
if c.EIP158Block == nil || num == nil { // ChainConfig that would alter the past.
return false type ConfigCompatError struct {
} What string
return num.Cmp(c.EIP158Block) >= 0 // block numbers of the stored and new configurations
StoredConfig, NewConfig *big.Int
// the block number to which the local chain must be rewound to correct the error
RewindTo uint64
} }
// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatError {
// that do not have or require information about the block. var rew *big.Int
// switch {
// Rules is a one time interface meaning that it shouldn't be used in between transition case storedblock == nil:
// phases. rew = newblock
type Rules struct { case newblock == nil || storedblock.Cmp(newblock) < 0:
ChainId *big.Int rew = storedblock
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool 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)
} }

81
params/config_test.go Normal file
View File

@ -0,0 +1,81 @@
// 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)
}
}
}

View File

@ -17,8 +17,6 @@
package params package params
import ( import (
"encoding/json"
"fmt"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -47,372 +45,123 @@ var DAORefundContract = common.HexToAddress("0xbf4ed7b27f1d666546e30d74d50d173d2
// DAODrainList is the list of accounts whose full balances will be moved into a // DAODrainList is the list of accounts whose full balances will be moved into a
// refund contract at the beginning of the dao-fork block. // refund contract at the beginning of the dao-fork block.
var DAODrainList []common.Address func DAODrainList() []common.Address {
return []common.Address{
func init() { common.HexToAddress("0xd4fe7bc31cedb7bfb8a345f31e668033056b2728"),
// Parse the list of DAO accounts to drain common.HexToAddress("0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"),
var list []map[string]string common.HexToAddress("0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f"),
if err := json.Unmarshal([]byte(daoDrainListJSON), &list); err != nil { common.HexToAddress("0xecd135fa4f61a655311e86238c92adcd779555d2"),
panic(fmt.Errorf("Failed to parse DAO drain list: %v", err)) common.HexToAddress("0x1975bd06d486162d5dc297798dfc41edd5d160a7"),
} common.HexToAddress("0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"),
// Collect all the accounts that need draining common.HexToAddress("0x319f70bab6845585f412ec7724b744fec6095c85"),
for _, dao := range list { common.HexToAddress("0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"),
DAODrainList = append(DAODrainList, common.HexToAddress(dao["address"])) common.HexToAddress("0x5c8536898fbb74fc7445814902fd08422eac56d0"),
DAODrainList = append(DAODrainList, common.HexToAddress(dao["extraBalanceAccount"])) common.HexToAddress("0x6966ab0d485353095148a2155858910e0965b6f9"),
common.HexToAddress("0x779543a0491a837ca36ce8c635d6154e3c4911a6"),
common.HexToAddress("0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"),
common.HexToAddress("0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5"),
common.HexToAddress("0x9c50426be05db97f5d64fc54bf89eff947f0a321"),
common.HexToAddress("0x200450f06520bdd6c527622a273333384d870efb"),
common.HexToAddress("0xbe8539bfe837b67d1282b2b1d61c3f723966f049"),
common.HexToAddress("0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb"),
common.HexToAddress("0xf1385fb24aad0cd7432824085e42aff90886fef5"),
common.HexToAddress("0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091"),
common.HexToAddress("0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"),
common.HexToAddress("0x51e0ddd9998364a2eb38588679f0d2c42653e4a6"),
common.HexToAddress("0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"),
common.HexToAddress("0xf0b1aa0eb660754448a7937c022e30aa692fe0c5"),
common.HexToAddress("0x24c4d950dfd4dd1902bbed3508144a54542bba94"),
common.HexToAddress("0x9f27daea7aca0aa0446220b98d028715e3bc803d"),
common.HexToAddress("0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"),
common.HexToAddress("0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b"),
common.HexToAddress("0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"),
common.HexToAddress("0x6f6704e5a10332af6672e50b3d9754dc460dfa4d"),
common.HexToAddress("0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"),
common.HexToAddress("0x492ea3bb0f3315521c31f273e565b868fc090f17"),
common.HexToAddress("0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"),
common.HexToAddress("0x9ea779f907f0b315b364b0cfc39a0fde5b02a416"),
common.HexToAddress("0xceaeb481747ca6c540a000c1f3641f8cef161fa7"),
common.HexToAddress("0xcc34673c6c40e791051898567a1222daf90be287"),
common.HexToAddress("0x579a80d909f346fbfb1189493f521d7f48d52238"),
common.HexToAddress("0xe308bd1ac5fda103967359b2712dd89deffb7973"),
common.HexToAddress("0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"),
common.HexToAddress("0xac1ecab32727358dba8962a0f3b261731aad9723"),
common.HexToAddress("0x4fd6ace747f06ece9c49699c7cabc62d02211f75"),
common.HexToAddress("0x440c59b325d2997a134c2c7c60a8c61611212bad"),
common.HexToAddress("0x4486a3d68fac6967006d7a517b889fd3f98c102b"),
common.HexToAddress("0x9c15b54878ba618f494b38f0ae7443db6af648ba"),
common.HexToAddress("0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"),
common.HexToAddress("0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241"),
common.HexToAddress("0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"),
common.HexToAddress("0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b"),
common.HexToAddress("0xb9637156d330c0d605a791f1c31ba5890582fe1c"),
common.HexToAddress("0x6131c42fa982e56929107413a9d526fd99405560"),
common.HexToAddress("0x1591fc0f688c81fbeb17f5426a162a7024d430c2"),
common.HexToAddress("0x542a9515200d14b68e934e9830d91645a980dd7a"),
common.HexToAddress("0xc4bbd073882dd2add2424cf47d35213405b01324"),
common.HexToAddress("0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4"),
common.HexToAddress("0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"),
common.HexToAddress("0x3ba4d81db016dc2890c81f3acec2454bff5aada5"),
common.HexToAddress("0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"),
common.HexToAddress("0xe4ae1efdfc53b73893af49113d8694a057b9c0d1"),
common.HexToAddress("0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"),
common.HexToAddress("0x0737a6b837f97f46ebade41b9bc3e1c509c85c53"),
common.HexToAddress("0x97f43a37f595ab5dd318fb46e7a155eae057317a"),
common.HexToAddress("0x52c5317c848ba20c7504cb2c8052abd1fde29d03"),
common.HexToAddress("0x4863226780fe7c0356454236d3b1c8792785748d"),
common.HexToAddress("0x5d2b2e6fcbe3b11d26b525e085ff818dae332479"),
common.HexToAddress("0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"),
common.HexToAddress("0x057b56736d32b86616a10f619859c6cd6f59092a"),
common.HexToAddress("0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"),
common.HexToAddress("0x304a554a310c7e546dfe434669c62820b7d83490"),
common.HexToAddress("0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"),
common.HexToAddress("0x4deb0033bb26bc534b197e61d19e0733e5679784"),
common.HexToAddress("0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"),
common.HexToAddress("0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b"),
common.HexToAddress("0x4fa802324e929786dbda3b8820dc7834e9134a2a"),
common.HexToAddress("0x9da397b9e80755301a3b32173283a91c0ef6c87e"),
common.HexToAddress("0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"),
common.HexToAddress("0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9"),
common.HexToAddress("0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"),
common.HexToAddress("0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76"),
common.HexToAddress("0x12e626b0eebfe86a56d633b9864e389b45dcb260"),
common.HexToAddress("0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7"),
common.HexToAddress("0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"),
common.HexToAddress("0xd164b088bd9108b60d0ca3751da4bceb207b0782"),
common.HexToAddress("0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"),
common.HexToAddress("0x1cba23d343a983e9b5cfd19496b9a9701ada385f"),
common.HexToAddress("0xa82f360a8d3455c5c41366975bde739c37bfeb8a"),
common.HexToAddress("0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339"),
common.HexToAddress("0x005f5cee7a43331d5a3d3eec71305925a62f34b6"),
common.HexToAddress("0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d"),
common.HexToAddress("0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"),
common.HexToAddress("0xbc07118b9ac290e4622f5e77a0853539789effbe"),
common.HexToAddress("0x47e7aa56d6bdf3f36be34619660de61275420af8"),
common.HexToAddress("0xacd87e28b0c9d1254e868b81cba4cc20d9a32225"),
common.HexToAddress("0xadf80daec7ba8dcf15392f1ac611fff65d94f880"),
common.HexToAddress("0x5524c55fb03cf21f549444ccbecb664d0acad706"),
common.HexToAddress("0x40b803a9abce16f50f36a77ba41180eb90023925"),
common.HexToAddress("0xfe24cdd8648121a43a7c86d289be4dd2951ed49f"),
common.HexToAddress("0x17802f43a0137c506ba92291391a8a8f207f487d"),
common.HexToAddress("0x253488078a4edf4d6f42f113d1e62836a942cf1a"),
common.HexToAddress("0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"),
common.HexToAddress("0xb136707642a4ea12fb4bae820f03d2562ebff487"),
common.HexToAddress("0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"),
common.HexToAddress("0xf14c14075d6c4ed84b86798af0956deef67365b5"),
common.HexToAddress("0xca544e5c4687d109611d0f8f928b53a25af72448"),
common.HexToAddress("0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c"),
common.HexToAddress("0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"),
common.HexToAddress("0x6d87578288b6cb5549d5076a207456a1f6a63dc0"),
common.HexToAddress("0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"),
common.HexToAddress("0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6"),
common.HexToAddress("0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"),
common.HexToAddress("0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a"),
common.HexToAddress("0xd343b217de44030afaa275f54d31a9317c7f441e"),
common.HexToAddress("0x84ef4b2357079cd7a7c69fd7a37cd0609a679106"),
common.HexToAddress("0xda2fef9e4a3230988ff17df2165440f37e8b1708"),
common.HexToAddress("0xf4c64518ea10f995918a454158c6b61407ea345c"),
common.HexToAddress("0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"),
common.HexToAddress("0xbb9bc244d798123fde783fcc1c72d3bb8c189413"),
common.HexToAddress("0x807640a13483f8ac783c557fcdf27be11ea4ac7a"),
} }
} }
// daoDrainListJSON is the JSON encoded list of accounts whose full balances will
// be moved into a refund contract at the beginning of the dao-fork block.
const daoDrainListJSON = `
[
{
"address":"0xd4fe7bc31cedb7bfb8a345f31e668033056b2728",
"balance":"186cc8bfaefb7be",
"extraBalance":"0",
"extraBalanceAccount":"0xb3fb0e5aba0e20e5c49d252dfd30e102b171a425"
},
{
"address":"0x2c19c7f9ae8b751e37aeb2d93a699722395ae18f",
"balance":"b14e8feab1ff435",
"extraBalance":"0",
"extraBalanceAccount":"0xecd135fa4f61a655311e86238c92adcd779555d2"
},
{
"address":"0x1975bd06d486162d5dc297798dfc41edd5d160a7",
"balance":"359d26614cb5070c77",
"extraBalance":"0",
"extraBalanceAccount":"0xa3acf3a1e16b1d7c315e23510fdd7847b48234f6"
},
{
"address":"0x319f70bab6845585f412ec7724b744fec6095c85",
"balance":"6e075cd846d2cb1d42",
"extraBalance":"13d34fd41b545b81",
"extraBalanceAccount":"0x06706dd3f2c9abf0a21ddcc6941d9b86f0596936"
},
{
"address":"0x5c8536898fbb74fc7445814902fd08422eac56d0",
"balance":"b1e5593558008fd78",
"extraBalance":"0",
"extraBalanceAccount":"0x6966ab0d485353095148a2155858910e0965b6f9"
},
{
"address":"0x779543a0491a837ca36ce8c635d6154e3c4911a6",
"balance":"392eaa20d1aad59a4c",
"extraBalance":"426938826a96c9",
"extraBalanceAccount":"0x2a5ed960395e2a49b1c758cef4aa15213cfd874c"
},
{
"address":"0x5c6e67ccd5849c0d29219c4f95f1a7a93b3f5dc5",
"balance":"2875d22b29793d4ba7",
"extraBalance":"0",
"extraBalanceAccount":"0x9c50426be05db97f5d64fc54bf89eff947f0a321"
},
{
"address":"0x200450f06520bdd6c527622a273333384d870efb",
"balance":"43c341d9f96954c049",
"extraBalance":"0",
"extraBalanceAccount":"0xbe8539bfe837b67d1282b2b1d61c3f723966f049"
},
{
"address":"0x6b0c4d41ba9ab8d8cfb5d379c69a612f2ced8ecb",
"balance":"75251057154d70fa816",
"extraBalance":"0",
"extraBalanceAccount":"0xf1385fb24aad0cd7432824085e42aff90886fef5"
},
{
"address":"0xd1ac8b1ef1b69ff51d1d401a476e7e612414f091",
"balance":"392409769296cf67f36",
"extraBalance":"0",
"extraBalanceAccount":"0x8163e7fb499e90f8544ea62bbf80d21cd26d9efd"
},
{
"address":"0x51e0ddd9998364a2eb38588679f0d2c42653e4a6",
"balance":"8ac72eccbf4e8083",
"extraBalance":"0",
"extraBalanceAccount":"0x627a0a960c079c21c34f7612d5d230e01b4ad4c7"
},
{
"address":"0xf0b1aa0eb660754448a7937c022e30aa692fe0c5",
"balance":"82289c3bb3e8c98799",
"extraBalance":"0",
"extraBalanceAccount":"0x24c4d950dfd4dd1902bbed3508144a54542bba94"
},
{
"address":"0x9f27daea7aca0aa0446220b98d028715e3bc803d",
"balance":"56bc29049ebed40fd",
"extraBalance":"0",
"extraBalanceAccount":"0xa5dc5acd6a7968a4554d89d65e59b7fd3bff0f90"
},
{
"address":"0xd9aef3a1e38a39c16b31d1ace71bca8ef58d315b",
"balance":"56bc7d3ff79110524",
"extraBalance":"0",
"extraBalanceAccount":"0x63ed5a272de2f6d968408b4acb9024f4cc208ebf"
},
{
"address":"0x6f6704e5a10332af6672e50b3d9754dc460dfa4d",
"balance":"23b651bd48cbc70cc",
"extraBalance":"0",
"extraBalanceAccount":"0x77ca7b50b6cd7e2f3fa008e24ab793fd56cb15f6"
},
{
"address":"0x492ea3bb0f3315521c31f273e565b868fc090f17",
"balance":"13ea6d4fee651dd7c9",
"extraBalance":"0",
"extraBalanceAccount":"0x0ff30d6de14a8224aa97b78aea5388d1c51c1f00"
},
{
"address":"0x9ea779f907f0b315b364b0cfc39a0fde5b02a416",
"balance":"35ac471a3836ae7de5a",
"extraBalance":"0",
"extraBalanceAccount":"0xceaeb481747ca6c540a000c1f3641f8cef161fa7"
},
{
"address":"0xcc34673c6c40e791051898567a1222daf90be287",
"balance":"d529c0b76b7aa0",
"extraBalance":"0",
"extraBalanceAccount":"0x579a80d909f346fbfb1189493f521d7f48d52238"
},
{
"address":"0xe308bd1ac5fda103967359b2712dd89deffb7973",
"balance":"5cd9e7df3a8e5cdd3",
"extraBalance":"0",
"extraBalanceAccount":"0x4cb31628079fb14e4bc3cd5e30c2f7489b00960c"
},
{
"address":"0xac1ecab32727358dba8962a0f3b261731aad9723",
"balance":"2c8442fe35363313b93",
"extraBalance":"0",
"extraBalanceAccount":"0x4fd6ace747f06ece9c49699c7cabc62d02211f75"
},
{
"address":"0x440c59b325d2997a134c2c7c60a8c61611212bad",
"balance":"e77583a3958130e53",
"extraBalance":"0",
"extraBalanceAccount":"0x4486a3d68fac6967006d7a517b889fd3f98c102b"
},
{
"address":"0x9c15b54878ba618f494b38f0ae7443db6af648ba",
"balance":"1f0b6ade348ca998",
"extraBalance":"0",
"extraBalanceAccount":"0x27b137a85656544b1ccb5a0f2e561a5703c6a68f"
},
{
"address":"0x21c7fdb9ed8d291d79ffd82eb2c4356ec0d81241",
"balance":"61725880736659",
"extraBalance":"0",
"extraBalanceAccount":"0x23b75c2f6791eef49c69684db4c6c1f93bf49a50"
},
{
"address":"0x1ca6abd14d30affe533b24d7a21bff4c2d5e1f3b",
"balance":"42948d8dc7ddbc22d",
"extraBalance":"0",
"extraBalanceAccount":"0xb9637156d330c0d605a791f1c31ba5890582fe1c"
},
{
"address":"0x6131c42fa982e56929107413a9d526fd99405560",
"balance":"7306683851d1eafbfa",
"extraBalance":"0",
"extraBalanceAccount":"0x1591fc0f688c81fbeb17f5426a162a7024d430c2"
},
{
"address":"0x542a9515200d14b68e934e9830d91645a980dd7a",
"balance":"2a8457d0d8432e21d0c",
"extraBalance":"0",
"extraBalanceAccount":"0xc4bbd073882dd2add2424cf47d35213405b01324"
},
{
"address":"0x782495b7b3355efb2833d56ecb34dc22ad7dfcc4",
"balance":"d8d7391feaeaa8cdb",
"extraBalance":"0",
"extraBalanceAccount":"0x58b95c9a9d5d26825e70a82b6adb139d3fd829eb"
},
{
"address":"0x3ba4d81db016dc2890c81f3acec2454bff5aada5",
"balance":"1",
"extraBalance":"0",
"extraBalanceAccount":"0xb52042c8ca3f8aa246fa79c3feaa3d959347c0ab"
},
{
"address":"0xe4ae1efdfc53b73893af49113d8694a057b9c0d1",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0x3c02a7bc0391e86d91b7d144e61c2c01a25a79c5"
},
{
"address":"0x0737a6b837f97f46ebade41b9bc3e1c509c85c53",
"balance":"6324dcb7126ecbef",
"extraBalance":"0",
"extraBalanceAccount":"0x97f43a37f595ab5dd318fb46e7a155eae057317a"
},
{
"address":"0x52c5317c848ba20c7504cb2c8052abd1fde29d03",
"balance":"6c3419b0705c01cd0d",
"extraBalance":"0",
"extraBalanceAccount":"0x4863226780fe7c0356454236d3b1c8792785748d"
},
{
"address":"0x5d2b2e6fcbe3b11d26b525e085ff818dae332479",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0x5f9f3392e9f62f63b8eac0beb55541fc8627f42c"
},
{
"address":"0x057b56736d32b86616a10f619859c6cd6f59092a",
"balance":"232c025bb44b46",
"extraBalance":"0",
"extraBalanceAccount":"0x9aa008f65de0b923a2a4f02012ad034a5e2e2192"
},
{
"address":"0x304a554a310c7e546dfe434669c62820b7d83490",
"balance":"3034f5ca7d45e17df199b",
"extraBalance":"f7d15162c44e97b6e",
"extraBalanceAccount":"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79"
},
{
"address":"0x4deb0033bb26bc534b197e61d19e0733e5679784",
"balance":"4417e96ed796591e09",
"extraBalance":"0",
"extraBalanceAccount":"0x07f5c1e1bc2c93e0402f23341973a0e043f7bf8a"
},
{
"address":"0x35a051a0010aba705c9008d7a7eff6fb88f6ea7b",
"balance":"d3ff7771412bbcc9",
"extraBalance":"0",
"extraBalanceAccount":"0x4fa802324e929786dbda3b8820dc7834e9134a2a"
},
{
"address":"0x9da397b9e80755301a3b32173283a91c0ef6c87e",
"balance":"32ae324c233816b4c2",
"extraBalance":"0",
"extraBalanceAccount":"0x8d9edb3054ce5c5774a420ac37ebae0ac02343c6"
},
{
"address":"0x0101f3be8ebb4bbd39a2e3b9a3639d4259832fd9",
"balance":"1e530695b705f037c6",
"extraBalance":"0",
"extraBalanceAccount":"0x5dc28b15dffed94048d73806ce4b7a4612a1d48f"
},
{
"address":"0xbcf899e6c7d9d5a215ab1e3444c86806fa854c76",
"balance":"68013bad5b4b1133fc5",
"extraBalance":"0",
"extraBalanceAccount":"0x12e626b0eebfe86a56d633b9864e389b45dcb260"
},
{
"address":"0xa2f1ccba9395d7fcb155bba8bc92db9bafaeade7",
"balance":"456397665fa74041",
"extraBalance":"0",
"extraBalanceAccount":"0xec8e57756626fdc07c63ad2eafbd28d08e7b0ca5"
},
{
"address":"0xd164b088bd9108b60d0ca3751da4bceb207b0782",
"balance":"3635ce47fabaaa336e",
"extraBalance":"0",
"extraBalanceAccount":"0x6231b6d0d5e77fe001c2a460bd9584fee60d409b"
},
{
"address":"0x1cba23d343a983e9b5cfd19496b9a9701ada385f",
"balance":"f3abd9906c170a",
"extraBalance":"0",
"extraBalanceAccount":"0xa82f360a8d3455c5c41366975bde739c37bfeb8a"
},
{
"address":"0x9fcd2deaff372a39cc679d5c5e4de7bafb0b1339",
"balance":"4c6679d9d9b95a4e08",
"extraBalance":"0",
"extraBalanceAccount":"0x005f5cee7a43331d5a3d3eec71305925a62f34b6"
},
{
"address":"0x0e0da70933f4c7849fc0d203f5d1d43b9ae4532d",
"balance":"40f622936475de31849",
"extraBalance":"671e1bbabded39754",
"extraBalanceAccount":"0xd131637d5275fd1a68a3200f4ad25c71a2a9522e"
},
{
"address":"0xbc07118b9ac290e4622f5e77a0853539789effbe",
"balance":"1316ccfa4a35db5e58f",
"extraBalance":"0",
"extraBalanceAccount":"0x47e7aa56d6bdf3f36be34619660de61275420af8"
},
{
"address":"0xacd87e28b0c9d1254e868b81cba4cc20d9a32225",
"balance":"b3ad6bb72000bab9f",
"extraBalance":"0",
"extraBalanceAccount":"0xadf80daec7ba8dcf15392f1ac611fff65d94f880"
},
{
"address":"0x5524c55fb03cf21f549444ccbecb664d0acad706",
"balance":"16f2da372a5c8a70967",
"extraBalance":"0",
"extraBalanceAccount":"0x40b803a9abce16f50f36a77ba41180eb90023925"
},
{
"address":"0xfe24cdd8648121a43a7c86d289be4dd2951ed49f",
"balance":"ea0b1bdc78f500a43",
"extraBalance":"0",
"extraBalanceAccount":"0x17802f43a0137c506ba92291391a8a8f207f487d"
},
{
"address":"0x253488078a4edf4d6f42f113d1e62836a942cf1a",
"balance":"3060e3aed135cc80",
"extraBalance":"0",
"extraBalanceAccount":"0x86af3e9626fce1957c82e88cbf04ddf3a2ed7915"
},
{
"address":"0xb136707642a4ea12fb4bae820f03d2562ebff487",
"balance":"6050bdeb3354b5c98adc3",
"extraBalance":"0",
"extraBalanceAccount":"0xdbe9b615a3ae8709af8b93336ce9b477e4ac0940"
},
{
"address":"0xf14c14075d6c4ed84b86798af0956deef67365b5",
"balance":"1d77844e94c25ba2",
"extraBalance":"0",
"extraBalanceAccount":"0xca544e5c4687d109611d0f8f928b53a25af72448"
},
{
"address":"0xaeeb8ff27288bdabc0fa5ebb731b6f409507516c",
"balance":"2e93a72de4fc5ec0ed",
"extraBalance":"0",
"extraBalanceAccount":"0xcbb9d3703e651b0d496cdefb8b92c25aeb2171f7"
},
{
"address":"0x6d87578288b6cb5549d5076a207456a1f6a63dc0",
"balance":"1afd340799e48c18",
"extraBalance":"0",
"extraBalanceAccount":"0xb2c6f0dfbb716ac562e2d85d6cb2f8d5ee87603e"
},
{
"address":"0xaccc230e8a6e5be9160b8cdf2864dd2a001c28b6",
"balance":"14d0944eb3be947a8",
"extraBalance":"0",
"extraBalanceAccount":"0x2b3455ec7fedf16e646268bf88846bd7a2319bb2"
},
{
"address":"0x4613f3bca5c44ea06337a9e439fbc6d42e501d0a",
"balance":"6202b236a200e365eba",
"extraBalance":"11979be9020f03ec4ec",
"extraBalanceAccount":"0xd343b217de44030afaa275f54d31a9317c7f441e"
},
{
"address":"0x84ef4b2357079cd7a7c69fd7a37cd0609a679106",
"balance":"7ed634ebbba531901e07",
"extraBalance":"f9c5eff28cb08720c85",
"extraBalanceAccount":"0xda2fef9e4a3230988ff17df2165440f37e8b1708"
},
{
"address":"0xf4c64518ea10f995918a454158c6b61407ea345c",
"balance":"39152e15508a96ff894a",
"extraBalance":"14041ca908bcc185c8",
"extraBalanceAccount":"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97"
},
{
"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"balance":"1",
"extraBalance":"5553ebc",
"extraBalanceAccount":"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
}
]
`