github.com/ethereum/go-ethereum@v1.14.3/core/genesis_test.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"math/big"
    23  	"reflect"
    24  	"testing"
    25  
    26  	"github.com/davecgh/go-spew/spew"
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/consensus/ethash"
    29  	"github.com/ethereum/go-ethereum/core/rawdb"
    30  	"github.com/ethereum/go-ethereum/core/types"
    31  	"github.com/ethereum/go-ethereum/core/vm"
    32  	"github.com/ethereum/go-ethereum/ethdb"
    33  	"github.com/ethereum/go-ethereum/params"
    34  	"github.com/ethereum/go-ethereum/triedb"
    35  	"github.com/ethereum/go-ethereum/triedb/pathdb"
    36  )
    37  
    38  func TestInvalidCliqueConfig(t *testing.T) {
    39  	block := DefaultGoerliGenesisBlock()
    40  	block.ExtraData = []byte{}
    41  	db := rawdb.NewMemoryDatabase()
    42  	if _, err := block.Commit(db, triedb.NewDatabase(db, nil)); err == nil {
    43  		t.Fatal("Expected error on invalid clique config")
    44  	}
    45  }
    46  
    47  func TestSetupGenesis(t *testing.T) {
    48  	testSetupGenesis(t, rawdb.HashScheme)
    49  	testSetupGenesis(t, rawdb.PathScheme)
    50  }
    51  
    52  func testSetupGenesis(t *testing.T, scheme string) {
    53  	var (
    54  		customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
    55  		customg     = Genesis{
    56  			Config: &params.ChainConfig{HomesteadBlock: big.NewInt(3)},
    57  			Alloc: types.GenesisAlloc{
    58  				{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
    59  			},
    60  		}
    61  		oldcustomg = customg
    62  	)
    63  	oldcustomg.Config = &params.ChainConfig{HomesteadBlock: big.NewInt(2)}
    64  
    65  	tests := []struct {
    66  		name       string
    67  		fn         func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
    68  		wantConfig *params.ChainConfig
    69  		wantHash   common.Hash
    70  		wantErr    error
    71  	}{
    72  		{
    73  			name: "genesis without ChainConfig",
    74  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
    75  				return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), new(Genesis))
    76  			},
    77  			wantErr:    errGenesisNoConfig,
    78  			wantConfig: params.AllEthashProtocolChanges,
    79  		},
    80  		{
    81  			name: "no block in DB, genesis == nil",
    82  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
    83  				return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil)
    84  			},
    85  			wantHash:   params.MainnetGenesisHash,
    86  			wantConfig: params.MainnetChainConfig,
    87  		},
    88  		{
    89  			name: "mainnet block in DB, genesis == nil",
    90  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
    91  				DefaultGenesisBlock().MustCommit(db, triedb.NewDatabase(db, newDbConfig(scheme)))
    92  				return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil)
    93  			},
    94  			wantHash:   params.MainnetGenesisHash,
    95  			wantConfig: params.MainnetChainConfig,
    96  		},
    97  		{
    98  			name: "custom block in DB, genesis == nil",
    99  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
   100  				tdb := triedb.NewDatabase(db, newDbConfig(scheme))
   101  				customg.Commit(db, tdb)
   102  				return SetupGenesisBlock(db, tdb, nil)
   103  			},
   104  			wantHash:   customghash,
   105  			wantConfig: customg.Config,
   106  		},
   107  		{
   108  			name: "custom block in DB, genesis == goerli",
   109  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
   110  				tdb := triedb.NewDatabase(db, newDbConfig(scheme))
   111  				customg.Commit(db, tdb)
   112  				return SetupGenesisBlock(db, tdb, DefaultGoerliGenesisBlock())
   113  			},
   114  			wantErr:    &GenesisMismatchError{Stored: customghash, New: params.GoerliGenesisHash},
   115  			wantHash:   params.GoerliGenesisHash,
   116  			wantConfig: params.GoerliChainConfig,
   117  		},
   118  		{
   119  			name: "compatible config in DB",
   120  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
   121  				tdb := triedb.NewDatabase(db, newDbConfig(scheme))
   122  				oldcustomg.Commit(db, tdb)
   123  				return SetupGenesisBlock(db, tdb, &customg)
   124  			},
   125  			wantHash:   customghash,
   126  			wantConfig: customg.Config,
   127  		},
   128  		{
   129  			name: "incompatible config in DB",
   130  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
   131  				// Commit the 'old' genesis block with Homestead transition at #2.
   132  				// Advance to block #4, past the homestead transition block of customg.
   133  				tdb := triedb.NewDatabase(db, newDbConfig(scheme))
   134  				oldcustomg.Commit(db, tdb)
   135  
   136  				bc, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), &oldcustomg, nil, ethash.NewFullFaker(), vm.Config{}, nil, nil)
   137  				defer bc.Stop()
   138  
   139  				_, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil)
   140  				bc.InsertChain(blocks)
   141  
   142  				// This should return a compatibility error.
   143  				return SetupGenesisBlock(db, tdb, &customg)
   144  			},
   145  			wantHash:   customghash,
   146  			wantConfig: customg.Config,
   147  			wantErr: &params.ConfigCompatError{
   148  				What:          "Homestead fork block",
   149  				StoredBlock:   big.NewInt(2),
   150  				NewBlock:      big.NewInt(3),
   151  				RewindToBlock: 1,
   152  			},
   153  		},
   154  	}
   155  
   156  	for _, test := range tests {
   157  		db := rawdb.NewMemoryDatabase()
   158  		config, hash, err := test.fn(db)
   159  		// Check the return values.
   160  		if !reflect.DeepEqual(err, test.wantErr) {
   161  			spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
   162  			t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
   163  		}
   164  		if !reflect.DeepEqual(config, test.wantConfig) {
   165  			t.Errorf("%s:\nreturned %v\nwant     %v", test.name, config, test.wantConfig)
   166  		}
   167  		if hash != test.wantHash {
   168  			t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
   169  		} else if err == nil {
   170  			// Check database content.
   171  			stored := rawdb.ReadBlock(db, test.wantHash, 0)
   172  			if stored.Hash() != test.wantHash {
   173  				t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
   174  			}
   175  		}
   176  	}
   177  }
   178  
   179  // TestGenesisHashes checks the congruity of default genesis data to
   180  // corresponding hardcoded genesis hash values.
   181  func TestGenesisHashes(t *testing.T) {
   182  	for i, c := range []struct {
   183  		genesis *Genesis
   184  		want    common.Hash
   185  	}{
   186  		{DefaultGenesisBlock(), params.MainnetGenesisHash},
   187  		{DefaultGoerliGenesisBlock(), params.GoerliGenesisHash},
   188  		{DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash},
   189  	} {
   190  		// Test via MustCommit
   191  		db := rawdb.NewMemoryDatabase()
   192  		if have := c.genesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults)).Hash(); have != c.want {
   193  			t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex())
   194  		}
   195  		// Test via ToBlock
   196  		if have := c.genesis.ToBlock().Hash(); have != c.want {
   197  			t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex())
   198  		}
   199  	}
   200  }
   201  
   202  func TestGenesis_Commit(t *testing.T) {
   203  	genesis := &Genesis{
   204  		BaseFee: big.NewInt(params.InitialBaseFee),
   205  		Config:  params.TestChainConfig,
   206  		// difficulty is nil
   207  	}
   208  
   209  	db := rawdb.NewMemoryDatabase()
   210  	genesisBlock := genesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))
   211  
   212  	if genesis.Difficulty != nil {
   213  		t.Fatalf("assumption wrong")
   214  	}
   215  
   216  	// This value should have been set as default in the ToBlock method.
   217  	if genesisBlock.Difficulty().Cmp(params.GenesisDifficulty) != 0 {
   218  		t.Errorf("assumption wrong: want: %d, got: %v", params.GenesisDifficulty, genesisBlock.Difficulty())
   219  	}
   220  
   221  	// Expect the stored total difficulty to be the difficulty of the genesis block.
   222  	stored := rawdb.ReadTd(db, genesisBlock.Hash(), genesisBlock.NumberU64())
   223  
   224  	if stored.Cmp(genesisBlock.Difficulty()) != 0 {
   225  		t.Errorf("inequal difficulty; stored: %v, genesisBlock: %v", stored, genesisBlock.Difficulty())
   226  	}
   227  }
   228  
   229  func TestReadWriteGenesisAlloc(t *testing.T) {
   230  	var (
   231  		db    = rawdb.NewMemoryDatabase()
   232  		alloc = &types.GenesisAlloc{
   233  			{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
   234  			{2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}},
   235  		}
   236  		hash, _ = hashAlloc(alloc, false)
   237  	)
   238  	blob, _ := json.Marshal(alloc)
   239  	rawdb.WriteGenesisStateSpec(db, hash, blob)
   240  
   241  	var reload types.GenesisAlloc
   242  	err := reload.UnmarshalJSON(rawdb.ReadGenesisStateSpec(db, hash))
   243  	if err != nil {
   244  		t.Fatalf("Failed to load genesis state %v", err)
   245  	}
   246  	if len(reload) != len(*alloc) {
   247  		t.Fatal("Unexpected genesis allocation")
   248  	}
   249  	for addr, account := range reload {
   250  		want, ok := (*alloc)[addr]
   251  		if !ok {
   252  			t.Fatal("Account is not found")
   253  		}
   254  		if !reflect.DeepEqual(want, account) {
   255  			t.Fatal("Unexpected account")
   256  		}
   257  	}
   258  }
   259  
   260  func newDbConfig(scheme string) *triedb.Config {
   261  	if scheme == rawdb.HashScheme {
   262  		return triedb.HashDefaults
   263  	}
   264  	return &triedb.Config{PathDB: pathdb.Defaults}
   265  }
   266  
   267  func TestVerkleGenesisCommit(t *testing.T) {
   268  	var verkleTime uint64 = 0
   269  	verkleConfig := &params.ChainConfig{
   270  		ChainID:                       big.NewInt(1),
   271  		HomesteadBlock:                big.NewInt(0),
   272  		DAOForkBlock:                  nil,
   273  		DAOForkSupport:                false,
   274  		EIP150Block:                   big.NewInt(0),
   275  		EIP155Block:                   big.NewInt(0),
   276  		EIP158Block:                   big.NewInt(0),
   277  		ByzantiumBlock:                big.NewInt(0),
   278  		ConstantinopleBlock:           big.NewInt(0),
   279  		PetersburgBlock:               big.NewInt(0),
   280  		IstanbulBlock:                 big.NewInt(0),
   281  		MuirGlacierBlock:              big.NewInt(0),
   282  		BerlinBlock:                   big.NewInt(0),
   283  		LondonBlock:                   big.NewInt(0),
   284  		ArrowGlacierBlock:             big.NewInt(0),
   285  		GrayGlacierBlock:              big.NewInt(0),
   286  		MergeNetsplitBlock:            nil,
   287  		ShanghaiTime:                  &verkleTime,
   288  		CancunTime:                    &verkleTime,
   289  		PragueTime:                    &verkleTime,
   290  		VerkleTime:                    &verkleTime,
   291  		TerminalTotalDifficulty:       big.NewInt(0),
   292  		TerminalTotalDifficultyPassed: true,
   293  		Ethash:                        nil,
   294  		Clique:                        nil,
   295  	}
   296  
   297  	genesis := &Genesis{
   298  		BaseFee:    big.NewInt(params.InitialBaseFee),
   299  		Config:     verkleConfig,
   300  		Timestamp:  verkleTime,
   301  		Difficulty: big.NewInt(0),
   302  		Alloc: types.GenesisAlloc{
   303  			{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
   304  		},
   305  	}
   306  
   307  	expected := common.Hex2Bytes("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b")
   308  	got := genesis.ToBlock().Root().Bytes()
   309  	if !bytes.Equal(got, expected) {
   310  		t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
   311  	}
   312  
   313  	db := rawdb.NewMemoryDatabase()
   314  	triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults})
   315  	block := genesis.MustCommit(db, triedb)
   316  	if !bytes.Equal(block.Root().Bytes(), expected) {
   317  		t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
   318  	}
   319  
   320  	// Test that the trie is verkle
   321  	if !triedb.IsVerkle() {
   322  		t.Fatalf("expected trie to be verkle")
   323  	}
   324  
   325  	if !rawdb.HasAccountTrieNode(db, nil) {
   326  		t.Fatal("could not find node")
   327  	}
   328  }