github.com/klaytn/klaytn@v1.12.1/blockchain/genesis_test.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2017 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from core/genesis_test.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package blockchain
    22  
    23  import (
    24  	"fmt"
    25  	"math/big"
    26  	"reflect"
    27  	"testing"
    28  
    29  	"github.com/davecgh/go-spew/spew"
    30  	"github.com/klaytn/klaytn/blockchain/types"
    31  	"github.com/klaytn/klaytn/blockchain/vm"
    32  	"github.com/klaytn/klaytn/common"
    33  	"github.com/klaytn/klaytn/consensus/gxhash"
    34  	"github.com/klaytn/klaytn/params"
    35  	"github.com/klaytn/klaytn/storage/database"
    36  	"github.com/stretchr/testify/assert"
    37  )
    38  
    39  // TestDefaultGenesisBlock tests the genesis block generation functions: DefaultGenesisBlock, DefaultBaobabGenesisBlock
    40  func TestDefaultGenesisBlock(t *testing.T) {
    41  	block := genCypressGenesisBlock().ToBlock(common.Hash{}, nil)
    42  	if block.Hash() != params.CypressGenesisHash {
    43  		t.Errorf("wrong cypress genesis hash, got %v, want %v", block.Hash(), params.CypressGenesisHash)
    44  	}
    45  	block = genBaobabGenesisBlock().ToBlock(common.Hash{}, nil)
    46  	if block.Hash() != params.BaobabGenesisHash {
    47  		t.Errorf("wrong baobab genesis hash, got %v, want %v", block.Hash(), params.BaobabGenesisHash)
    48  	}
    49  }
    50  
    51  // TestHardCodedChainConfigUpdate tests the public network's chainConfig update.
    52  func TestHardCodedChainConfigUpdate(t *testing.T) {
    53  	cypressGenesisBlock, baobabGenesisBlock := genCypressGenesisBlock(), genBaobabGenesisBlock()
    54  	tests := []struct {
    55  		name             string
    56  		newHFBlock       *big.Int
    57  		originHFBlock    *big.Int
    58  		fn               func(database.DBManager, *big.Int) (*params.ChainConfig, common.Hash, error)
    59  		wantConfig       *params.ChainConfig // expect value of the SetupGenesisBlock's first return value
    60  		wantHash         common.Hash
    61  		wantErr          error
    62  		wantStoredConfig *params.ChainConfig // expect value of the stored config in DB
    63  		resetFn          func(*big.Int)
    64  	}{
    65  		{
    66  			name:       "cypress chainConfig update",
    67  			newHFBlock: big.NewInt(3),
    68  			fn: func(db database.DBManager, newHFBlock *big.Int) (*params.ChainConfig, common.Hash, error) {
    69  				cypressGenesisBlock.MustCommit(db)
    70  				cypressGenesisBlock.Config.IstanbulCompatibleBlock = newHFBlock
    71  				return SetupGenesisBlock(db, cypressGenesisBlock, params.CypressNetworkId, false, false)
    72  			},
    73  			wantHash:         params.CypressGenesisHash,
    74  			wantConfig:       cypressGenesisBlock.Config,
    75  			wantStoredConfig: cypressGenesisBlock.Config,
    76  		},
    77  		// TODO-klaytn: add more cypress test cases after cypress hard fork block numbers are added
    78  		{
    79  			// Because of the fork-ordering check logic, the istanbulCompatibleBlock should be less than the londonCompatibleBlock
    80  			name:       "baobab chainConfig update - correct hard-fork block number order",
    81  			newHFBlock: big.NewInt(79999999),
    82  			fn: func(db database.DBManager, newHFBlock *big.Int) (*params.ChainConfig, common.Hash, error) {
    83  				baobabGenesisBlock.MustCommit(db)
    84  				baobabGenesisBlock.Config.IstanbulCompatibleBlock = newHFBlock
    85  				return SetupGenesisBlock(db, baobabGenesisBlock, params.BaobabNetworkId, false, false)
    86  			},
    87  			wantHash:         params.BaobabGenesisHash,
    88  			wantConfig:       baobabGenesisBlock.Config,
    89  			wantStoredConfig: baobabGenesisBlock.Config,
    90  		},
    91  		{
    92  			// This test fails because the new istanbulCompatibleBlock(90909999) is larger than londonCompatibleBlock(80295291)
    93  			name:       "baobab chainConfig update - wrong hard-fork block number order",
    94  			newHFBlock: big.NewInt(90909999),
    95  			fn: func(db database.DBManager, newHFBlock *big.Int) (*params.ChainConfig, common.Hash, error) {
    96  				baobabGenesisBlock.MustCommit(db)
    97  				baobabGenesisBlock.Config.IstanbulCompatibleBlock = newHFBlock
    98  				return SetupGenesisBlock(db, baobabGenesisBlock, params.BaobabNetworkId, false, false)
    99  			},
   100  			wantHash:         common.Hash{},
   101  			wantConfig:       baobabGenesisBlock.Config,
   102  			wantStoredConfig: nil,
   103  			wantErr: fmt.Errorf("unsupported fork ordering: %v enabled at %v, but %v enabled at %v",
   104  				"istanbulBlock", big.NewInt(90909999), "londonBlock", big.NewInt(80295291)),
   105  		},
   106  		{
   107  			name:       "incompatible config in DB",
   108  			newHFBlock: big.NewInt(3),
   109  			fn: func(db database.DBManager, newHFBlock *big.Int) (*params.ChainConfig, common.Hash, error) {
   110  				// Commit the 'old' genesis block with Istanbul transition at #2.
   111  				// Advance to block #4, past the Istanbul transition block of customGenesis.
   112  				genesis := genCypressGenesisBlock()
   113  				genesisBlock := genesis.MustCommit(db)
   114  
   115  				bc, _ := NewBlockChain(db, nil, genesis.Config, gxhash.NewFullFaker(), vm.Config{})
   116  				defer bc.Stop()
   117  
   118  				blocks, _ := GenerateChain(genesis.Config, genesisBlock, gxhash.NewFaker(), db, 4, nil)
   119  				bc.InsertChain(blocks)
   120  				// This should return a compatibility error.
   121  				newConfig := *genesis
   122  				newConfig.Config.IstanbulCompatibleBlock = newHFBlock
   123  				return SetupGenesisBlock(db, &newConfig, params.CypressNetworkId, true, false)
   124  			},
   125  			wantHash:         params.CypressGenesisHash,
   126  			wantConfig:       cypressGenesisBlock.Config,
   127  			wantStoredConfig: params.CypressChainConfig,
   128  			wantErr: &params.ConfigCompatError{
   129  				What:         "Istanbul Block",
   130  				StoredConfig: params.CypressChainConfig.IstanbulCompatibleBlock,
   131  				NewConfig:    big.NewInt(3),
   132  				RewindTo:     2,
   133  			},
   134  		},
   135  	}
   136  
   137  	for _, test := range tests {
   138  		db := database.NewMemoryDBManager()
   139  		config, hash, err := test.fn(db, test.newHFBlock)
   140  
   141  		// Check the return values
   142  		assert.Equal(t, test.wantErr, err, test.name+": err is mismatching")
   143  		assert.Equal(t, test.wantConfig, config, test.name+": config is mismatching")
   144  		assert.Equal(t, test.wantHash, hash, test.name+": hash is mismatching")
   145  
   146  		// Check stored genesis block
   147  		if test.wantHash != (common.Hash{}) {
   148  			stored := db.ReadBlock(test.wantHash, 0)
   149  			assert.Equal(t, test.wantHash, stored.Hash(), test.name+": stored genesis block is not compatible")
   150  		}
   151  
   152  		// Check stored chainConfig
   153  		storedChainConfig := db.ReadChainConfig(test.wantHash)
   154  		assert.Equal(t, test.wantStoredConfig, storedChainConfig, test.name+": stored chainConfig is not compatible")
   155  	}
   156  }
   157  
   158  func TestSetupGenesis(t *testing.T) {
   159  	var (
   160  		customGenesisHash = common.HexToHash("0x4eb4035b7a09619a9950c9a4751cc331843f2373ef38263d676b4a132ba4059c")
   161  		customChainId     = uint64(4343)
   162  		customGenesis     = genCustomGenesisBlock(customChainId)
   163  	)
   164  	tests := []struct {
   165  		name       string
   166  		fn         func(database.DBManager) (*params.ChainConfig, common.Hash, error)
   167  		wantConfig *params.ChainConfig
   168  		wantHash   common.Hash
   169  		wantErr    error
   170  	}{
   171  		{
   172  			name: "genesis without ChainConfig",
   173  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   174  				return SetupGenesisBlock(db, new(Genesis), params.UnusedNetworkId, false, false)
   175  			},
   176  			wantErr:    errGenesisNoConfig,
   177  			wantConfig: params.AllGxhashProtocolChanges,
   178  		},
   179  		{
   180  			name: "no block in DB, genesis == nil, cypress networkId",
   181  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   182  				return SetupGenesisBlock(db, nil, params.CypressNetworkId, false, false)
   183  			},
   184  			wantHash:   params.CypressGenesisHash,
   185  			wantConfig: params.CypressChainConfig,
   186  		},
   187  		{
   188  			name: "no block in DB, genesis == nil, baobab networkId",
   189  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   190  				return SetupGenesisBlock(db, nil, params.BaobabNetworkId, false, false)
   191  			},
   192  			wantHash:   params.BaobabGenesisHash,
   193  			wantConfig: params.BaobabChainConfig,
   194  		},
   195  		{
   196  			name: "no block in DB, genesis == customGenesis, private network",
   197  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   198  				return SetupGenesisBlock(db, customGenesis, customChainId, true, false)
   199  			},
   200  			wantHash:   customGenesisHash,
   201  			wantConfig: customGenesis.Config,
   202  		},
   203  		{
   204  			name: "cypress block in DB, genesis == nil, cypress networkId",
   205  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   206  				genCypressGenesisBlock().MustCommit(db)
   207  				return SetupGenesisBlock(db, nil, params.CypressNetworkId, false, false)
   208  			},
   209  			wantHash:   params.CypressGenesisHash,
   210  			wantConfig: params.CypressChainConfig,
   211  		},
   212  		{
   213  			name: "baobab block in DB, genesis == nil, baobab networkId",
   214  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   215  				genBaobabGenesisBlock().MustCommit(db)
   216  				return SetupGenesisBlock(db, nil, params.BaobabNetworkId, false, false)
   217  			},
   218  			wantHash:   params.BaobabGenesisHash,
   219  			wantConfig: params.BaobabChainConfig,
   220  		},
   221  		{
   222  			name: "custom block in DB, genesis == nil, custom networkId",
   223  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   224  				customGenesis.MustCommit(db)
   225  				return SetupGenesisBlock(db, nil, customChainId, true, false)
   226  			},
   227  			wantHash:   customGenesisHash,
   228  			wantConfig: customGenesis.Config,
   229  		},
   230  		{
   231  			name: "cypress block in DB, genesis == baobab",
   232  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   233  				genCypressGenesisBlock().MustCommit(db)
   234  				return SetupGenesisBlock(db, genBaobabGenesisBlock(), params.BaobabNetworkId, false, false)
   235  			},
   236  			wantErr:    &GenesisMismatchError{Stored: params.CypressGenesisHash, New: params.BaobabGenesisHash},
   237  			wantHash:   params.BaobabGenesisHash,
   238  			wantConfig: params.BaobabChainConfig,
   239  		},
   240  		{
   241  			name: "baobab block in DB, genesis == cypress",
   242  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   243  				genBaobabGenesisBlock().MustCommit(db)
   244  				return SetupGenesisBlock(db, genCypressGenesisBlock(), params.CypressNetworkId, false, false)
   245  			},
   246  			wantErr:    &GenesisMismatchError{Stored: params.BaobabGenesisHash, New: params.CypressGenesisHash},
   247  			wantHash:   params.CypressGenesisHash,
   248  			wantConfig: params.CypressChainConfig,
   249  		},
   250  		{
   251  			name: "cypress block in DB, genesis == custom",
   252  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   253  				genCypressGenesisBlock().MustCommit(db)
   254  				return SetupGenesisBlock(db, genCustomGenesisBlock(customChainId), customChainId, true, false)
   255  			},
   256  			wantErr:    &GenesisMismatchError{Stored: params.CypressGenesisHash, New: customGenesisHash},
   257  			wantHash:   customGenesisHash,
   258  			wantConfig: customGenesis.Config,
   259  		},
   260  		{
   261  			name: "baobab block in DB, genesis == custom",
   262  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   263  				genBaobabGenesisBlock().MustCommit(db)
   264  				return SetupGenesisBlock(db, customGenesis, customChainId, true, false)
   265  			},
   266  			wantErr:    &GenesisMismatchError{Stored: params.BaobabGenesisHash, New: customGenesisHash},
   267  			wantHash:   customGenesisHash,
   268  			wantConfig: customGenesis.Config,
   269  		},
   270  		{
   271  			name: "custom block in DB, genesis == cypress",
   272  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   273  				customGenesis.MustCommit(db)
   274  				return SetupGenesisBlock(db, genCypressGenesisBlock(), params.CypressNetworkId, false, false)
   275  			},
   276  			wantErr:    &GenesisMismatchError{Stored: customGenesisHash, New: params.CypressGenesisHash},
   277  			wantHash:   params.CypressGenesisHash,
   278  			wantConfig: params.CypressChainConfig,
   279  		},
   280  		{
   281  			name: "custom block in DB, genesis == baobab",
   282  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   283  				customGenesis.MustCommit(db)
   284  				return SetupGenesisBlock(db, genBaobabGenesisBlock(), params.BaobabNetworkId, false, false)
   285  			},
   286  			wantErr:    &GenesisMismatchError{Stored: customGenesisHash, New: params.BaobabGenesisHash},
   287  			wantHash:   params.BaobabGenesisHash,
   288  			wantConfig: params.BaobabChainConfig,
   289  		},
   290  		{
   291  			name: "compatible config in DB",
   292  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   293  				customGenesis.MustCommit(db)
   294  				return SetupGenesisBlock(db, customGenesis, customChainId, true, false)
   295  			},
   296  			wantHash:   customGenesisHash,
   297  			wantConfig: customGenesis.Config,
   298  		},
   299  		{
   300  			name: "incompatible config in DB",
   301  			fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) {
   302  				// Commit the 'old' genesis block with Istanbul transition at #2.
   303  				// Advance to block #4, past the Istanbul transition block of customGenesis.
   304  				genesis := customGenesis.MustCommit(db)
   305  
   306  				bc, _ := NewBlockChain(db, nil, customGenesis.Config, gxhash.NewFullFaker(), vm.Config{})
   307  				defer bc.Stop()
   308  
   309  				blocks, _ := GenerateChain(customGenesis.Config, genesis, gxhash.NewFaker(), db, 4, nil)
   310  				bc.InsertChain(blocks)
   311  				// This should return a compatibility error.
   312  				newConfig := *customGenesis
   313  				newConfig.Config.IstanbulCompatibleBlock = big.NewInt(3)
   314  				return SetupGenesisBlock(db, &newConfig, customChainId, true, false)
   315  			},
   316  			wantHash:   customGenesisHash,
   317  			wantConfig: customGenesis.Config,
   318  			wantErr: &params.ConfigCompatError{
   319  				What:         "Istanbul Block",
   320  				StoredConfig: big.NewInt(2),
   321  				NewConfig:    big.NewInt(3),
   322  				RewindTo:     1,
   323  			},
   324  		},
   325  	}
   326  
   327  	for _, test := range tests {
   328  		db := database.NewMemoryDBManager()
   329  		config, hash, err := test.fn(db)
   330  		// Check the return values.
   331  		if !reflect.DeepEqual(err, test.wantErr) {
   332  			spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
   333  			t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
   334  		}
   335  		if !reflect.DeepEqual(config, test.wantConfig) {
   336  			t.Errorf("%s:\nreturned %v\nwant     %v", test.name, config, test.wantConfig)
   337  		}
   338  		if hash != test.wantHash {
   339  			t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
   340  		} else if err == nil {
   341  			// Check database content.
   342  			stored := db.ReadBlock(test.wantHash, 0)
   343  			if stored.Hash() != test.wantHash {
   344  				t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
   345  			}
   346  		}
   347  	}
   348  }
   349  
   350  func genCypressGenesisBlock() *Genesis {
   351  	genesis := DefaultGenesisBlock()
   352  	genesis.Config = params.CypressChainConfig.Copy()
   353  	genesis.Governance = SetGenesisGovernance(genesis)
   354  	InitDeriveSha(genesis.Config)
   355  	return genesis
   356  }
   357  
   358  func genBaobabGenesisBlock() *Genesis {
   359  	genesis := DefaultBaobabGenesisBlock()
   360  	genesis.Config = params.BaobabChainConfig.Copy()
   361  	genesis.Governance = SetGenesisGovernance(genesis)
   362  	InitDeriveSha(genesis.Config)
   363  	return genesis
   364  }
   365  
   366  func genCustomGenesisBlock(customChainId uint64) *Genesis {
   367  	genesis := &Genesis{
   368  		Config: &params.ChainConfig{
   369  			ChainID:                 new(big.Int).SetUint64(customChainId),
   370  			IstanbulCompatibleBlock: big.NewInt(2),
   371  			DeriveShaImpl:           types.ImplDeriveShaConcat,
   372  		},
   373  		Alloc: GenesisAlloc{
   374  			common.HexToAddress("0x0100000000000000000000000000000000000000"): {
   375  				Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}},
   376  			},
   377  		},
   378  	}
   379  	genesis.Config.SetDefaultsForGenesis()
   380  	genesis.Governance = SetGenesisGovernance(genesis)
   381  	InitDeriveSha(genesis.Config)
   382  	return genesis
   383  }