c72b16c340
* core: write test showing that TD is not stored properly at genesis The ToBlock method applies a default value for an empty difficulty value. This default is not carried over through the Commit method because the TotalDifficulty database write writes the original difficulty value (nil) instead of the defaulty value present on the genesis Block. Date: 2021-10-22 08:25:32-07:00 Signed-off-by: meows <b5c6@protonmail.com> * core: write TD value from Block, not original genesis value This an issue where a default TD value was not written to the database, resulting in a 0 value TD at genesis. A test for this issue was provided at 90e3ffd393 Date: 2021-10-22 08:28:00-07:00 Signed-off-by: meows <b5c6@protonmail.com> * core: fix tests by adding GenesisDifficulty to expected result See prior two commits. Date: 2021-10-22 09:16:01-07:00 Signed-off-by: meows <b5c6@protonmail.com> * les: fix test with genesis change Co-authored-by: Martin Holst Swende <martin@swende.se>
242 lines
7.9 KiB
Go
242 lines
7.9 KiB
Go
// 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/consensus/ethash"
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
|
"github.com/ethereum/go-ethereum/ethdb"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
)
|
|
|
|
func TestDefaultGenesisBlock(t *testing.T) {
|
|
block := DefaultGenesisBlock().ToBlock(nil)
|
|
if block.Hash() != params.MainnetGenesisHash {
|
|
t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash(), params.MainnetGenesisHash)
|
|
}
|
|
block = DefaultRopstenGenesisBlock().ToBlock(nil)
|
|
if block.Hash() != params.RopstenGenesisHash {
|
|
t.Errorf("wrong ropsten genesis hash, got %v, want %v", block.Hash(), params.RopstenGenesisHash)
|
|
}
|
|
block = DefaultRinkebyGenesisBlock().ToBlock(nil)
|
|
if block.Hash() != params.RinkebyGenesisHash {
|
|
t.Errorf("wrong rinkeby genesis hash, got %v, want %v", block.Hash(), params.RinkebyGenesisHash)
|
|
}
|
|
block = DefaultGoerliGenesisBlock().ToBlock(nil)
|
|
if block.Hash() != params.GoerliGenesisHash {
|
|
t.Errorf("wrong goerli genesis hash, got %v, want %v", block.Hash(), params.GoerliGenesisHash)
|
|
}
|
|
}
|
|
|
|
func TestInvalidCliqueConfig(t *testing.T) {
|
|
block := DefaultGoerliGenesisBlock()
|
|
block.ExtraData = []byte{}
|
|
if _, err := block.Commit(nil); err == nil {
|
|
t.Fatal("Expected error on invalid clique config")
|
|
}
|
|
}
|
|
|
|
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.AllEthashProtocolChanges,
|
|
},
|
|
{
|
|
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 == ropsten",
|
|
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
|
|
customg.MustCommit(db)
|
|
return SetupGenesisBlock(db, DefaultRopstenGenesisBlock())
|
|
},
|
|
wantErr: &GenesisMismatchError{Stored: customghash, New: params.RopstenGenesisHash},
|
|
wantHash: params.RopstenGenesisHash,
|
|
wantConfig: params.RopstenChainConfig,
|
|
},
|
|
{
|
|
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, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil)
|
|
defer bc.Stop()
|
|
|
|
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
|
bc.InsertChain(blocks)
|
|
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 := rawdb.NewMemoryDatabase()
|
|
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 := rawdb.ReadBlock(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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestGenesisHashes checks the congruity of default genesis data to corresponding hardcoded genesis hash values.
|
|
func TestGenesisHashes(t *testing.T) {
|
|
cases := []struct {
|
|
genesis *Genesis
|
|
hash common.Hash
|
|
}{
|
|
{
|
|
genesis: DefaultGenesisBlock(),
|
|
hash: params.MainnetGenesisHash,
|
|
},
|
|
{
|
|
genesis: DefaultGoerliGenesisBlock(),
|
|
hash: params.GoerliGenesisHash,
|
|
},
|
|
{
|
|
genesis: DefaultRopstenGenesisBlock(),
|
|
hash: params.RopstenGenesisHash,
|
|
},
|
|
{
|
|
genesis: DefaultRinkebyGenesisBlock(),
|
|
hash: params.RinkebyGenesisHash,
|
|
},
|
|
}
|
|
for i, c := range cases {
|
|
b := c.genesis.MustCommit(rawdb.NewMemoryDatabase())
|
|
if got := b.Hash(); got != c.hash {
|
|
t.Errorf("case: %d, want: %s, got: %s", i, c.hash.Hex(), got.Hex())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGenesis_Commit(t *testing.T) {
|
|
genesis := &Genesis{
|
|
BaseFee: big.NewInt(params.InitialBaseFee),
|
|
Config: params.TestChainConfig,
|
|
// difficulty is nil
|
|
}
|
|
|
|
db := rawdb.NewMemoryDatabase()
|
|
genesisBlock, err := genesis.Commit(db)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if genesis.Difficulty != nil {
|
|
t.Fatalf("assumption wrong")
|
|
}
|
|
|
|
// This value should have been set as default in the ToBlock method.
|
|
if genesisBlock.Difficulty().Cmp(params.GenesisDifficulty) != 0 {
|
|
t.Errorf("assumption wrong: want: %d, got: %v", params.GenesisDifficulty, genesisBlock.Difficulty())
|
|
}
|
|
|
|
// Expect the stored total difficulty to be the difficulty of the genesis block.
|
|
stored := rawdb.ReadTd(db, genesisBlock.Hash(), genesisBlock.NumberU64())
|
|
|
|
if stored.Cmp(genesisBlock.Difficulty()) != 0 {
|
|
t.Errorf("inequal difficulty; stored: %v, genesisBlock: %v", stored, genesisBlock.Difficulty())
|
|
}
|
|
}
|