mirror of https://github.com/ethereum/go-ethereum
Merge pull request #3794 from fjl/core-genesis-refactor
core: refactor genesis handlingpull/3816/head
commit
8771c3061f
File diff suppressed because one or more lines are too long
@ -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 |
||||
} |
@ -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 |
||||
} |
File diff suppressed because one or more lines are too long
@ -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: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3)}, |
||||
Alloc: GenesisAlloc{ |
||||
{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, |
||||
}, |
||||
} |
||||
oldcustomg = customg |
||||
) |
||||
oldcustomg.Config = ¶ms.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: ¶ms.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) |
||||
} |
||||
} |
||||
} |
||||
} |
@ -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)) |
||||
} |
@ -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) |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue