core: refactor genesis handling
This commit solves several issues concerning the genesis block: * Genesis/ChainConfig loading was handled by cmd/geth code. This left library users in the cold. They could specify a JSON-encoded string and overwrite the config, but didn't get any of the additional checks performed by geth. * Decoding and writing of genesis JSON was conflated in WriteGenesisBlock. This made it a lot harder to embed the genesis block into the forthcoming config file loader. This commit changes things so there is a single Genesis type that represents genesis blocks. All uses of Write*Genesis* are changed to use the new type instead. * If the chain config supplied by the user was incompatible with the current chain (i.e. the chain had already advanced beyond a scheduled fork), it got overwritten. This is not an issue in practice because previous forks have always had the highest total difficulty. It might matter in the future though. The new code reverts the local chain to the point of the fork when upgrading configuration. The change to genesis block data removes compression library dependencies from package core.
This commit is contained in:
@ -20,7 +20,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@ -30,7 +29,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/pow"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
// 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
|
||||
// header only chain.
|
||||
func newCanonical(n int) (ethdb.Database, *LightChain, error) {
|
||||
// Create te new chain database
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
evmux := &event.TypeMux{}
|
||||
|
||||
// Initialize a fresh chain with only a genesis block
|
||||
genesis, _ := core.WriteTestNetGenesisBlock(db)
|
||||
|
||||
blockchain, _ := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.FakePow{}, evmux)
|
||||
gspec := core.Genesis{Config: testChainConfig()}
|
||||
genesis := gspec.MustCommit(db)
|
||||
blockchain, _ := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.FakePow{}, new(event.TypeMux))
|
||||
// Create and inject the requested chain
|
||||
if n == 0 {
|
||||
return db, blockchain, nil
|
||||
@ -77,21 +71,20 @@ func newCanonical(n int) (ethdb.Database, *LightChain, error) {
|
||||
return db, blockchain, err
|
||||
}
|
||||
|
||||
func init() {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
}
|
||||
|
||||
func theLightChain(db ethdb.Database, t *testing.T) *LightChain {
|
||||
var eventMux event.TypeMux
|
||||
core.WriteTestNetGenesisBlock(db)
|
||||
LightChain, err := NewLightChain(&dummyOdr{db: db}, testChainConfig(), pow.NewTestEthash(), &eventMux)
|
||||
if err != nil {
|
||||
t.Error("failed creating LightChain:", err)
|
||||
t.FailNow()
|
||||
return nil
|
||||
// newTestLightChain creates a LightChain that doesn't validate anything.
|
||||
func newTestLightChain() *LightChain {
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
gspec := &core.Genesis{
|
||||
Difficulty: big.NewInt(1),
|
||||
Config: testChainConfig(),
|
||||
}
|
||||
|
||||
return LightChain
|
||||
gspec.MustCommit(db)
|
||||
lc, err := NewLightChain(&dummyOdr{db: db}, gspec.Config, pow.NewTestEthash(), new(event.TypeMux))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
lc.SetValidator(bproc{})
|
||||
return lc
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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
|
||||
// overwrites the canonical numbers and links in the database.
|
||||
func TestReorgLongHeaders(t *testing.T) {
|
||||
@ -329,14 +308,11 @@ func TestReorgShortHeaders(t *testing.T) {
|
||||
}
|
||||
|
||||
func testReorg(t *testing.T, first, second []int, td int64) {
|
||||
// Create a pristine block chain
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
genesis, _ := core.WriteTestNetGenesisBlock(db)
|
||||
bc := chm(genesis, db)
|
||||
bc := newTestLightChain()
|
||||
|
||||
// Insert an easy and a difficult chain afterwards
|
||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, first, 11), 1)
|
||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(genesis, second, 22), 1)
|
||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)
|
||||
bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)
|
||||
// Check that the chain is valid number and link wise
|
||||
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) {
|
||||
@ -345,7 +321,7 @@ func testReorg(t *testing.T, first, second []int, td int64) {
|
||||
}
|
||||
}
|
||||
// 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 {
|
||||
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.
|
||||
func TestBadHeaderHashes(t *testing.T) {
|
||||
// Create a pristine block chain
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
genesis, _ := core.WriteTestNetGenesisBlock(db)
|
||||
bc := chm(genesis, db)
|
||||
bc := newTestLightChain()
|
||||
|
||||
// Create a chain, ban a hash and try to import
|
||||
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
|
||||
_, err = bc.InsertHeaderChain(headers, 1)
|
||||
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
|
||||
// good state prior to the bad hash.
|
||||
func TestReorgBadHeaderHashes(t *testing.T) {
|
||||
// Create a pristine block chain
|
||||
db, _ := ethdb.NewMemDatabase()
|
||||
genesis, _ := core.WriteTestNetGenesisBlock(db)
|
||||
bc := chm(genesis, db)
|
||||
bc := newTestLightChain()
|
||||
|
||||
// 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 {
|
||||
t.Fatalf("failed to import headers: %v", err)
|
||||
@ -387,8 +357,9 @@ func TestReorgBadHeaderHashes(t *testing.T) {
|
||||
}
|
||||
core.BadHashes[headers[3].Hash()] = true
|
||||
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 {
|
||||
t.Fatalf("failed to create new chain manager: %v", err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user