github.com/MetalBlockchain/subnet-evm@v0.4.9/core/genesis_test.go (about)

     1  // (c) 2019-2021, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2017 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package core
    28  
    29  import (
    30  	_ "embed"
    31  	"math/big"
    32  	"reflect"
    33  	"testing"
    34  
    35  	"github.com/MetalBlockchain/subnet-evm/consensus/dummy"
    36  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    37  	"github.com/MetalBlockchain/subnet-evm/core/state"
    38  	"github.com/MetalBlockchain/subnet-evm/core/vm"
    39  	"github.com/MetalBlockchain/subnet-evm/ethdb"
    40  	"github.com/MetalBlockchain/subnet-evm/params"
    41  	"github.com/MetalBlockchain/subnet-evm/precompile"
    42  	"github.com/davecgh/go-spew/spew"
    43  	"github.com/ethereum/go-ethereum/common"
    44  	"github.com/stretchr/testify/assert"
    45  	"github.com/stretchr/testify/require"
    46  )
    47  
    48  func setupGenesisBlock(db ethdb.Database, genesis *Genesis, lastAcceptedHash common.Hash) (*params.ChainConfig, common.Hash, error) {
    49  	conf, err := SetupGenesisBlock(db, genesis, lastAcceptedHash, false)
    50  	stored := rawdb.ReadCanonicalHash(db, 0)
    51  	return conf, stored, err
    52  }
    53  
    54  func TestGenesisBlockForTesting(t *testing.T) {
    55  	genesisBlockForTestingHash := common.HexToHash("0x114ce61b50051f70768f982f7b59e82dd73b7bbd768e310c9d9f508d492e687b")
    56  	block := GenesisBlockForTesting(rawdb.NewMemoryDatabase(), common.Address{1}, big.NewInt(1))
    57  	if block.Hash() != genesisBlockForTestingHash {
    58  		t.Errorf("wrong testing genesis hash, got %v, want %v", block.Hash(), genesisBlockForTestingHash)
    59  	}
    60  }
    61  
    62  func TestSetupGenesis(t *testing.T) {
    63  	preSubnetConfig := *params.TestPreSubnetEVMConfig
    64  	preSubnetConfig.SubnetEVMTimestamp = big.NewInt(100)
    65  	var (
    66  		customghash = common.HexToHash("0x4a12fe7bf8d40d152d7e9de22337b115186a4662aa3a97217b36146202bbfc66")
    67  		customg     = Genesis{
    68  			Config: &preSubnetConfig,
    69  			Alloc: GenesisAlloc{
    70  				{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
    71  			},
    72  			GasLimit: preSubnetConfig.FeeConfig.GasLimit.Uint64(),
    73  		}
    74  		oldcustomg = customg
    75  	)
    76  
    77  	rollbackpreSubnetConfig := preSubnetConfig
    78  	rollbackpreSubnetConfig.SubnetEVMTimestamp = big.NewInt(90)
    79  	oldcustomg.Config = &rollbackpreSubnetConfig
    80  	tests := []struct {
    81  		name       string
    82  		fn         func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
    83  		wantConfig *params.ChainConfig
    84  		wantHash   common.Hash
    85  		wantErr    error
    86  	}{
    87  		{
    88  			name: "genesis without ChainConfig",
    89  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
    90  				return setupGenesisBlock(db, new(Genesis), common.Hash{})
    91  			},
    92  			wantErr:    errGenesisNoConfig,
    93  			wantConfig: nil,
    94  		},
    95  		{
    96  			name: "no block in DB, genesis == nil",
    97  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
    98  				return setupGenesisBlock(db, nil, common.Hash{})
    99  			},
   100  			wantErr:    ErrNoGenesis,
   101  			wantConfig: nil,
   102  		},
   103  		{
   104  			name: "custom block in DB, genesis == nil",
   105  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
   106  				customg.MustCommit(db)
   107  				return setupGenesisBlock(db, nil, common.Hash{})
   108  			},
   109  			wantErr:    ErrNoGenesis,
   110  			wantHash:   customghash,
   111  			wantConfig: nil,
   112  		},
   113  		{
   114  			name: "compatible config in DB",
   115  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
   116  				oldcustomg.MustCommit(db)
   117  				return setupGenesisBlock(db, &customg, customghash)
   118  			},
   119  			wantHash:   customghash,
   120  			wantConfig: customg.Config,
   121  		},
   122  		{
   123  			name: "incompatible config for metal fork in DB",
   124  			fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
   125  				// Commit the 'old' genesis block with SubnetEVM transition at 90.
   126  				// Advance to block #4, past the SubnetEVM transition block of customg.
   127  				genesis := oldcustomg.MustCommit(db)
   128  
   129  				bc, _ := NewBlockChain(db, DefaultCacheConfig, oldcustomg.Config, dummy.NewFullFaker(), vm.Config{}, common.Hash{})
   130  				defer bc.Stop()
   131  
   132  				blocks, _, _ := GenerateChain(oldcustomg.Config, genesis, dummy.NewFullFaker(), db, 4, 25, nil)
   133  				bc.InsertChain(blocks)
   134  				bc.CurrentBlock()
   135  				for _, block := range blocks {
   136  					if err := bc.Accept(block); err != nil {
   137  						t.Fatal(err)
   138  					}
   139  				}
   140  
   141  				// This should return a compatibility error.
   142  				return setupGenesisBlock(db, &customg, bc.lastAccepted.Hash())
   143  			},
   144  			wantHash:   customghash,
   145  			wantConfig: customg.Config,
   146  			wantErr: &params.ConfigCompatError{
   147  				What:         "SubnetEVM fork block timestamp",
   148  				StoredConfig: big.NewInt(90),
   149  				NewConfig:    big.NewInt(100),
   150  				RewindTo:     89,
   151  			},
   152  		},
   153  	}
   154  
   155  	for _, test := range tests {
   156  		t.Run(test.name, func(t *testing.T) {
   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("returned error %#v, want %#v", spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
   163  			}
   164  			if !reflect.DeepEqual(config, test.wantConfig) {
   165  				t.Errorf("returned %v\nwant     %v", config, test.wantConfig)
   166  			}
   167  			if hash != test.wantHash {
   168  				t.Errorf("returned hash %s, want %s", 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("block in DB has hash %s, want %s", stored.Hash(), test.wantHash)
   174  				}
   175  			}
   176  		})
   177  	}
   178  }
   179  
   180  func TestStatefulPrecompilesConfigure(t *testing.T) {
   181  	type test struct {
   182  		getConfig   func() *params.ChainConfig             // Return the config that enables the stateful precompile at the genesis for the test
   183  		assertState func(t *testing.T, sdb *state.StateDB) // Check that the stateful precompiles were configured correctly
   184  	}
   185  
   186  	addr := common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC")
   187  
   188  	// Test suite to ensure that stateful precompiles are configured correctly in the genesis.
   189  	for name, test := range map[string]test{
   190  		"allow list enabled in genesis": {
   191  			getConfig: func() *params.ChainConfig {
   192  				config := *params.TestChainConfig
   193  				config.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(0), []common.Address{addr}, nil)
   194  				return &config
   195  			},
   196  			assertState: func(t *testing.T, sdb *state.StateDB) {
   197  				assert.Equal(t, precompile.AllowListAdmin, precompile.GetContractDeployerAllowListStatus(sdb, addr), "unexpected allow list status for modified address")
   198  				assert.Equal(t, uint64(1), sdb.GetNonce(precompile.ContractDeployerAllowListAddress))
   199  			},
   200  		},
   201  	} {
   202  		t.Run(name, func(t *testing.T) {
   203  			config := test.getConfig()
   204  
   205  			genesis := &Genesis{
   206  				Config: config,
   207  				Alloc: GenesisAlloc{
   208  					{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
   209  				},
   210  				GasLimit: config.FeeConfig.GasLimit.Uint64(),
   211  			}
   212  
   213  			db := rawdb.NewMemoryDatabase()
   214  
   215  			genesisBlock := genesis.ToBlock(nil)
   216  			genesisRoot := genesisBlock.Root()
   217  
   218  			_, err := SetupGenesisBlock(db, genesis, genesisBlock.Hash(), false)
   219  			if err != nil {
   220  				t.Fatal(err)
   221  			}
   222  
   223  			statedb, err := state.New(genesisRoot, state.NewDatabase(db), nil)
   224  			if err != nil {
   225  				t.Fatal(err)
   226  			}
   227  
   228  			if test.assertState != nil {
   229  				test.assertState(t, statedb)
   230  			}
   231  		})
   232  	}
   233  }
   234  
   235  // regression test for precompile activation after header block
   236  func TestPrecompileActivationAfterHeaderBlock(t *testing.T) {
   237  	db := rawdb.NewMemoryDatabase()
   238  
   239  	customg := Genesis{
   240  		Config: params.SubnetEVMDefaultChainConfig,
   241  		Alloc: GenesisAlloc{
   242  			{1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}},
   243  		},
   244  		GasLimit: params.SubnetEVMDefaultChainConfig.FeeConfig.GasLimit.Uint64(),
   245  	}
   246  	genesis := customg.MustCommit(db)
   247  	bc, _ := NewBlockChain(db, DefaultCacheConfig, customg.Config, dummy.NewFullFaker(), vm.Config{}, common.Hash{})
   248  	defer bc.Stop()
   249  
   250  	// Advance header to block #4, past the ContractDeployerAllowListConfig.
   251  	blocks, _, _ := GenerateChain(customg.Config, genesis, dummy.NewFullFaker(), db, 4, 25, nil)
   252  
   253  	require := require.New(t)
   254  	_, err := bc.InsertChain(blocks)
   255  	require.NoError(err)
   256  
   257  	// accept up to block #2
   258  	for _, block := range blocks[:2] {
   259  		require.NoError(bc.Accept(block))
   260  	}
   261  	block := bc.CurrentBlock()
   262  
   263  	require.Equal(blocks[1].Hash(), bc.lastAccepted.Hash())
   264  	// header must be bigger than last accepted
   265  	require.Greater(block.Time(), bc.lastAccepted.Time())
   266  
   267  	activatedGenesis := customg
   268  	contractDeployerConfig := precompile.NewContractDeployerAllowListConfig(big.NewInt(51), nil, nil)
   269  	activatedGenesis.Config.UpgradeConfig.PrecompileUpgrades = []params.PrecompileUpgrade{
   270  		{
   271  			// Enable ContractDeployerAllowList at timestamp 50
   272  			ContractDeployerAllowListConfig: contractDeployerConfig,
   273  		},
   274  	}
   275  
   276  	// assert block is after the activation block
   277  	require.Greater(block.Time(), contractDeployerConfig.Timestamp().Uint64())
   278  	// assert last accepted block is before the activation block
   279  	require.Less(bc.lastAccepted.Time(), contractDeployerConfig.Timestamp().Uint64())
   280  
   281  	// This should not return any error since the last accepted block is before the activation block.
   282  	config, _, err := setupGenesisBlock(db, &activatedGenesis, bc.lastAccepted.Hash())
   283  	require.NoError(err)
   284  	if !reflect.DeepEqual(config, activatedGenesis.Config) {
   285  		t.Errorf("returned %v\nwant     %v", config, activatedGenesis.Config)
   286  	}
   287  }