github.com/MetalBlockchain/subnet-evm@v0.4.9/plugin/evm/vm_test.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package evm
     5  
     6  import (
     7  	"context"
     8  	"crypto/ecdsa"
     9  	"crypto/rand"
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"math/big"
    14  	"os"
    15  	"path/filepath"
    16  	"strings"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/MetalBlockchain/subnet-evm/commontype"
    21  	"github.com/MetalBlockchain/subnet-evm/internal/ethapi"
    22  	"github.com/MetalBlockchain/subnet-evm/metrics"
    23  	"github.com/MetalBlockchain/subnet-evm/plugin/evm/message"
    24  	"github.com/MetalBlockchain/subnet-evm/precompile"
    25  	"github.com/MetalBlockchain/subnet-evm/trie"
    26  	"github.com/MetalBlockchain/subnet-evm/vmerrs"
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/log"
    31  
    32  	"github.com/stretchr/testify/require"
    33  
    34  	"github.com/MetalBlockchain/metalgo/api/keystore"
    35  	"github.com/MetalBlockchain/metalgo/database/manager"
    36  	"github.com/MetalBlockchain/metalgo/ids"
    37  	"github.com/MetalBlockchain/metalgo/snow"
    38  	"github.com/MetalBlockchain/metalgo/snow/choices"
    39  	"github.com/MetalBlockchain/metalgo/snow/consensus/snowman"
    40  	"github.com/MetalBlockchain/metalgo/snow/validators"
    41  	metalConstants "github.com/MetalBlockchain/metalgo/utils/constants"
    42  	"github.com/MetalBlockchain/metalgo/utils/formatting"
    43  	"github.com/MetalBlockchain/metalgo/utils/logging"
    44  	"github.com/MetalBlockchain/metalgo/version"
    45  	"github.com/MetalBlockchain/metalgo/vms/components/chain"
    46  
    47  	engCommon "github.com/MetalBlockchain/metalgo/snow/engine/common"
    48  
    49  	"github.com/MetalBlockchain/subnet-evm/consensus/dummy"
    50  	"github.com/MetalBlockchain/subnet-evm/constants"
    51  	"github.com/MetalBlockchain/subnet-evm/core"
    52  	"github.com/MetalBlockchain/subnet-evm/core/types"
    53  	"github.com/MetalBlockchain/subnet-evm/eth"
    54  	"github.com/MetalBlockchain/subnet-evm/params"
    55  	"github.com/MetalBlockchain/subnet-evm/rpc"
    56  
    57  	"github.com/MetalBlockchain/subnet-evm/accounts/abi"
    58  	accountKeystore "github.com/MetalBlockchain/subnet-evm/accounts/keystore"
    59  )
    60  
    61  var (
    62  	testNetworkID   uint32 = 10
    63  	testCChainID           = ids.ID{'c', 'c', 'h', 'a', 'i', 'n', 't', 'e', 's', 't'}
    64  	testXChainID           = ids.ID{'t', 'e', 's', 't', 'x'}
    65  	testMinGasPrice int64  = 225_000_000_000
    66  	testKeys        []*ecdsa.PrivateKey
    67  	testEthAddrs    []common.Address // testEthAddrs[i] corresponds to testKeys[i]
    68  	testAvaxAssetID = ids.ID{1, 2, 3}
    69  	username        = "Johns"
    70  	password        = "CjasdjhiPeirbSenfeI13" // #nosec G101
    71  	// Use chainId: 43111, so that it does not overlap with any Metal ChainIDs, which may have their
    72  	// config overridden in vm.Initialize.
    73  	genesisJSONSubnetEVMLateEnablement = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"subnetEVMTimestamp\":50},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x7A1200\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0x71562b71999873DB5b286dF957af199Ec94617F7\": {\"balance\":\"0x4192927743b88000\"}, \"0x703c4b2bD70c169f5717101CaeE543299Fc946C7\": {\"balance\":\"0x4192927743b88000\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    74  	genesisJSONSubnetEVM               = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"subnetEVMTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x7A1200\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0x71562b71999873DB5b286dF957af199Ec94617F7\": {\"balance\":\"0x4192927743b88000\"}, \"0x703c4b2bD70c169f5717101CaeE543299Fc946C7\": {\"balance\":\"0x4192927743b88000\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    75  	genesisJSONPreSubnetEVM            = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x7A1200\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0x71562b71999873DB5b286dF957af199Ec94617F7\": {\"balance\":\"0x4192927743b88000\"}, \"0x703c4b2bD70c169f5717101CaeE543299Fc946C7\": {\"balance\":\"0x4192927743b88000\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    76  	genesisJSONLatest                  = genesisJSONSubnetEVM
    77  
    78  	firstTxAmount  *big.Int
    79  	genesisBalance *big.Int
    80  )
    81  
    82  func init() {
    83  	key1, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    84  	key2, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
    85  	testKeys = append(testKeys, key1, key2)
    86  	addr1 := crypto.PubkeyToAddress(key1.PublicKey)
    87  	addr2 := crypto.PubkeyToAddress(key2.PublicKey)
    88  	testEthAddrs = append(testEthAddrs, addr1, addr2)
    89  
    90  	firstTxAmount = new(big.Int).Mul(big.NewInt(testMinGasPrice), big.NewInt(21000*100))
    91  	genesisBalance = new(big.Int).Mul(big.NewInt(testMinGasPrice), big.NewInt(21000*1000))
    92  }
    93  
    94  // BuildGenesisTest returns the genesis bytes for Subnet EVM VM to be used in testing
    95  func buildGenesisTest(t *testing.T, genesisJSON string) []byte {
    96  	ss := CreateStaticService()
    97  
    98  	genesis := &core.Genesis{}
    99  	if err := json.Unmarshal([]byte(genesisJSON), genesis); err != nil {
   100  		t.Fatalf("Problem unmarshaling genesis JSON: %s", err)
   101  	}
   102  	args := &BuildGenesisArgs{GenesisData: genesis}
   103  	reply := &BuildGenesisReply{}
   104  	err := ss.BuildGenesis(nil, args, reply)
   105  	if err != nil {
   106  		t.Fatalf("Failed to create test genesis")
   107  	}
   108  	genesisBytes, err := formatting.Decode(reply.Encoding, reply.GenesisBytes)
   109  	if err != nil {
   110  		t.Fatalf("Failed to decode genesis bytes: %s", err)
   111  	}
   112  	return genesisBytes
   113  }
   114  
   115  func NewContext() *snow.Context {
   116  	ctx := snow.DefaultContextTest()
   117  	ctx.NetworkID = testNetworkID
   118  	ctx.NodeID = ids.GenerateTestNodeID()
   119  	ctx.ChainID = testCChainID
   120  	ctx.AVAXAssetID = testAvaxAssetID
   121  	ctx.XChainID = testXChainID
   122  	aliaser := ctx.BCLookup.(ids.Aliaser)
   123  	_ = aliaser.Alias(testCChainID, "C")
   124  	_ = aliaser.Alias(testCChainID, testCChainID.String())
   125  	_ = aliaser.Alias(testXChainID, "X")
   126  	_ = aliaser.Alias(testXChainID, testXChainID.String())
   127  	ctx.ValidatorState = &validators.TestState{
   128  		GetSubnetIDF: func(_ context.Context, chainID ids.ID) (ids.ID, error) {
   129  			subnetID, ok := map[ids.ID]ids.ID{
   130  				metalConstants.PlatformChainID: metalConstants.PrimaryNetworkID,
   131  				testXChainID:                   metalConstants.PrimaryNetworkID,
   132  				testCChainID:                   metalConstants.PrimaryNetworkID,
   133  			}[chainID]
   134  			if !ok {
   135  				return ids.Empty, errors.New("unknown chain")
   136  			}
   137  			return subnetID, nil
   138  		},
   139  	}
   140  	return ctx
   141  }
   142  
   143  type snLookup struct {
   144  	chainsToSubnet map[ids.ID]ids.ID
   145  }
   146  
   147  func (sn *snLookup) SubnetID(chainID ids.ID) (ids.ID, error) {
   148  	subnetID, ok := sn.chainsToSubnet[chainID]
   149  	if !ok {
   150  		return ids.ID{}, errors.New("unknown chain")
   151  	}
   152  	return subnetID, nil
   153  }
   154  
   155  // If [genesisJSON] is empty, defaults to using [genesisJSONLatest]
   156  func setupGenesis(t *testing.T,
   157  	genesisJSON string,
   158  ) (*snow.Context,
   159  	manager.Manager,
   160  	[]byte,
   161  	chan engCommon.Message,
   162  ) {
   163  	if len(genesisJSON) == 0 {
   164  		genesisJSON = genesisJSONLatest
   165  	}
   166  	genesisBytes := buildGenesisTest(t, genesisJSON)
   167  	ctx := NewContext()
   168  
   169  	baseDBManager := manager.NewMemDB(&version.Semantic{
   170  		Major: 1,
   171  		Minor: 4,
   172  		Patch: 5,
   173  	})
   174  
   175  	// NB: this lock is intentionally left locked when this function returns.
   176  	// The caller of this function is responsible for unlocking.
   177  	ctx.Lock.Lock()
   178  
   179  	userKeystore := keystore.New(logging.NoLog{}, manager.NewMemDB(&version.Semantic{
   180  		Major: 1,
   181  		Minor: 4,
   182  		Patch: 5,
   183  	}))
   184  	if err := userKeystore.CreateUser(username, password); err != nil {
   185  		t.Fatal(err)
   186  	}
   187  	ctx.Keystore = userKeystore.NewBlockchainKeyStore(ctx.ChainID)
   188  
   189  	issuer := make(chan engCommon.Message, 1)
   190  	prefixedDBManager := baseDBManager.NewPrefixDBManager([]byte{1})
   191  	return ctx, prefixedDBManager, genesisBytes, issuer
   192  }
   193  
   194  // GenesisVM creates a VM instance with the genesis test bytes and returns
   195  // the channel use to send messages to the engine, the VM, database manager,
   196  // and sender.
   197  // If [genesisJSON] is empty, defaults to using [genesisJSONLatest]
   198  func GenesisVM(t *testing.T,
   199  	finishBootstrapping bool,
   200  	genesisJSON string,
   201  	configJSON string,
   202  	upgradeJSON string,
   203  ) (chan engCommon.Message,
   204  	*VM, manager.Manager,
   205  	*engCommon.SenderTest,
   206  ) {
   207  	vm := &VM{}
   208  	ctx, dbManager, genesisBytes, issuer := setupGenesis(t, genesisJSON)
   209  	appSender := &engCommon.SenderTest{T: t}
   210  	appSender.CantSendAppGossip = true
   211  	appSender.SendAppGossipF = func(context.Context, []byte) error { return nil }
   212  	if err := vm.Initialize(
   213  		context.Background(),
   214  		ctx,
   215  		dbManager,
   216  		genesisBytes,
   217  		[]byte(upgradeJSON),
   218  		[]byte(configJSON),
   219  		issuer,
   220  		[]*engCommon.Fx{},
   221  		appSender,
   222  	); err != nil {
   223  		t.Fatal(err)
   224  	}
   225  
   226  	if finishBootstrapping {
   227  		require.NoError(t, vm.SetState(context.Background(), snow.Bootstrapping))
   228  		require.NoError(t, vm.SetState(context.Background(), snow.NormalOp))
   229  	}
   230  
   231  	return issuer, vm, dbManager, appSender
   232  }
   233  
   234  func TestVMConfig(t *testing.T) {
   235  	txFeeCap := float64(11)
   236  	enabledEthAPIs := []string{"debug"}
   237  	configJSON := fmt.Sprintf("{\"rpc-tx-fee-cap\": %g,\"eth-apis\": %s}", txFeeCap, fmt.Sprintf("[%q]", enabledEthAPIs[0]))
   238  	_, vm, _, _ := GenesisVM(t, false, "", configJSON, "")
   239  	require.Equal(t, vm.config.RPCTxFeeCap, txFeeCap, "Tx Fee Cap should be set")
   240  	require.Equal(t, vm.config.EthAPIs(), enabledEthAPIs, "EnabledEthAPIs should be set")
   241  	require.NoError(t, vm.Shutdown(context.Background()))
   242  }
   243  
   244  func TestVMConfigDefaults(t *testing.T) {
   245  	txFeeCap := float64(11)
   246  	enabledEthAPIs := []string{"debug"}
   247  	configJSON := fmt.Sprintf("{\"rpc-tx-fee-cap\": %g,\"eth-apis\": %s}", txFeeCap, fmt.Sprintf("[%q]", enabledEthAPIs[0]))
   248  	_, vm, _, _ := GenesisVM(t, false, "", configJSON, "")
   249  
   250  	var vmConfig Config
   251  	vmConfig.SetDefaults()
   252  	vmConfig.RPCTxFeeCap = txFeeCap
   253  	vmConfig.EnabledEthAPIs = enabledEthAPIs
   254  	require.Equal(t, vmConfig, vm.config, "VM Config should match default with overrides")
   255  	require.NoError(t, vm.Shutdown(context.Background()))
   256  }
   257  
   258  func TestVMNilConfig(t *testing.T) {
   259  	_, vm, _, _ := GenesisVM(t, false, "", "", "")
   260  
   261  	// VM Config should match defaults if no config is passed in
   262  	var vmConfig Config
   263  	vmConfig.SetDefaults()
   264  	require.Equal(t, vmConfig, vm.config, "VM Config should match default config")
   265  	require.NoError(t, vm.Shutdown(context.Background()))
   266  }
   267  
   268  func TestVMContinuousProfiler(t *testing.T) {
   269  	profilerDir := t.TempDir()
   270  	profilerFrequency := 500 * time.Millisecond
   271  	configJSON := fmt.Sprintf("{\"continuous-profiler-dir\": %q,\"continuous-profiler-frequency\": \"500ms\"}", profilerDir)
   272  	_, vm, _, _ := GenesisVM(t, false, "", configJSON, "")
   273  	require.Equal(t, vm.config.ContinuousProfilerDir, profilerDir, "profiler dir should be set")
   274  	require.Equal(t, vm.config.ContinuousProfilerFrequency.Duration, profilerFrequency, "profiler frequency should be set")
   275  
   276  	// Sleep for twice the frequency of the profiler to give it time
   277  	// to generate the first profile.
   278  	time.Sleep(2 * time.Second)
   279  	require.NoError(t, vm.Shutdown(context.Background()))
   280  
   281  	// Check that the first profile was generated
   282  	expectedFileName := filepath.Join(profilerDir, "cpu.profile.1")
   283  	_, err := os.Stat(expectedFileName)
   284  	require.NoError(t, err, "Expected continuous profiler to generate the first CPU profile at %s", expectedFileName)
   285  }
   286  
   287  func TestVMUpgrades(t *testing.T) {
   288  	genesisTests := []struct {
   289  		name             string
   290  		genesis          string
   291  		expectedGasPrice *big.Int
   292  	}{
   293  		{
   294  			name:             "Subnet EVM",
   295  			genesis:          genesisJSONSubnetEVM,
   296  			expectedGasPrice: big.NewInt(0),
   297  		},
   298  	}
   299  	for _, test := range genesisTests {
   300  		t.Run(test.name, func(t *testing.T) {
   301  			_, vm, _, _ := GenesisVM(t, true, test.genesis, "", "")
   302  
   303  			if gasPrice := vm.txPool.GasPrice(); gasPrice.Cmp(test.expectedGasPrice) != 0 {
   304  				t.Fatalf("Expected pool gas price to be %d but found %d", test.expectedGasPrice, gasPrice)
   305  			}
   306  			defer func() {
   307  				shutdownChan := make(chan error, 1)
   308  				shutdownFunc := func() {
   309  					err := vm.Shutdown(context.Background())
   310  					shutdownChan <- err
   311  				}
   312  
   313  				go shutdownFunc()
   314  				shutdownTimeout := 50 * time.Millisecond
   315  				ticker := time.NewTicker(shutdownTimeout)
   316  				select {
   317  				case <-ticker.C:
   318  					t.Fatalf("VM shutdown took longer than timeout: %v", shutdownTimeout)
   319  				case err := <-shutdownChan:
   320  					if err != nil {
   321  						t.Fatalf("Shutdown errored: %s", err)
   322  					}
   323  				}
   324  			}()
   325  
   326  			lastAcceptedID, err := vm.LastAccepted(context.Background())
   327  			if err != nil {
   328  				t.Fatal(err)
   329  			}
   330  
   331  			if lastAcceptedID != ids.ID(vm.genesisHash) {
   332  				t.Fatal("Expected last accepted block to match the genesis block hash")
   333  			}
   334  
   335  			genesisBlk, err := vm.GetBlock(context.Background(), lastAcceptedID)
   336  			if err != nil {
   337  				t.Fatalf("Failed to get genesis block due to %s", err)
   338  			}
   339  
   340  			if height := genesisBlk.Height(); height != 0 {
   341  				t.Fatalf("Expected height of geneiss block to be 0, found: %d", height)
   342  			}
   343  
   344  			if _, err := vm.ParseBlock(context.Background(), genesisBlk.Bytes()); err != nil {
   345  				t.Fatalf("Failed to parse genesis block due to %s", err)
   346  			}
   347  
   348  			genesisStatus := genesisBlk.Status()
   349  			if genesisStatus != choices.Accepted {
   350  				t.Fatalf("expected genesis status to be %s but was %s", choices.Accepted, genesisStatus)
   351  			}
   352  		})
   353  	}
   354  }
   355  
   356  func issueAndAccept(t *testing.T, issuer <-chan engCommon.Message, vm *VM) snowman.Block {
   357  	t.Helper()
   358  	<-issuer
   359  
   360  	blk, err := vm.BuildBlock(context.Background())
   361  	if err != nil {
   362  		t.Fatal(err)
   363  	}
   364  
   365  	if err := blk.Verify(context.Background()); err != nil {
   366  		t.Fatal(err)
   367  	}
   368  
   369  	if status := blk.Status(); status != choices.Processing {
   370  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   371  	}
   372  
   373  	if err := vm.SetPreference(context.Background(), blk.ID()); err != nil {
   374  		t.Fatal(err)
   375  	}
   376  
   377  	if err := blk.Accept(context.Background()); err != nil {
   378  		t.Fatal(err)
   379  	}
   380  
   381  	return blk
   382  }
   383  
   384  func TestSubnetEVMUpgradeRequiredAtGenesis(t *testing.T) {
   385  	genesisTests := []struct {
   386  		genesisJSON string
   387  		configJSON  string
   388  		expectedErr error
   389  	}{
   390  		{
   391  			// we expect an error when subnet evm upgrade is nil in chain config
   392  			genesisJSON: genesisJSONPreSubnetEVM,
   393  			configJSON:  "",
   394  			expectedErr: errSubnetEVMUpgradeNotEnabled,
   395  		},
   396  		{
   397  			// we expect an error when subnet evm upgrade is not enabled at genesis and at a later block instead
   398  			genesisJSON: genesisJSONSubnetEVMLateEnablement,
   399  			configJSON:  "",
   400  			expectedErr: errSubnetEVMUpgradeNotEnabled,
   401  		},
   402  		{
   403  			// we do not expect an err when skip-subnet-evm-upgrade-check is set to true
   404  			genesisJSON: genesisJSONPreSubnetEVM,
   405  			configJSON:  "{\"skip-subnet-evm-upgrade-check\": true}",
   406  			expectedErr: nil,
   407  		},
   408  		{
   409  			// we do not expect an err when skip-subnet-evm-upgrade-check is set to true
   410  			genesisJSON: genesisJSONSubnetEVMLateEnablement,
   411  			configJSON:  "{\"skip-subnet-evm-upgrade-check\": true}",
   412  			expectedErr: nil,
   413  		},
   414  	}
   415  
   416  	for _, test := range genesisTests {
   417  		ctx, dbManager, genesisBytes, issuer := setupGenesis(t, test.genesisJSON)
   418  		vm := &VM{}
   419  		err := vm.Initialize(
   420  			context.Background(),
   421  			ctx,
   422  			dbManager,
   423  			genesisBytes,
   424  			[]byte(""),
   425  			[]byte(test.configJSON),
   426  			issuer,
   427  			[]*engCommon.Fx{},
   428  			nil,
   429  		)
   430  
   431  		require.ErrorIs(t, err, test.expectedErr)
   432  	}
   433  }
   434  
   435  func TestBuildEthTxBlock(t *testing.T) {
   436  	// reduce block gas cost
   437  	issuer, vm, dbManager, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "{\"pruning-enabled\":true}", "")
   438  
   439  	defer func() {
   440  		if err := vm.Shutdown(context.Background()); err != nil {
   441  			t.Fatal(err)
   442  		}
   443  	}()
   444  
   445  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
   446  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
   447  
   448  	key, err := accountKeystore.NewKey(rand.Reader)
   449  	if err != nil {
   450  		t.Fatal(err)
   451  	}
   452  
   453  	tx := types.NewTransaction(uint64(0), key.Address, firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
   454  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
   455  	if err != nil {
   456  		t.Fatal(err)
   457  	}
   458  	errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
   459  	for i, err := range errs {
   460  		if err != nil {
   461  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
   462  		}
   463  	}
   464  
   465  	blk1 := issueAndAccept(t, issuer, vm)
   466  	newHead := <-newTxPoolHeadChan
   467  	if newHead.Head.Hash() != common.Hash(blk1.ID()) {
   468  		t.Fatalf("Expected new block to match")
   469  	}
   470  
   471  	txs := make([]*types.Transaction, 10)
   472  	for i := 0; i < 10; i++ {
   473  		tx := types.NewTransaction(uint64(i), key.Address, big.NewInt(10), 21000, big.NewInt(testMinGasPrice), nil)
   474  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), key.PrivateKey)
   475  		if err != nil {
   476  			t.Fatal(err)
   477  		}
   478  		txs[i] = signedTx
   479  	}
   480  	errs = vm.txPool.AddRemotesSync(txs)
   481  	for i, err := range errs {
   482  		if err != nil {
   483  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
   484  		}
   485  	}
   486  
   487  	vm.clock.Set(vm.clock.Time().Add(2 * time.Second))
   488  	blk2 := issueAndAccept(t, issuer, vm)
   489  	newHead = <-newTxPoolHeadChan
   490  	if newHead.Head.Hash() != common.Hash(blk2.ID()) {
   491  		t.Fatalf("Expected new block to match")
   492  	}
   493  
   494  	if status := blk2.Status(); status != choices.Accepted {
   495  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
   496  	}
   497  
   498  	lastAcceptedID, err := vm.LastAccepted(context.Background())
   499  	if err != nil {
   500  		t.Fatal(err)
   501  	}
   502  	if lastAcceptedID != blk2.ID() {
   503  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk2.ID(), lastAcceptedID)
   504  	}
   505  
   506  	ethBlk1 := blk1.(*chain.BlockWrapper).Block.(*Block).ethBlock
   507  	if ethBlk1Root := ethBlk1.Root(); !vm.blockChain.HasState(ethBlk1Root) {
   508  		t.Fatalf("Expected blk1 state root to not yet be pruned after blk2 was accepted because of tip buffer")
   509  	}
   510  
   511  	// Clear the cache and ensure that GetBlock returns internal blocks with the correct status
   512  	vm.State.Flush()
   513  	blk2Refreshed, err := vm.GetBlockInternal(context.Background(), blk2.ID())
   514  	if err != nil {
   515  		t.Fatal(err)
   516  	}
   517  	if status := blk2Refreshed.Status(); status != choices.Accepted {
   518  		t.Fatalf("Expected refreshed blk2 to be Accepted, but found status: %s", status)
   519  	}
   520  
   521  	blk1RefreshedID := blk2Refreshed.Parent()
   522  	blk1Refreshed, err := vm.GetBlockInternal(context.Background(), blk1RefreshedID)
   523  	if err != nil {
   524  		t.Fatal(err)
   525  	}
   526  	if status := blk1Refreshed.Status(); status != choices.Accepted {
   527  		t.Fatalf("Expected refreshed blk1 to be Accepted, but found status: %s", status)
   528  	}
   529  
   530  	if blk1Refreshed.ID() != blk1.ID() {
   531  		t.Fatalf("Found unexpected blkID for parent of blk2")
   532  	}
   533  
   534  	restartedVM := &VM{}
   535  	genesisBytes := buildGenesisTest(t, genesisJSONSubnetEVM)
   536  
   537  	if err := restartedVM.Initialize(
   538  		context.Background(),
   539  		NewContext(),
   540  		dbManager,
   541  		genesisBytes,
   542  		[]byte(""),
   543  		[]byte("{\"pruning-enabled\":true}"),
   544  		issuer,
   545  		[]*engCommon.Fx{},
   546  		nil,
   547  	); err != nil {
   548  		t.Fatal(err)
   549  	}
   550  
   551  	// State root should not have been committed and discarded on restart
   552  	if ethBlk1Root := ethBlk1.Root(); restartedVM.blockChain.HasState(ethBlk1Root) {
   553  		t.Fatalf("Expected blk1 state root to be pruned after blk2 was accepted on top of it in pruning mode")
   554  	}
   555  
   556  	// State root should be committed when accepted tip on shutdown
   557  	ethBlk2 := blk2.(*chain.BlockWrapper).Block.(*Block).ethBlock
   558  	if ethBlk2Root := ethBlk2.Root(); !restartedVM.blockChain.HasState(ethBlk2Root) {
   559  		t.Fatalf("Expected blk2 state root to not be pruned after shutdown (last accepted tip should be committed)")
   560  	}
   561  }
   562  
   563  // Regression test to ensure that after accepting block A
   564  // then calling SetPreference on block B (when it becomes preferred)
   565  // and the head of a longer chain (block D) does not corrupt the
   566  // canonical chain.
   567  //  A
   568  // / \
   569  // B  C
   570  //    |
   571  //    D
   572  func TestSetPreferenceRace(t *testing.T) {
   573  	// Create two VMs which will agree on block A and then
   574  	// build the two distinct preferred chains above
   575  	issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "{\"pruning-enabled\":true}", "")
   576  	issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "{\"pruning-enabled\":true}", "")
   577  
   578  	defer func() {
   579  		if err := vm1.Shutdown(context.Background()); err != nil {
   580  			t.Fatal(err)
   581  		}
   582  
   583  		if err := vm2.Shutdown(context.Background()); err != nil {
   584  			t.Fatal(err)
   585  		}
   586  	}()
   587  
   588  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
   589  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
   590  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
   591  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
   592  
   593  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
   594  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[0])
   595  	if err != nil {
   596  		t.Fatal(err)
   597  	}
   598  
   599  	txErrors := vm1.txPool.AddRemotesSync([]*types.Transaction{signedTx})
   600  	for i, err := range txErrors {
   601  		if err != nil {
   602  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
   603  		}
   604  	}
   605  
   606  	<-issuer1
   607  
   608  	vm1BlkA, err := vm1.BuildBlock(context.Background())
   609  	if err != nil {
   610  		t.Fatalf("Failed to build block with import transaction: %s", err)
   611  	}
   612  
   613  	if err := vm1BlkA.Verify(context.Background()); err != nil {
   614  		t.Fatalf("Block failed verification on VM1: %s", err)
   615  	}
   616  
   617  	if status := vm1BlkA.Status(); status != choices.Processing {
   618  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   619  	}
   620  
   621  	if err := vm1.SetPreference(context.Background(), vm1BlkA.ID()); err != nil {
   622  		t.Fatal(err)
   623  	}
   624  
   625  	vm2BlkA, err := vm2.ParseBlock(context.Background(), vm1BlkA.Bytes())
   626  	if err != nil {
   627  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
   628  	}
   629  	if err := vm2BlkA.Verify(context.Background()); err != nil {
   630  		t.Fatalf("Block failed verification on VM2: %s", err)
   631  	}
   632  	if status := vm2BlkA.Status(); status != choices.Processing {
   633  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
   634  	}
   635  	if err := vm2.SetPreference(context.Background(), vm2BlkA.ID()); err != nil {
   636  		t.Fatal(err)
   637  	}
   638  
   639  	if err := vm1BlkA.Accept(context.Background()); err != nil {
   640  		t.Fatalf("VM1 failed to accept block: %s", err)
   641  	}
   642  	if err := vm2BlkA.Accept(context.Background()); err != nil {
   643  		t.Fatalf("VM2 failed to accept block: %s", err)
   644  	}
   645  
   646  	newHead := <-newTxPoolHeadChan1
   647  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
   648  		t.Fatalf("Expected new block to match")
   649  	}
   650  	newHead = <-newTxPoolHeadChan2
   651  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
   652  		t.Fatalf("Expected new block to match")
   653  	}
   654  
   655  	// Create list of 10 successive transactions to build block A on vm1
   656  	// and to be split into two separate blocks on VM2
   657  	txs := make([]*types.Transaction, 10)
   658  	for i := 0; i < 10; i++ {
   659  		tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(testMinGasPrice), nil)
   660  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[1])
   661  		if err != nil {
   662  			t.Fatal(err)
   663  		}
   664  		txs[i] = signedTx
   665  	}
   666  
   667  	var errs []error
   668  
   669  	// Add the remote transactions, build the block, and set VM1's preference for block A
   670  	errs = vm1.txPool.AddRemotesSync(txs)
   671  	for i, err := range errs {
   672  		if err != nil {
   673  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
   674  		}
   675  	}
   676  
   677  	<-issuer1
   678  
   679  	vm1BlkB, err := vm1.BuildBlock(context.Background())
   680  	if err != nil {
   681  		t.Fatal(err)
   682  	}
   683  
   684  	if err := vm1BlkB.Verify(context.Background()); err != nil {
   685  		t.Fatal(err)
   686  	}
   687  
   688  	if status := vm1BlkB.Status(); status != choices.Processing {
   689  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   690  	}
   691  
   692  	if err := vm1.SetPreference(context.Background(), vm1BlkB.ID()); err != nil {
   693  		t.Fatal(err)
   694  	}
   695  
   696  	// Split the transactions over two blocks, and set VM2's preference to them in sequence
   697  	// after building each block
   698  	// Block C
   699  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
   700  	for i, err := range errs {
   701  		if err != nil {
   702  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
   703  		}
   704  	}
   705  
   706  	<-issuer2
   707  	vm2BlkC, err := vm2.BuildBlock(context.Background())
   708  	if err != nil {
   709  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
   710  	}
   711  
   712  	if err := vm2BlkC.Verify(context.Background()); err != nil {
   713  		t.Fatalf("BlkC failed verification on VM2: %s", err)
   714  	}
   715  
   716  	if status := vm2BlkC.Status(); status != choices.Processing {
   717  		t.Fatalf("Expected status of built block C to be %s, but found %s", choices.Processing, status)
   718  	}
   719  
   720  	if err := vm2.SetPreference(context.Background(), vm2BlkC.ID()); err != nil {
   721  		t.Fatal(err)
   722  	}
   723  
   724  	newHead = <-newTxPoolHeadChan2
   725  	if newHead.Head.Hash() != common.Hash(vm2BlkC.ID()) {
   726  		t.Fatalf("Expected new block to match")
   727  	}
   728  
   729  	// Block D
   730  	errs = vm2.txPool.AddRemotesSync(txs[5:10])
   731  	for i, err := range errs {
   732  		if err != nil {
   733  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
   734  		}
   735  	}
   736  
   737  	<-issuer2
   738  	vm2BlkD, err := vm2.BuildBlock(context.Background())
   739  	if err != nil {
   740  		t.Fatalf("Failed to build BlkD on VM2: %s", err)
   741  	}
   742  
   743  	if err := vm2BlkD.Verify(context.Background()); err != nil {
   744  		t.Fatalf("BlkD failed verification on VM2: %s", err)
   745  	}
   746  
   747  	if status := vm2BlkD.Status(); status != choices.Processing {
   748  		t.Fatalf("Expected status of built block D to be %s, but found %s", choices.Processing, status)
   749  	}
   750  
   751  	if err := vm2.SetPreference(context.Background(), vm2BlkD.ID()); err != nil {
   752  		t.Fatal(err)
   753  	}
   754  
   755  	// VM1 receives blkC and blkD from VM1
   756  	// and happens to call SetPreference on blkD without ever calling SetPreference
   757  	// on blkC
   758  	// Here we parse them in reverse order to simulate receiving a chain from the tip
   759  	// back to the last accepted block as would typically be the case in the consensus
   760  	// engine
   761  	vm1BlkD, err := vm1.ParseBlock(context.Background(), vm2BlkD.Bytes())
   762  	if err != nil {
   763  		t.Fatalf("VM1 errored parsing blkD: %s", err)
   764  	}
   765  	vm1BlkC, err := vm1.ParseBlock(context.Background(), vm2BlkC.Bytes())
   766  	if err != nil {
   767  		t.Fatalf("VM1 errored parsing blkC: %s", err)
   768  	}
   769  
   770  	// The blocks must be verified in order. This invariant is maintained
   771  	// in the consensus engine.
   772  	if err := vm1BlkC.Verify(context.Background()); err != nil {
   773  		t.Fatalf("VM1 BlkC failed verification: %s", err)
   774  	}
   775  	if err := vm1BlkD.Verify(context.Background()); err != nil {
   776  		t.Fatalf("VM1 BlkD failed verification: %s", err)
   777  	}
   778  
   779  	// Set VM1's preference to blockD, skipping blockC
   780  	if err := vm1.SetPreference(context.Background(), vm1BlkD.ID()); err != nil {
   781  		t.Fatal(err)
   782  	}
   783  
   784  	// Accept the longer chain on both VMs and ensure there are no errors
   785  	// VM1 Accepts the blocks in order
   786  	if err := vm1BlkC.Accept(context.Background()); err != nil {
   787  		t.Fatalf("VM1 BlkC failed on accept: %s", err)
   788  	}
   789  	if err := vm1BlkD.Accept(context.Background()); err != nil {
   790  		t.Fatalf("VM1 BlkC failed on accept: %s", err)
   791  	}
   792  
   793  	// VM2 Accepts the blocks in order
   794  	if err := vm2BlkC.Accept(context.Background()); err != nil {
   795  		t.Fatalf("VM2 BlkC failed on accept: %s", err)
   796  	}
   797  	if err := vm2BlkD.Accept(context.Background()); err != nil {
   798  		t.Fatalf("VM2 BlkC failed on accept: %s", err)
   799  	}
   800  
   801  	log.Info("Validating canonical chain")
   802  	// Verify the Canonical Chain for Both VMs
   803  	if err := vm2.blockChain.ValidateCanonicalChain(); err != nil {
   804  		t.Fatalf("VM2 failed canonical chain verification due to: %s", err)
   805  	}
   806  
   807  	if err := vm1.blockChain.ValidateCanonicalChain(); err != nil {
   808  		t.Fatalf("VM1 failed canonical chain verification due to: %s", err)
   809  	}
   810  }
   811  
   812  // Regression test to ensure that a VM that accepts block A and B
   813  // will not attempt to orphan either when verifying blocks C and D
   814  // from another VM (which have a common ancestor under the finalized
   815  // frontier).
   816  //   A
   817  //  / \
   818  // B   C
   819  //
   820  // verifies block B and C, then Accepts block B. Then we test to ensure
   821  // that the VM defends against any attempt to set the preference or to
   822  // accept block C, which should be an orphaned block at this point and
   823  // get rejected.
   824  func TestReorgProtection(t *testing.T) {
   825  	issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "{\"pruning-enabled\":false}", "")
   826  	issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "{\"pruning-enabled\":false}", "")
   827  
   828  	defer func() {
   829  		if err := vm1.Shutdown(context.Background()); err != nil {
   830  			t.Fatal(err)
   831  		}
   832  
   833  		if err := vm2.Shutdown(context.Background()); err != nil {
   834  			t.Fatal(err)
   835  		}
   836  	}()
   837  
   838  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
   839  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
   840  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
   841  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
   842  
   843  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
   844  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[0])
   845  	if err != nil {
   846  		t.Fatal(err)
   847  	}
   848  
   849  	txErrors := vm1.txPool.AddRemotesSync([]*types.Transaction{signedTx})
   850  	for i, err := range txErrors {
   851  		if err != nil {
   852  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
   853  		}
   854  	}
   855  
   856  	<-issuer1
   857  
   858  	vm1BlkA, err := vm1.BuildBlock(context.Background())
   859  	if err != nil {
   860  		t.Fatalf("Failed to build block with import transaction: %s", err)
   861  	}
   862  
   863  	if err := vm1BlkA.Verify(context.Background()); err != nil {
   864  		t.Fatalf("Block failed verification on VM1: %s", err)
   865  	}
   866  
   867  	if status := vm1BlkA.Status(); status != choices.Processing {
   868  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   869  	}
   870  
   871  	if err := vm1.SetPreference(context.Background(), vm1BlkA.ID()); err != nil {
   872  		t.Fatal(err)
   873  	}
   874  
   875  	vm2BlkA, err := vm2.ParseBlock(context.Background(), vm1BlkA.Bytes())
   876  	if err != nil {
   877  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
   878  	}
   879  	if err := vm2BlkA.Verify(context.Background()); err != nil {
   880  		t.Fatalf("Block failed verification on VM2: %s", err)
   881  	}
   882  	if status := vm2BlkA.Status(); status != choices.Processing {
   883  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
   884  	}
   885  	if err := vm2.SetPreference(context.Background(), vm2BlkA.ID()); err != nil {
   886  		t.Fatal(err)
   887  	}
   888  
   889  	if err := vm1BlkA.Accept(context.Background()); err != nil {
   890  		t.Fatalf("VM1 failed to accept block: %s", err)
   891  	}
   892  	if err := vm2BlkA.Accept(context.Background()); err != nil {
   893  		t.Fatalf("VM2 failed to accept block: %s", err)
   894  	}
   895  
   896  	newHead := <-newTxPoolHeadChan1
   897  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
   898  		t.Fatalf("Expected new block to match")
   899  	}
   900  	newHead = <-newTxPoolHeadChan2
   901  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
   902  		t.Fatalf("Expected new block to match")
   903  	}
   904  
   905  	// Create list of 10 successive transactions to build block A on vm1
   906  	// and to be split into two separate blocks on VM2
   907  	txs := make([]*types.Transaction, 10)
   908  	for i := 0; i < 10; i++ {
   909  		tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(testMinGasPrice), nil)
   910  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[1])
   911  		if err != nil {
   912  			t.Fatal(err)
   913  		}
   914  		txs[i] = signedTx
   915  	}
   916  
   917  	var errs []error
   918  
   919  	// Add the remote transactions, build the block, and set VM1's preference for block A
   920  	errs = vm1.txPool.AddRemotesSync(txs)
   921  	for i, err := range errs {
   922  		if err != nil {
   923  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
   924  		}
   925  	}
   926  
   927  	<-issuer1
   928  
   929  	vm1BlkB, err := vm1.BuildBlock(context.Background())
   930  	if err != nil {
   931  		t.Fatal(err)
   932  	}
   933  
   934  	if err := vm1BlkB.Verify(context.Background()); err != nil {
   935  		t.Fatal(err)
   936  	}
   937  
   938  	if status := vm1BlkB.Status(); status != choices.Processing {
   939  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   940  	}
   941  
   942  	if err := vm1.SetPreference(context.Background(), vm1BlkB.ID()); err != nil {
   943  		t.Fatal(err)
   944  	}
   945  
   946  	// Split the transactions over two blocks, and set VM2's preference to them in sequence
   947  	// after building each block
   948  	// Block C
   949  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
   950  	for i, err := range errs {
   951  		if err != nil {
   952  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
   953  		}
   954  	}
   955  
   956  	<-issuer2
   957  	vm2BlkC, err := vm2.BuildBlock(context.Background())
   958  	if err != nil {
   959  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
   960  	}
   961  
   962  	if err := vm2BlkC.Verify(context.Background()); err != nil {
   963  		t.Fatalf("Block failed verification on VM2: %s", err)
   964  	}
   965  	if status := vm2BlkC.Status(); status != choices.Processing {
   966  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
   967  	}
   968  
   969  	vm1BlkC, err := vm1.ParseBlock(context.Background(), vm2BlkC.Bytes())
   970  	if err != nil {
   971  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
   972  	}
   973  
   974  	if err := vm1BlkC.Verify(context.Background()); err != nil {
   975  		t.Fatalf("Block failed verification on VM1: %s", err)
   976  	}
   977  
   978  	// Accept B, such that block C should get Rejected.
   979  	if err := vm1BlkB.Accept(context.Background()); err != nil {
   980  		t.Fatalf("VM1 failed to accept block: %s", err)
   981  	}
   982  
   983  	// The below (setting preference blocks that have a common ancestor
   984  	// with the preferred chain lower than the last finalized block)
   985  	// should NEVER happen. However, the VM defends against this
   986  	// just in case.
   987  	if err := vm1.SetPreference(context.Background(), vm1BlkC.ID()); !strings.Contains(err.Error(), "cannot orphan finalized block") {
   988  		t.Fatalf("Unexpected error when setting preference that would trigger reorg: %s", err)
   989  	}
   990  
   991  	if err := vm1BlkC.Accept(context.Background()); !strings.Contains(err.Error(), "expected accepted block to have parent") {
   992  		t.Fatalf("Unexpected error when setting block at finalized height: %s", err)
   993  	}
   994  }
   995  
   996  // Regression test to ensure that a VM that accepts block C while preferring
   997  // block B will trigger a reorg.
   998  //   A
   999  //  / \
  1000  // B   C
  1001  func TestNonCanonicalAccept(t *testing.T) {
  1002  	issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1003  	issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1004  
  1005  	defer func() {
  1006  		if err := vm1.Shutdown(context.Background()); err != nil {
  1007  			t.Fatal(err)
  1008  		}
  1009  
  1010  		if err := vm2.Shutdown(context.Background()); err != nil {
  1011  			t.Fatal(err)
  1012  		}
  1013  	}()
  1014  
  1015  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  1016  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  1017  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  1018  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  1019  
  1020  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  1021  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[0])
  1022  	if err != nil {
  1023  		t.Fatal(err)
  1024  	}
  1025  
  1026  	txErrors := vm1.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  1027  	for i, err := range txErrors {
  1028  		if err != nil {
  1029  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  1030  		}
  1031  	}
  1032  
  1033  	<-issuer1
  1034  
  1035  	vm1BlkA, err := vm1.BuildBlock(context.Background())
  1036  	if err != nil {
  1037  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1038  	}
  1039  
  1040  	if err := vm1BlkA.Verify(context.Background()); err != nil {
  1041  		t.Fatalf("Block failed verification on VM1: %s", err)
  1042  	}
  1043  
  1044  	if status := vm1BlkA.Status(); status != choices.Processing {
  1045  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1046  	}
  1047  
  1048  	if err := vm1.SetPreference(context.Background(), vm1BlkA.ID()); err != nil {
  1049  		t.Fatal(err)
  1050  	}
  1051  
  1052  	vm2BlkA, err := vm2.ParseBlock(context.Background(), vm1BlkA.Bytes())
  1053  	if err != nil {
  1054  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1055  	}
  1056  	if err := vm2BlkA.Verify(context.Background()); err != nil {
  1057  		t.Fatalf("Block failed verification on VM2: %s", err)
  1058  	}
  1059  	if status := vm2BlkA.Status(); status != choices.Processing {
  1060  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1061  	}
  1062  	if err := vm2.SetPreference(context.Background(), vm2BlkA.ID()); err != nil {
  1063  		t.Fatal(err)
  1064  	}
  1065  
  1066  	if err := vm1BlkA.Accept(context.Background()); err != nil {
  1067  		t.Fatalf("VM1 failed to accept block: %s", err)
  1068  	}
  1069  	if err := vm2BlkA.Accept(context.Background()); err != nil {
  1070  		t.Fatalf("VM2 failed to accept block: %s", err)
  1071  	}
  1072  
  1073  	newHead := <-newTxPoolHeadChan1
  1074  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  1075  		t.Fatalf("Expected new block to match")
  1076  	}
  1077  	newHead = <-newTxPoolHeadChan2
  1078  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  1079  		t.Fatalf("Expected new block to match")
  1080  	}
  1081  
  1082  	// Create list of 10 successive transactions to build block A on vm1
  1083  	// and to be split into two separate blocks on VM2
  1084  	txs := make([]*types.Transaction, 10)
  1085  	for i := 0; i < 10; i++ {
  1086  		tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(testMinGasPrice), nil)
  1087  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[1])
  1088  		if err != nil {
  1089  			t.Fatal(err)
  1090  		}
  1091  		txs[i] = signedTx
  1092  	}
  1093  
  1094  	var errs []error
  1095  
  1096  	// Add the remote transactions, build the block, and set VM1's preference for block A
  1097  	errs = vm1.txPool.AddRemotesSync(txs)
  1098  	for i, err := range errs {
  1099  		if err != nil {
  1100  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  1101  		}
  1102  	}
  1103  
  1104  	<-issuer1
  1105  
  1106  	vm1BlkB, err := vm1.BuildBlock(context.Background())
  1107  	if err != nil {
  1108  		t.Fatal(err)
  1109  	}
  1110  
  1111  	if err := vm1BlkB.Verify(context.Background()); err != nil {
  1112  		t.Fatal(err)
  1113  	}
  1114  
  1115  	if status := vm1BlkB.Status(); status != choices.Processing {
  1116  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1117  	}
  1118  
  1119  	if err := vm1.SetPreference(context.Background(), vm1BlkB.ID()); err != nil {
  1120  		t.Fatal(err)
  1121  	}
  1122  
  1123  	vm1.blockChain.GetVMConfig().AllowUnfinalizedQueries = true
  1124  
  1125  	blkBHeight := vm1BlkB.Height()
  1126  	blkBHash := vm1BlkB.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1127  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkBHash {
  1128  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkBHash.Hex(), b.Hash().Hex())
  1129  	}
  1130  
  1131  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  1132  	for i, err := range errs {
  1133  		if err != nil {
  1134  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1135  		}
  1136  	}
  1137  
  1138  	<-issuer2
  1139  	vm2BlkC, err := vm2.BuildBlock(context.Background())
  1140  	if err != nil {
  1141  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  1142  	}
  1143  
  1144  	vm1BlkC, err := vm1.ParseBlock(context.Background(), vm2BlkC.Bytes())
  1145  	if err != nil {
  1146  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1147  	}
  1148  
  1149  	if err := vm1BlkC.Verify(context.Background()); err != nil {
  1150  		t.Fatalf("Block failed verification on VM1: %s", err)
  1151  	}
  1152  
  1153  	if err := vm1BlkC.Accept(context.Background()); err != nil {
  1154  		t.Fatalf("VM1 failed to accept block: %s", err)
  1155  	}
  1156  
  1157  	blkCHash := vm1BlkC.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1158  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkCHash {
  1159  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkCHash.Hex(), b.Hash().Hex())
  1160  	}
  1161  }
  1162  
  1163  // Regression test to ensure that a VM that verifies block B, C, then
  1164  // D (preferring block B) does not trigger a reorg through the re-verification
  1165  // of block C or D.
  1166  //   A
  1167  //  / \
  1168  // B   C
  1169  //     |
  1170  //     D
  1171  func TestStickyPreference(t *testing.T) {
  1172  	issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1173  	issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1174  
  1175  	defer func() {
  1176  		if err := vm1.Shutdown(context.Background()); err != nil {
  1177  			t.Fatal(err)
  1178  		}
  1179  
  1180  		if err := vm2.Shutdown(context.Background()); err != nil {
  1181  			t.Fatal(err)
  1182  		}
  1183  	}()
  1184  
  1185  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  1186  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  1187  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  1188  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  1189  
  1190  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  1191  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[0])
  1192  	if err != nil {
  1193  		t.Fatal(err)
  1194  	}
  1195  
  1196  	txErrors := vm1.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  1197  	for i, err := range txErrors {
  1198  		if err != nil {
  1199  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  1200  		}
  1201  	}
  1202  
  1203  	<-issuer1
  1204  
  1205  	vm1BlkA, err := vm1.BuildBlock(context.Background())
  1206  	if err != nil {
  1207  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1208  	}
  1209  
  1210  	if err := vm1BlkA.Verify(context.Background()); err != nil {
  1211  		t.Fatalf("Block failed verification on VM1: %s", err)
  1212  	}
  1213  
  1214  	if status := vm1BlkA.Status(); status != choices.Processing {
  1215  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1216  	}
  1217  
  1218  	if err := vm1.SetPreference(context.Background(), vm1BlkA.ID()); err != nil {
  1219  		t.Fatal(err)
  1220  	}
  1221  
  1222  	vm2BlkA, err := vm2.ParseBlock(context.Background(), vm1BlkA.Bytes())
  1223  	if err != nil {
  1224  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1225  	}
  1226  	if err := vm2BlkA.Verify(context.Background()); err != nil {
  1227  		t.Fatalf("Block failed verification on VM2: %s", err)
  1228  	}
  1229  	if status := vm2BlkA.Status(); status != choices.Processing {
  1230  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1231  	}
  1232  	if err := vm2.SetPreference(context.Background(), vm2BlkA.ID()); err != nil {
  1233  		t.Fatal(err)
  1234  	}
  1235  
  1236  	if err := vm1BlkA.Accept(context.Background()); err != nil {
  1237  		t.Fatalf("VM1 failed to accept block: %s", err)
  1238  	}
  1239  	if err := vm2BlkA.Accept(context.Background()); err != nil {
  1240  		t.Fatalf("VM2 failed to accept block: %s", err)
  1241  	}
  1242  
  1243  	newHead := <-newTxPoolHeadChan1
  1244  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  1245  		t.Fatalf("Expected new block to match")
  1246  	}
  1247  	newHead = <-newTxPoolHeadChan2
  1248  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  1249  		t.Fatalf("Expected new block to match")
  1250  	}
  1251  
  1252  	// Create list of 10 successive transactions to build block A on vm1
  1253  	// and to be split into two separate blocks on VM2
  1254  	txs := make([]*types.Transaction, 10)
  1255  	for i := 0; i < 10; i++ {
  1256  		tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(testMinGasPrice), nil)
  1257  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[1])
  1258  		if err != nil {
  1259  			t.Fatal(err)
  1260  		}
  1261  		txs[i] = signedTx
  1262  	}
  1263  
  1264  	var errs []error
  1265  
  1266  	// Add the remote transactions, build the block, and set VM1's preference for block A
  1267  	errs = vm1.txPool.AddRemotesSync(txs)
  1268  	for i, err := range errs {
  1269  		if err != nil {
  1270  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  1271  		}
  1272  	}
  1273  
  1274  	<-issuer1
  1275  
  1276  	vm1BlkB, err := vm1.BuildBlock(context.Background())
  1277  	if err != nil {
  1278  		t.Fatal(err)
  1279  	}
  1280  
  1281  	if err := vm1BlkB.Verify(context.Background()); err != nil {
  1282  		t.Fatal(err)
  1283  	}
  1284  
  1285  	if status := vm1BlkB.Status(); status != choices.Processing {
  1286  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1287  	}
  1288  
  1289  	if err := vm1.SetPreference(context.Background(), vm1BlkB.ID()); err != nil {
  1290  		t.Fatal(err)
  1291  	}
  1292  
  1293  	vm1.blockChain.GetVMConfig().AllowUnfinalizedQueries = true
  1294  
  1295  	blkBHeight := vm1BlkB.Height()
  1296  	blkBHash := vm1BlkB.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1297  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkBHash {
  1298  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkBHash.Hex(), b.Hash().Hex())
  1299  	}
  1300  
  1301  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  1302  	for i, err := range errs {
  1303  		if err != nil {
  1304  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1305  		}
  1306  	}
  1307  
  1308  	<-issuer2
  1309  	vm2BlkC, err := vm2.BuildBlock(context.Background())
  1310  	if err != nil {
  1311  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  1312  	}
  1313  
  1314  	if err := vm2BlkC.Verify(context.Background()); err != nil {
  1315  		t.Fatalf("BlkC failed verification on VM2: %s", err)
  1316  	}
  1317  
  1318  	if status := vm2BlkC.Status(); status != choices.Processing {
  1319  		t.Fatalf("Expected status of built block C to be %s, but found %s", choices.Processing, status)
  1320  	}
  1321  
  1322  	if err := vm2.SetPreference(context.Background(), vm2BlkC.ID()); err != nil {
  1323  		t.Fatal(err)
  1324  	}
  1325  
  1326  	newHead = <-newTxPoolHeadChan2
  1327  	if newHead.Head.Hash() != common.Hash(vm2BlkC.ID()) {
  1328  		t.Fatalf("Expected new block to match")
  1329  	}
  1330  
  1331  	errs = vm2.txPool.AddRemotesSync(txs[5:])
  1332  	for i, err := range errs {
  1333  		if err != nil {
  1334  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1335  		}
  1336  	}
  1337  
  1338  	<-issuer2
  1339  	vm2BlkD, err := vm2.BuildBlock(context.Background())
  1340  	if err != nil {
  1341  		t.Fatalf("Failed to build BlkD on VM2: %s", err)
  1342  	}
  1343  
  1344  	// Parse blocks produced in vm2
  1345  	vm1BlkC, err := vm1.ParseBlock(context.Background(), vm2BlkC.Bytes())
  1346  	if err != nil {
  1347  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1348  	}
  1349  	blkCHash := vm1BlkC.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1350  
  1351  	vm1BlkD, err := vm1.ParseBlock(context.Background(), vm2BlkD.Bytes())
  1352  	if err != nil {
  1353  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1354  	}
  1355  	blkDHeight := vm1BlkD.Height()
  1356  	blkDHash := vm1BlkD.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1357  
  1358  	// Should be no-ops
  1359  	if err := vm1BlkC.Verify(context.Background()); err != nil {
  1360  		t.Fatalf("Block failed verification on VM1: %s", err)
  1361  	}
  1362  	if err := vm1BlkD.Verify(context.Background()); err != nil {
  1363  		t.Fatalf("Block failed verification on VM1: %s", err)
  1364  	}
  1365  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkBHash {
  1366  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkBHash.Hex(), b.Hash().Hex())
  1367  	}
  1368  	if b := vm1.blockChain.GetBlockByNumber(blkDHeight); b != nil {
  1369  		t.Fatalf("expected block at %d to be nil but got %s", blkDHeight, b.Hash().Hex())
  1370  	}
  1371  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkBHash {
  1372  		t.Fatalf("expected current block to have hash %s but got %s", blkBHash.Hex(), b.Hash().Hex())
  1373  	}
  1374  
  1375  	// Should still be no-ops on re-verify
  1376  	if err := vm1BlkC.Verify(context.Background()); err != nil {
  1377  		t.Fatalf("Block failed verification on VM1: %s", err)
  1378  	}
  1379  	if err := vm1BlkD.Verify(context.Background()); err != nil {
  1380  		t.Fatalf("Block failed verification on VM1: %s", err)
  1381  	}
  1382  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkBHash {
  1383  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkBHash.Hex(), b.Hash().Hex())
  1384  	}
  1385  	if b := vm1.blockChain.GetBlockByNumber(blkDHeight); b != nil {
  1386  		t.Fatalf("expected block at %d to be nil but got %s", blkDHeight, b.Hash().Hex())
  1387  	}
  1388  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkBHash {
  1389  		t.Fatalf("expected current block to have hash %s but got %s", blkBHash.Hex(), b.Hash().Hex())
  1390  	}
  1391  
  1392  	// Should be queryable after setting preference to side chain
  1393  	if err := vm1.SetPreference(context.Background(), vm1BlkD.ID()); err != nil {
  1394  		t.Fatal(err)
  1395  	}
  1396  
  1397  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkCHash {
  1398  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkCHash.Hex(), b.Hash().Hex())
  1399  	}
  1400  	if b := vm1.blockChain.GetBlockByNumber(blkDHeight); b.Hash() != blkDHash {
  1401  		t.Fatalf("expected block at %d to have hash %s but got %s", blkDHeight, blkDHash.Hex(), b.Hash().Hex())
  1402  	}
  1403  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkDHash {
  1404  		t.Fatalf("expected current block to have hash %s but got %s", blkDHash.Hex(), b.Hash().Hex())
  1405  	}
  1406  
  1407  	// Attempt to accept out of order
  1408  	if err := vm1BlkD.Accept(context.Background()); !strings.Contains(err.Error(), "expected accepted block to have parent") {
  1409  		t.Fatalf("unexpected error when accepting out of order block: %s", err)
  1410  	}
  1411  
  1412  	// Accept in order
  1413  	if err := vm1BlkC.Accept(context.Background()); err != nil {
  1414  		t.Fatalf("Block failed verification on VM1: %s", err)
  1415  	}
  1416  	if err := vm1BlkD.Accept(context.Background()); err != nil {
  1417  		t.Fatalf("Block failed acceptance on VM1: %s", err)
  1418  	}
  1419  
  1420  	// Ensure queryable after accepting
  1421  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkCHash {
  1422  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkCHash.Hex(), b.Hash().Hex())
  1423  	}
  1424  	if b := vm1.blockChain.GetBlockByNumber(blkDHeight); b.Hash() != blkDHash {
  1425  		t.Fatalf("expected block at %d to have hash %s but got %s", blkDHeight, blkDHash.Hex(), b.Hash().Hex())
  1426  	}
  1427  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkDHash {
  1428  		t.Fatalf("expected current block to have hash %s but got %s", blkDHash.Hex(), b.Hash().Hex())
  1429  	}
  1430  }
  1431  
  1432  // Regression test to ensure that a VM that prefers block B is able to parse
  1433  // block C but unable to parse block D because it names B as an uncle, which
  1434  // are not supported.
  1435  //   A
  1436  //  / \
  1437  // B   C
  1438  //     |
  1439  //     D
  1440  func TestUncleBlock(t *testing.T) {
  1441  	issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1442  	issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1443  
  1444  	defer func() {
  1445  		if err := vm1.Shutdown(context.Background()); err != nil {
  1446  			t.Fatal(err)
  1447  		}
  1448  		if err := vm2.Shutdown(context.Background()); err != nil {
  1449  			t.Fatal(err)
  1450  		}
  1451  	}()
  1452  
  1453  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  1454  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  1455  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  1456  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  1457  
  1458  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  1459  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[0])
  1460  	if err != nil {
  1461  		t.Fatal(err)
  1462  	}
  1463  
  1464  	txErrors := vm1.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  1465  	for i, err := range txErrors {
  1466  		if err != nil {
  1467  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  1468  		}
  1469  	}
  1470  
  1471  	<-issuer1
  1472  
  1473  	vm1BlkA, err := vm1.BuildBlock(context.Background())
  1474  	if err != nil {
  1475  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1476  	}
  1477  
  1478  	if err := vm1BlkA.Verify(context.Background()); err != nil {
  1479  		t.Fatalf("Block failed verification on VM1: %s", err)
  1480  	}
  1481  
  1482  	if status := vm1BlkA.Status(); status != choices.Processing {
  1483  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1484  	}
  1485  
  1486  	if err := vm1.SetPreference(context.Background(), vm1BlkA.ID()); err != nil {
  1487  		t.Fatal(err)
  1488  	}
  1489  
  1490  	vm2BlkA, err := vm2.ParseBlock(context.Background(), vm1BlkA.Bytes())
  1491  	if err != nil {
  1492  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1493  	}
  1494  	if err := vm2BlkA.Verify(context.Background()); err != nil {
  1495  		t.Fatalf("Block failed verification on VM2: %s", err)
  1496  	}
  1497  	if status := vm2BlkA.Status(); status != choices.Processing {
  1498  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1499  	}
  1500  	if err := vm2.SetPreference(context.Background(), vm2BlkA.ID()); err != nil {
  1501  		t.Fatal(err)
  1502  	}
  1503  
  1504  	if err := vm1BlkA.Accept(context.Background()); err != nil {
  1505  		t.Fatalf("VM1 failed to accept block: %s", err)
  1506  	}
  1507  	if err := vm2BlkA.Accept(context.Background()); err != nil {
  1508  		t.Fatalf("VM2 failed to accept block: %s", err)
  1509  	}
  1510  
  1511  	newHead := <-newTxPoolHeadChan1
  1512  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  1513  		t.Fatalf("Expected new block to match")
  1514  	}
  1515  	newHead = <-newTxPoolHeadChan2
  1516  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  1517  		t.Fatalf("Expected new block to match")
  1518  	}
  1519  
  1520  	txs := make([]*types.Transaction, 10)
  1521  	for i := 0; i < 10; i++ {
  1522  		tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(testMinGasPrice), nil)
  1523  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[1])
  1524  		if err != nil {
  1525  			t.Fatal(err)
  1526  		}
  1527  		txs[i] = signedTx
  1528  	}
  1529  
  1530  	var errs []error
  1531  
  1532  	errs = vm1.txPool.AddRemotesSync(txs)
  1533  	for i, err := range errs {
  1534  		if err != nil {
  1535  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  1536  		}
  1537  	}
  1538  
  1539  	<-issuer1
  1540  
  1541  	vm1BlkB, err := vm1.BuildBlock(context.Background())
  1542  	if err != nil {
  1543  		t.Fatal(err)
  1544  	}
  1545  
  1546  	if err := vm1BlkB.Verify(context.Background()); err != nil {
  1547  		t.Fatal(err)
  1548  	}
  1549  
  1550  	if status := vm1BlkB.Status(); status != choices.Processing {
  1551  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1552  	}
  1553  
  1554  	if err := vm1.SetPreference(context.Background(), vm1BlkB.ID()); err != nil {
  1555  		t.Fatal(err)
  1556  	}
  1557  
  1558  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  1559  	for i, err := range errs {
  1560  		if err != nil {
  1561  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1562  		}
  1563  	}
  1564  
  1565  	<-issuer2
  1566  	vm2BlkC, err := vm2.BuildBlock(context.Background())
  1567  	if err != nil {
  1568  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  1569  	}
  1570  
  1571  	if err := vm2BlkC.Verify(context.Background()); err != nil {
  1572  		t.Fatalf("BlkC failed verification on VM2: %s", err)
  1573  	}
  1574  
  1575  	if status := vm2BlkC.Status(); status != choices.Processing {
  1576  		t.Fatalf("Expected status of built block C to be %s, but found %s", choices.Processing, status)
  1577  	}
  1578  
  1579  	if err := vm2.SetPreference(context.Background(), vm2BlkC.ID()); err != nil {
  1580  		t.Fatal(err)
  1581  	}
  1582  
  1583  	newHead = <-newTxPoolHeadChan2
  1584  	if newHead.Head.Hash() != common.Hash(vm2BlkC.ID()) {
  1585  		t.Fatalf("Expected new block to match")
  1586  	}
  1587  
  1588  	errs = vm2.txPool.AddRemotesSync(txs[5:10])
  1589  	for i, err := range errs {
  1590  		if err != nil {
  1591  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1592  		}
  1593  	}
  1594  
  1595  	<-issuer2
  1596  	vm2BlkD, err := vm2.BuildBlock(context.Background())
  1597  	if err != nil {
  1598  		t.Fatalf("Failed to build BlkD on VM2: %s", err)
  1599  	}
  1600  
  1601  	// Create uncle block from blkD
  1602  	blkDEthBlock := vm2BlkD.(*chain.BlockWrapper).Block.(*Block).ethBlock
  1603  	uncles := []*types.Header{vm1BlkB.(*chain.BlockWrapper).Block.(*Block).ethBlock.Header()}
  1604  	uncleBlockHeader := types.CopyHeader(blkDEthBlock.Header())
  1605  	uncleBlockHeader.UncleHash = types.CalcUncleHash(uncles)
  1606  
  1607  	uncleEthBlock := types.NewBlock(
  1608  		uncleBlockHeader,
  1609  		blkDEthBlock.Transactions(),
  1610  		uncles,
  1611  		nil,
  1612  		new(trie.Trie),
  1613  	)
  1614  	uncleBlock := vm2.newBlock(uncleEthBlock)
  1615  
  1616  	if err := uncleBlock.Verify(context.Background()); !errors.Is(err, errUnclesUnsupported) {
  1617  		t.Fatalf("VM2 should have failed with %q but got %q", errUnclesUnsupported, err.Error())
  1618  	}
  1619  	if _, err := vm1.ParseBlock(context.Background(), vm2BlkC.Bytes()); err != nil {
  1620  		t.Fatalf("VM1 errored parsing blkC: %s", err)
  1621  	}
  1622  	if _, err := vm1.ParseBlock(context.Background(), uncleBlock.Bytes()); !errors.Is(err, errUnclesUnsupported) {
  1623  		t.Fatalf("VM1 should have failed with %q but got %q", errUnclesUnsupported, err.Error())
  1624  	}
  1625  }
  1626  
  1627  // Regression test to ensure that a VM that is not able to parse a block that
  1628  // contains no transactions.
  1629  func TestEmptyBlock(t *testing.T) {
  1630  	issuer, vm, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1631  
  1632  	defer func() {
  1633  		if err := vm.Shutdown(context.Background()); err != nil {
  1634  			t.Fatal(err)
  1635  		}
  1636  	}()
  1637  
  1638  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  1639  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  1640  	if err != nil {
  1641  		t.Fatal(err)
  1642  	}
  1643  
  1644  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  1645  	for i, err := range txErrors {
  1646  		if err != nil {
  1647  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  1648  		}
  1649  	}
  1650  
  1651  	<-issuer
  1652  
  1653  	blk, err := vm.BuildBlock(context.Background())
  1654  	if err != nil {
  1655  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1656  	}
  1657  
  1658  	// Create empty block from blkA
  1659  	ethBlock := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  1660  
  1661  	emptyEthBlock := types.NewBlock(
  1662  		types.CopyHeader(ethBlock.Header()),
  1663  		nil,
  1664  		nil,
  1665  		nil,
  1666  		new(trie.Trie),
  1667  	)
  1668  
  1669  	emptyBlock := vm.newBlock(emptyEthBlock)
  1670  
  1671  	if _, err := vm.ParseBlock(context.Background(), emptyBlock.Bytes()); !errors.Is(err, errEmptyBlock) {
  1672  		t.Fatalf("VM should have failed with errEmptyBlock but got %s", err.Error())
  1673  	}
  1674  	if err := emptyBlock.Verify(context.Background()); !errors.Is(err, errEmptyBlock) {
  1675  		t.Fatalf("block should have failed verification with errEmptyBlock but got %s", err.Error())
  1676  	}
  1677  }
  1678  
  1679  // Regression test to ensure that a VM that verifies block B, C, then
  1680  // D (preferring block B) reorgs when C and then D are accepted.
  1681  //   A
  1682  //  / \
  1683  // B   C
  1684  //     |
  1685  //     D
  1686  func TestAcceptReorg(t *testing.T) {
  1687  	issuer1, vm1, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1688  	issuer2, vm2, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1689  
  1690  	defer func() {
  1691  		if err := vm1.Shutdown(context.Background()); err != nil {
  1692  			t.Fatal(err)
  1693  		}
  1694  
  1695  		if err := vm2.Shutdown(context.Background()); err != nil {
  1696  			t.Fatal(err)
  1697  		}
  1698  	}()
  1699  
  1700  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  1701  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  1702  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  1703  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  1704  
  1705  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  1706  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[0])
  1707  	if err != nil {
  1708  		t.Fatal(err)
  1709  	}
  1710  
  1711  	txErrors := vm1.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  1712  	for i, err := range txErrors {
  1713  		if err != nil {
  1714  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  1715  		}
  1716  	}
  1717  
  1718  	<-issuer1
  1719  
  1720  	vm1BlkA, err := vm1.BuildBlock(context.Background())
  1721  	if err != nil {
  1722  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1723  	}
  1724  
  1725  	if err := vm1BlkA.Verify(context.Background()); err != nil {
  1726  		t.Fatalf("Block failed verification on VM1: %s", err)
  1727  	}
  1728  
  1729  	if status := vm1BlkA.Status(); status != choices.Processing {
  1730  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1731  	}
  1732  
  1733  	if err := vm1.SetPreference(context.Background(), vm1BlkA.ID()); err != nil {
  1734  		t.Fatal(err)
  1735  	}
  1736  
  1737  	vm2BlkA, err := vm2.ParseBlock(context.Background(), vm1BlkA.Bytes())
  1738  	if err != nil {
  1739  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1740  	}
  1741  	if err := vm2BlkA.Verify(context.Background()); err != nil {
  1742  		t.Fatalf("Block failed verification on VM2: %s", err)
  1743  	}
  1744  	if status := vm2BlkA.Status(); status != choices.Processing {
  1745  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1746  	}
  1747  	if err := vm2.SetPreference(context.Background(), vm2BlkA.ID()); err != nil {
  1748  		t.Fatal(err)
  1749  	}
  1750  
  1751  	if err := vm1BlkA.Accept(context.Background()); err != nil {
  1752  		t.Fatalf("VM1 failed to accept block: %s", err)
  1753  	}
  1754  	if err := vm2BlkA.Accept(context.Background()); err != nil {
  1755  		t.Fatalf("VM2 failed to accept block: %s", err)
  1756  	}
  1757  
  1758  	newHead := <-newTxPoolHeadChan1
  1759  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  1760  		t.Fatalf("Expected new block to match")
  1761  	}
  1762  	newHead = <-newTxPoolHeadChan2
  1763  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  1764  		t.Fatalf("Expected new block to match")
  1765  	}
  1766  
  1767  	// Create list of 10 successive transactions to build block A on vm1
  1768  	// and to be split into two separate blocks on VM2
  1769  	txs := make([]*types.Transaction, 10)
  1770  	for i := 0; i < 10; i++ {
  1771  		tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(testMinGasPrice), nil)
  1772  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainConfig.ChainID), testKeys[1])
  1773  		if err != nil {
  1774  			t.Fatal(err)
  1775  		}
  1776  		txs[i] = signedTx
  1777  	}
  1778  
  1779  	// Add the remote transactions, build the block, and set VM1's preference
  1780  	// for block B
  1781  	errs := vm1.txPool.AddRemotesSync(txs)
  1782  	for i, err := range errs {
  1783  		if err != nil {
  1784  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  1785  		}
  1786  	}
  1787  
  1788  	<-issuer1
  1789  
  1790  	vm1BlkB, err := vm1.BuildBlock(context.Background())
  1791  	if err != nil {
  1792  		t.Fatal(err)
  1793  	}
  1794  
  1795  	if err := vm1BlkB.Verify(context.Background()); err != nil {
  1796  		t.Fatal(err)
  1797  	}
  1798  
  1799  	if status := vm1BlkB.Status(); status != choices.Processing {
  1800  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1801  	}
  1802  
  1803  	if err := vm1.SetPreference(context.Background(), vm1BlkB.ID()); err != nil {
  1804  		t.Fatal(err)
  1805  	}
  1806  
  1807  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  1808  	for i, err := range errs {
  1809  		if err != nil {
  1810  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1811  		}
  1812  	}
  1813  
  1814  	<-issuer2
  1815  
  1816  	vm2BlkC, err := vm2.BuildBlock(context.Background())
  1817  	if err != nil {
  1818  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  1819  	}
  1820  
  1821  	if err := vm2BlkC.Verify(context.Background()); err != nil {
  1822  		t.Fatalf("BlkC failed verification on VM2: %s", err)
  1823  	}
  1824  
  1825  	if err := vm2.SetPreference(context.Background(), vm2BlkC.ID()); err != nil {
  1826  		t.Fatal(err)
  1827  	}
  1828  
  1829  	newHead = <-newTxPoolHeadChan2
  1830  	if newHead.Head.Hash() != common.Hash(vm2BlkC.ID()) {
  1831  		t.Fatalf("Expected new block to match")
  1832  	}
  1833  
  1834  	errs = vm2.txPool.AddRemotesSync(txs[5:])
  1835  	for i, err := range errs {
  1836  		if err != nil {
  1837  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1838  		}
  1839  	}
  1840  
  1841  	<-issuer2
  1842  
  1843  	vm2BlkD, err := vm2.BuildBlock(context.Background())
  1844  	if err != nil {
  1845  		t.Fatalf("Failed to build BlkD on VM2: %s", err)
  1846  	}
  1847  
  1848  	// Parse blocks produced in vm2
  1849  	vm1BlkC, err := vm1.ParseBlock(context.Background(), vm2BlkC.Bytes())
  1850  	if err != nil {
  1851  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1852  	}
  1853  
  1854  	vm1BlkD, err := vm1.ParseBlock(context.Background(), vm2BlkD.Bytes())
  1855  	if err != nil {
  1856  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1857  	}
  1858  
  1859  	if err := vm1BlkC.Verify(context.Background()); err != nil {
  1860  		t.Fatalf("Block failed verification on VM1: %s", err)
  1861  	}
  1862  	if err := vm1BlkD.Verify(context.Background()); err != nil {
  1863  		t.Fatalf("Block failed verification on VM1: %s", err)
  1864  	}
  1865  
  1866  	blkBHash := vm1BlkB.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1867  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkBHash {
  1868  		t.Fatalf("expected current block to have hash %s but got %s", blkBHash.Hex(), b.Hash().Hex())
  1869  	}
  1870  
  1871  	if err := vm1BlkC.Accept(context.Background()); err != nil {
  1872  		t.Fatal(err)
  1873  	}
  1874  
  1875  	blkCHash := vm1BlkC.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1876  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkCHash {
  1877  		t.Fatalf("expected current block to have hash %s but got %s", blkCHash.Hex(), b.Hash().Hex())
  1878  	}
  1879  	if err := vm1BlkB.Reject(context.Background()); err != nil {
  1880  		t.Fatal(err)
  1881  	}
  1882  
  1883  	if err := vm1BlkD.Accept(context.Background()); err != nil {
  1884  		t.Fatal(err)
  1885  	}
  1886  	blkDHash := vm1BlkD.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1887  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkDHash {
  1888  		t.Fatalf("expected current block to have hash %s but got %s", blkDHash.Hex(), b.Hash().Hex())
  1889  	}
  1890  }
  1891  
  1892  func TestFutureBlock(t *testing.T) {
  1893  	issuer, vm, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1894  
  1895  	defer func() {
  1896  		if err := vm.Shutdown(context.Background()); err != nil {
  1897  			t.Fatal(err)
  1898  		}
  1899  	}()
  1900  
  1901  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  1902  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  1903  	if err != nil {
  1904  		t.Fatal(err)
  1905  	}
  1906  
  1907  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  1908  	for i, err := range txErrors {
  1909  		if err != nil {
  1910  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  1911  		}
  1912  	}
  1913  
  1914  	<-issuer
  1915  
  1916  	blkA, err := vm.BuildBlock(context.Background())
  1917  	if err != nil {
  1918  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1919  	}
  1920  
  1921  	// Create empty block from blkA
  1922  	internalBlkA := blkA.(*chain.BlockWrapper).Block.(*Block)
  1923  	modifiedHeader := types.CopyHeader(internalBlkA.ethBlock.Header())
  1924  	// Set the VM's clock to the time of the produced block
  1925  	vm.clock.Set(time.Unix(int64(modifiedHeader.Time), 0))
  1926  	// Set the modified time to exceed the allowed future time
  1927  	modifiedTime := modifiedHeader.Time + uint64(maxFutureBlockTime.Seconds()+1)
  1928  	modifiedHeader.Time = modifiedTime
  1929  	modifiedBlock := types.NewBlock(
  1930  		modifiedHeader,
  1931  		internalBlkA.ethBlock.Transactions(),
  1932  		nil,
  1933  		nil,
  1934  		new(trie.Trie),
  1935  	)
  1936  
  1937  	futureBlock := vm.newBlock(modifiedBlock)
  1938  
  1939  	if err := futureBlock.Verify(context.Background()); err == nil {
  1940  		t.Fatal("Future block should have failed verification due to block timestamp too far in the future")
  1941  	} else if !strings.Contains(err.Error(), "block timestamp is too far in the future") {
  1942  		t.Fatalf("Expected error to be block timestamp too far in the future but found %s", err)
  1943  	}
  1944  }
  1945  
  1946  func TestLastAcceptedBlockNumberAllow(t *testing.T) {
  1947  	issuer, vm, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  1948  
  1949  	defer func() {
  1950  		if err := vm.Shutdown(context.Background()); err != nil {
  1951  			t.Fatal(err)
  1952  		}
  1953  	}()
  1954  
  1955  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  1956  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  1957  	if err != nil {
  1958  		t.Fatal(err)
  1959  	}
  1960  
  1961  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  1962  	for i, err := range txErrors {
  1963  		if err != nil {
  1964  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  1965  		}
  1966  	}
  1967  
  1968  	<-issuer
  1969  
  1970  	blk, err := vm.BuildBlock(context.Background())
  1971  	if err != nil {
  1972  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1973  	}
  1974  
  1975  	if err := blk.Verify(context.Background()); err != nil {
  1976  		t.Fatalf("Block failed verification on VM: %s", err)
  1977  	}
  1978  
  1979  	if status := blk.Status(); status != choices.Processing {
  1980  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1981  	}
  1982  
  1983  	if err := vm.SetPreference(context.Background(), blk.ID()); err != nil {
  1984  		t.Fatal(err)
  1985  	}
  1986  
  1987  	blkHeight := blk.Height()
  1988  	blkHash := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1989  
  1990  	vm.blockChain.GetVMConfig().AllowUnfinalizedQueries = true
  1991  
  1992  	ctx := context.Background()
  1993  	b, err := vm.eth.APIBackend.BlockByNumber(ctx, rpc.BlockNumber(blkHeight))
  1994  	if err != nil {
  1995  		t.Fatal(err)
  1996  	}
  1997  	if b.Hash() != blkHash {
  1998  		t.Fatalf("expected block at %d to have hash %s but got %s", blkHeight, blkHash.Hex(), b.Hash().Hex())
  1999  	}
  2000  
  2001  	vm.blockChain.GetVMConfig().AllowUnfinalizedQueries = false
  2002  
  2003  	_, err = vm.eth.APIBackend.BlockByNumber(ctx, rpc.BlockNumber(blkHeight))
  2004  	if !errors.Is(err, eth.ErrUnfinalizedData) {
  2005  		t.Fatalf("expected ErrUnfinalizedData but got %s", err.Error())
  2006  	}
  2007  
  2008  	if err := blk.Accept(context.Background()); err != nil {
  2009  		t.Fatalf("VM failed to accept block: %s", err)
  2010  	}
  2011  
  2012  	if b := vm.blockChain.GetBlockByNumber(blkHeight); b.Hash() != blkHash {
  2013  		t.Fatalf("expected block at %d to have hash %s but got %s", blkHeight, blkHash.Hex(), b.Hash().Hex())
  2014  	}
  2015  }
  2016  
  2017  func TestConfigureLogLevel(t *testing.T) {
  2018  	configTests := []struct {
  2019  		name                     string
  2020  		logConfig                string
  2021  		genesisJSON, upgradeJSON string
  2022  		expectedErr              string
  2023  	}{
  2024  		{
  2025  			name:        "Log level info",
  2026  			logConfig:   "{\"log-level\": \"info\"}",
  2027  			genesisJSON: genesisJSONSubnetEVM,
  2028  			upgradeJSON: "",
  2029  			expectedErr: "",
  2030  		},
  2031  	}
  2032  	for _, test := range configTests {
  2033  		t.Run(test.name, func(t *testing.T) {
  2034  			vm := &VM{}
  2035  			ctx, dbManager, genesisBytes, issuer := setupGenesis(t, test.genesisJSON)
  2036  			appSender := &engCommon.SenderTest{T: t}
  2037  			appSender.CantSendAppGossip = true
  2038  			appSender.SendAppGossipF = func(context.Context, []byte) error { return nil }
  2039  			err := vm.Initialize(
  2040  				context.Background(),
  2041  				ctx,
  2042  				dbManager,
  2043  				genesisBytes,
  2044  				[]byte(""),
  2045  				[]byte(test.logConfig),
  2046  				issuer,
  2047  				[]*engCommon.Fx{},
  2048  				appSender,
  2049  			)
  2050  			if len(test.expectedErr) == 0 && err != nil {
  2051  				t.Fatal(err)
  2052  			} else if len(test.expectedErr) > 0 {
  2053  				if err == nil {
  2054  					t.Fatalf("initialize should have failed due to %s", test.expectedErr)
  2055  				} else if !strings.Contains(err.Error(), test.expectedErr) {
  2056  					t.Fatalf("Expected initialize to fail due to %s, but failed with %s", test.expectedErr, err.Error())
  2057  				}
  2058  			}
  2059  
  2060  			// If the VM was not initialized, do not attept to shut it down
  2061  			if err == nil {
  2062  				shutdownChan := make(chan error, 1)
  2063  				shutdownFunc := func() {
  2064  					err := vm.Shutdown(context.Background())
  2065  					shutdownChan <- err
  2066  				}
  2067  				go shutdownFunc()
  2068  
  2069  				shutdownTimeout := 50 * time.Millisecond
  2070  				ticker := time.NewTicker(shutdownTimeout)
  2071  				select {
  2072  				case <-ticker.C:
  2073  					t.Fatalf("VM shutdown took longer than timeout: %v", shutdownTimeout)
  2074  				case err := <-shutdownChan:
  2075  					if err != nil {
  2076  						t.Fatalf("Shutdown errored: %s", err)
  2077  					}
  2078  				}
  2079  			}
  2080  		})
  2081  	}
  2082  }
  2083  
  2084  // Regression test to ensure we can build blocks if we are starting with the
  2085  // Subnet EVM ruleset in genesis.
  2086  func TestBuildSubnetEVMBlock(t *testing.T) {
  2087  	issuer, vm, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  2088  
  2089  	defer func() {
  2090  		if err := vm.Shutdown(context.Background()); err != nil {
  2091  			t.Fatal(err)
  2092  		}
  2093  	}()
  2094  
  2095  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2096  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2097  
  2098  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], new(big.Int).Mul(firstTxAmount, big.NewInt(4)), 21000, big.NewInt(testMinGasPrice*3), nil)
  2099  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2100  	if err != nil {
  2101  		t.Fatal(err)
  2102  	}
  2103  
  2104  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  2105  	for i, err := range txErrors {
  2106  		if err != nil {
  2107  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  2108  		}
  2109  	}
  2110  
  2111  	blk := issueAndAccept(t, issuer, vm)
  2112  	newHead := <-newTxPoolHeadChan
  2113  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  2114  		t.Fatalf("Expected new block to match")
  2115  	}
  2116  
  2117  	txs := make([]*types.Transaction, 10)
  2118  	for i := 0; i < 10; i++ {
  2119  		tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(testMinGasPrice*3), nil)
  2120  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2121  		if err != nil {
  2122  			t.Fatal(err)
  2123  		}
  2124  		txs[i] = signedTx
  2125  	}
  2126  	errs := vm.txPool.AddRemotes(txs)
  2127  	for i, err := range errs {
  2128  		if err != nil {
  2129  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  2130  		}
  2131  	}
  2132  
  2133  	blk = issueAndAccept(t, issuer, vm)
  2134  	ethBlk := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2135  	if ethBlk.BlockGasCost() == nil || ethBlk.BlockGasCost().Cmp(big.NewInt(100)) < 0 {
  2136  		t.Fatalf("expected blockGasCost to be at least 100 but got %d", ethBlk.BlockGasCost())
  2137  	}
  2138  	minRequiredTip, err := dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header())
  2139  	if err != nil {
  2140  		t.Fatal(err)
  2141  	}
  2142  	if minRequiredTip == nil || minRequiredTip.Cmp(big.NewInt(0.05*params.GWei)) < 0 {
  2143  		t.Fatalf("expected minRequiredTip to be at least 0.05 gwei but got %d", minRequiredTip)
  2144  	}
  2145  
  2146  	if status := blk.Status(); status != choices.Accepted {
  2147  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
  2148  	}
  2149  
  2150  	lastAcceptedID, err := vm.LastAccepted(context.Background())
  2151  	if err != nil {
  2152  		t.Fatal(err)
  2153  	}
  2154  	if lastAcceptedID != blk.ID() {
  2155  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID)
  2156  	}
  2157  
  2158  	// Confirm all txs are present
  2159  	ethBlkTxs := vm.blockChain.GetBlockByNumber(2).Transactions()
  2160  	for i, tx := range txs {
  2161  		if len(ethBlkTxs) <= i {
  2162  			t.Fatalf("missing transactions expected: %d but found: %d", len(txs), len(ethBlkTxs))
  2163  		}
  2164  		if ethBlkTxs[i].Hash() != tx.Hash() {
  2165  			t.Fatalf("expected tx at index %d to have hash: %x but has: %x", i, txs[i].Hash(), tx.Hash())
  2166  		}
  2167  	}
  2168  }
  2169  
  2170  func TestBuildAllowListActivationBlock(t *testing.T) {
  2171  	genesis := &core.Genesis{}
  2172  	if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil {
  2173  		t.Fatal(err)
  2174  	}
  2175  	genesis.Config.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(time.Now().Unix()), testEthAddrs, nil)
  2176  
  2177  	genesisJSON, err := genesis.MarshalJSON()
  2178  	if err != nil {
  2179  		t.Fatal(err)
  2180  	}
  2181  	issuer, vm, _, _ := GenesisVM(t, true, string(genesisJSON), "", "")
  2182  
  2183  	defer func() {
  2184  		if err := vm.Shutdown(context.Background()); err != nil {
  2185  			t.Fatal(err)
  2186  		}
  2187  	}()
  2188  
  2189  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2190  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2191  
  2192  	genesisState, err := vm.blockChain.StateAt(vm.blockChain.Genesis().Root())
  2193  	if err != nil {
  2194  		t.Fatal(err)
  2195  	}
  2196  	role := precompile.GetContractDeployerAllowListStatus(genesisState, testEthAddrs[0])
  2197  	if role != precompile.AllowListNoRole {
  2198  		t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role)
  2199  	}
  2200  
  2201  	// Send basic transaction to construct a simple block and confirm that the precompile state configuration in the worker behaves correctly.
  2202  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], new(big.Int).Mul(firstTxAmount, big.NewInt(4)), 21000, big.NewInt(testMinGasPrice*3), nil)
  2203  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2204  	if err != nil {
  2205  		t.Fatal(err)
  2206  	}
  2207  
  2208  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  2209  	for i, err := range txErrors {
  2210  		if err != nil {
  2211  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  2212  		}
  2213  	}
  2214  
  2215  	blk := issueAndAccept(t, issuer, vm)
  2216  	newHead := <-newTxPoolHeadChan
  2217  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  2218  		t.Fatalf("Expected new block to match")
  2219  	}
  2220  
  2221  	// Verify that the allow list config activation was handled correctly in the first block.
  2222  	blkState, err := vm.blockChain.StateAt(blk.(*chain.BlockWrapper).Block.(*Block).ethBlock.Root())
  2223  	if err != nil {
  2224  		t.Fatal(err)
  2225  	}
  2226  	role = precompile.GetContractDeployerAllowListStatus(blkState, testEthAddrs[0])
  2227  	if role != precompile.AllowListAdmin {
  2228  		t.Fatalf("Expected allow list status to be set to Admin: %s, but found: %s", precompile.AllowListAdmin, role)
  2229  	}
  2230  }
  2231  
  2232  // Test that the tx allow list allows whitelisted transactions and blocks non-whitelisted addresses
  2233  func TestTxAllowListSuccessfulTx(t *testing.T) {
  2234  	// Setup chain params
  2235  	genesis := &core.Genesis{}
  2236  	if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil {
  2237  		t.Fatal(err)
  2238  	}
  2239  	genesis.Config.TxAllowListConfig = precompile.NewTxAllowListConfig(big.NewInt(0), testEthAddrs[0:1], nil)
  2240  	genesisJSON, err := genesis.MarshalJSON()
  2241  	if err != nil {
  2242  		t.Fatal(err)
  2243  	}
  2244  	issuer, vm, _, _ := GenesisVM(t, true, string(genesisJSON), "", "")
  2245  
  2246  	defer func() {
  2247  		if err := vm.Shutdown(context.Background()); err != nil {
  2248  			t.Fatal(err)
  2249  		}
  2250  	}()
  2251  
  2252  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2253  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2254  
  2255  	genesisState, err := vm.blockChain.StateAt(vm.blockChain.Genesis().Root())
  2256  	if err != nil {
  2257  		t.Fatal(err)
  2258  	}
  2259  
  2260  	// Check that address 0 is whitelisted and address 1 is not
  2261  	role := precompile.GetTxAllowListStatus(genesisState, testEthAddrs[0])
  2262  	if role != precompile.AllowListAdmin {
  2263  		t.Fatalf("Expected allow list status to be set to admin: %s, but found: %s", precompile.AllowListAdmin, role)
  2264  	}
  2265  	role = precompile.GetTxAllowListStatus(genesisState, testEthAddrs[1])
  2266  	if role != precompile.AllowListNoRole {
  2267  		t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role)
  2268  	}
  2269  
  2270  	// Submit a successful transaction
  2271  	tx0 := types.NewTransaction(uint64(0), testEthAddrs[0], big.NewInt(1), 21000, big.NewInt(testMinGasPrice), nil)
  2272  	signedTx0, err := types.SignTx(tx0, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2273  	require.NoError(t, err)
  2274  
  2275  	errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx0})
  2276  	if err := errs[0]; err != nil {
  2277  		t.Fatalf("Failed to add tx at index: %s", err)
  2278  	}
  2279  
  2280  	// Submit a rejected transaction, should throw an error
  2281  	tx1 := types.NewTransaction(uint64(0), testEthAddrs[1], big.NewInt(2), 21000, big.NewInt(testMinGasPrice), nil)
  2282  	signedTx1, err := types.SignTx(tx1, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2283  	if err != nil {
  2284  		t.Fatal(err)
  2285  	}
  2286  
  2287  	errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
  2288  	if err := errs[0]; !errors.Is(err, precompile.ErrSenderAddressNotAllowListed) {
  2289  		t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err)
  2290  	}
  2291  
  2292  	blk := issueAndAccept(t, issuer, vm)
  2293  
  2294  	// Verify that the constructed block only has the whitelisted tx
  2295  	block := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2296  
  2297  	txs := block.Transactions()
  2298  
  2299  	if txs.Len() != 1 {
  2300  		t.Fatalf("Expected number of txs to be %d, but found %d", 1, txs.Len())
  2301  	}
  2302  
  2303  	require.Equal(t, signedTx0.Hash(), txs[0].Hash())
  2304  }
  2305  
  2306  // Test that the tx allow list allows whitelisted transactions and blocks non-whitelisted addresses
  2307  // and the allowlist is removed after the precompile is disabled.
  2308  func TestTxAllowListDisablePrecompile(t *testing.T) {
  2309  	// Setup chain params
  2310  	genesis := &core.Genesis{}
  2311  	if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil {
  2312  		t.Fatal(err)
  2313  	}
  2314  	enableAllowListTimestamp := time.Unix(0, 0) // enable at genesis
  2315  	genesis.Config.TxAllowListConfig = precompile.NewTxAllowListConfig(big.NewInt(enableAllowListTimestamp.Unix()), testEthAddrs[0:1], nil)
  2316  	genesisJSON, err := genesis.MarshalJSON()
  2317  	if err != nil {
  2318  		t.Fatal(err)
  2319  	}
  2320  
  2321  	// arbitrary choice ahead of enableAllowListTimestamp
  2322  	disableAllowListTimestamp := enableAllowListTimestamp.Add(10 * time.Hour)
  2323  	// configure a network upgrade to remove the allowlist
  2324  	upgradeConfig := fmt.Sprintf(`
  2325  	{
  2326  		"precompileUpgrades": [
  2327  			{
  2328  				"txAllowListConfig": {
  2329  					"blockTimestamp": %d,
  2330  					"disable": true
  2331  				}
  2332  			}
  2333  		]
  2334  	}
  2335  	`, disableAllowListTimestamp.Unix())
  2336  
  2337  	issuer, vm, _, _ := GenesisVM(t, true, string(genesisJSON), "", upgradeConfig)
  2338  
  2339  	vm.clock.Set(disableAllowListTimestamp) // upgrade takes effect after a block is issued, so we can set vm's clock here.
  2340  
  2341  	defer func() {
  2342  		if err := vm.Shutdown(context.Background()); err != nil {
  2343  			t.Fatal(err)
  2344  		}
  2345  	}()
  2346  
  2347  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2348  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2349  
  2350  	genesisState, err := vm.blockChain.StateAt(vm.blockChain.Genesis().Root())
  2351  	if err != nil {
  2352  		t.Fatal(err)
  2353  	}
  2354  
  2355  	// Check that address 0 is whitelisted and address 1 is not
  2356  	role := precompile.GetTxAllowListStatus(genesisState, testEthAddrs[0])
  2357  	if role != precompile.AllowListAdmin {
  2358  		t.Fatalf("Expected allow list status to be set to admin: %s, but found: %s", precompile.AllowListAdmin, role)
  2359  	}
  2360  	role = precompile.GetTxAllowListStatus(genesisState, testEthAddrs[1])
  2361  	if role != precompile.AllowListNoRole {
  2362  		t.Fatalf("Expected allow list status to be set to no role: %s, but found: %s", precompile.AllowListNoRole, role)
  2363  	}
  2364  
  2365  	// Submit a successful transaction
  2366  	tx0 := types.NewTransaction(uint64(0), testEthAddrs[0], big.NewInt(1), 21000, big.NewInt(testMinGasPrice), nil)
  2367  	signedTx0, err := types.SignTx(tx0, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2368  	require.NoError(t, err)
  2369  
  2370  	errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx0})
  2371  	if err := errs[0]; err != nil {
  2372  		t.Fatalf("Failed to add tx at index: %s", err)
  2373  	}
  2374  
  2375  	// Submit a rejected transaction, should throw an error
  2376  	tx1 := types.NewTransaction(uint64(0), testEthAddrs[1], big.NewInt(2), 21000, big.NewInt(testMinGasPrice), nil)
  2377  	signedTx1, err := types.SignTx(tx1, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2378  	if err != nil {
  2379  		t.Fatal(err)
  2380  	}
  2381  
  2382  	errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
  2383  	if err := errs[0]; !errors.Is(err, precompile.ErrSenderAddressNotAllowListed) {
  2384  		t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err)
  2385  	}
  2386  
  2387  	blk := issueAndAccept(t, issuer, vm)
  2388  
  2389  	// Verify that the constructed block only has the whitelisted tx
  2390  	block := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2391  	txs := block.Transactions()
  2392  	if txs.Len() != 1 {
  2393  		t.Fatalf("Expected number of txs to be %d, but found %d", 1, txs.Len())
  2394  	}
  2395  	require.Equal(t, signedTx0.Hash(), txs[0].Hash())
  2396  
  2397  	// verify the issued block is after the network upgrade
  2398  	require.True(t, block.Timestamp().Cmp(big.NewInt(disableAllowListTimestamp.Unix())) >= 0)
  2399  
  2400  	<-newTxPoolHeadChan // wait for new head in tx pool
  2401  
  2402  	// retry the rejected Tx, which should now succeed
  2403  	errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
  2404  	if err := errs[0]; err != nil {
  2405  		t.Fatalf("Failed to add tx at index: %s", err)
  2406  	}
  2407  
  2408  	vm.clock.Set(vm.clock.Time().Add(2 * time.Second)) // add 2 seconds for gas fee to adjust
  2409  	blk = issueAndAccept(t, issuer, vm)
  2410  
  2411  	// Verify that the constructed block only has the previously rejected tx
  2412  	block = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2413  	txs = block.Transactions()
  2414  	if txs.Len() != 1 {
  2415  		t.Fatalf("Expected number of txs to be %d, but found %d", 1, txs.Len())
  2416  	}
  2417  	require.Equal(t, signedTx1.Hash(), txs[0].Hash())
  2418  }
  2419  
  2420  // Test that the fee manager changes fee configuration
  2421  func TestFeeManagerChangeFee(t *testing.T) {
  2422  	// Setup chain params
  2423  	genesis := &core.Genesis{}
  2424  	if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil {
  2425  		t.Fatal(err)
  2426  	}
  2427  	genesis.Config.FeeManagerConfig = precompile.NewFeeManagerConfig(big.NewInt(0), testEthAddrs[0:1], nil, nil)
  2428  
  2429  	// set a lower fee config now
  2430  	testLowFeeConfig := commontype.FeeConfig{
  2431  		GasLimit:        big.NewInt(8_000_000),
  2432  		TargetBlockRate: 5, // in seconds
  2433  
  2434  		MinBaseFee:               big.NewInt(5_000_000_000),
  2435  		TargetGas:                big.NewInt(18_000_000),
  2436  		BaseFeeChangeDenominator: big.NewInt(3396),
  2437  
  2438  		MinBlockGasCost:  big.NewInt(0),
  2439  		MaxBlockGasCost:  big.NewInt(4_000_000),
  2440  		BlockGasCostStep: big.NewInt(500_000),
  2441  	}
  2442  
  2443  	genesis.Config.FeeConfig = testLowFeeConfig
  2444  	genesisJSON, err := genesis.MarshalJSON()
  2445  	if err != nil {
  2446  		t.Fatal(err)
  2447  	}
  2448  	issuer, vm, _, _ := GenesisVM(t, true, string(genesisJSON), "", "")
  2449  
  2450  	defer func() {
  2451  		if err := vm.Shutdown(context.Background()); err != nil {
  2452  			t.Fatal(err)
  2453  		}
  2454  	}()
  2455  
  2456  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2457  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2458  
  2459  	genesisState, err := vm.blockChain.StateAt(vm.blockChain.Genesis().Root())
  2460  	if err != nil {
  2461  		t.Fatal(err)
  2462  	}
  2463  
  2464  	// Check that address 0 is whitelisted and address 1 is not
  2465  	role := precompile.GetFeeConfigManagerStatus(genesisState, testEthAddrs[0])
  2466  	if role != precompile.AllowListAdmin {
  2467  		t.Fatalf("Expected fee manager list status to be set to admin: %s, but found: %s", precompile.FeeConfigManagerAddress, role)
  2468  	}
  2469  	role = precompile.GetFeeConfigManagerStatus(genesisState, testEthAddrs[1])
  2470  	if role != precompile.AllowListNoRole {
  2471  		t.Fatalf("Expected fee manager list status to be set to no role: %s, but found: %s", precompile.FeeConfigManagerAddress, role)
  2472  	}
  2473  	// Contract is initialized but no preconfig is given, reader should return genesis fee config
  2474  	feeConfig, lastChangedAt, err := vm.blockChain.GetFeeConfigAt(vm.blockChain.Genesis().Header())
  2475  	require.NoError(t, err)
  2476  	require.EqualValues(t, feeConfig, testLowFeeConfig)
  2477  	require.Zero(t, vm.blockChain.CurrentBlock().Number().Cmp(lastChangedAt))
  2478  
  2479  	// set a different fee config now
  2480  	testHighFeeConfig := testLowFeeConfig
  2481  	testHighFeeConfig.MinBaseFee = big.NewInt(28_000_000_000)
  2482  
  2483  	data, err := precompile.PackSetFeeConfig(testHighFeeConfig)
  2484  	require.NoError(t, err)
  2485  
  2486  	tx := types.NewTx(&types.DynamicFeeTx{
  2487  		ChainID:   genesis.Config.ChainID,
  2488  		Nonce:     uint64(0),
  2489  		To:        &precompile.FeeConfigManagerAddress,
  2490  		Gas:       testLowFeeConfig.GasLimit.Uint64(),
  2491  		Value:     common.Big0,
  2492  		GasFeeCap: testLowFeeConfig.MinBaseFee, // give low fee, it should work since we still haven't applied high fees
  2493  		GasTipCap: common.Big0,
  2494  		Data:      data,
  2495  	})
  2496  
  2497  	signedTx, err := types.SignTx(tx, types.LatestSigner(genesis.Config), testKeys[0])
  2498  	if err != nil {
  2499  		t.Fatal(err)
  2500  	}
  2501  
  2502  	errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  2503  	if err := errs[0]; err != nil {
  2504  		t.Fatalf("Failed to add tx at index: %s", err)
  2505  	}
  2506  
  2507  	blk := issueAndAccept(t, issuer, vm)
  2508  	newHead := <-newTxPoolHeadChan
  2509  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  2510  		t.Fatalf("Expected new block to match")
  2511  	}
  2512  
  2513  	block := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2514  
  2515  	// Contract is initialized but no state is given, reader should return genesis fee config
  2516  	feeConfig, lastChangedAt, err = vm.blockChain.GetFeeConfigAt(block.Header())
  2517  	require.NoError(t, err)
  2518  	require.EqualValues(t, testHighFeeConfig, feeConfig)
  2519  	require.EqualValues(t, vm.blockChain.CurrentBlock().Number(), lastChangedAt)
  2520  
  2521  	// should fail, with same params since fee is higher now
  2522  	tx2 := types.NewTx(&types.DynamicFeeTx{
  2523  		ChainID:   genesis.Config.ChainID,
  2524  		Nonce:     uint64(1),
  2525  		To:        &precompile.FeeConfigManagerAddress,
  2526  		Gas:       genesis.Config.FeeConfig.GasLimit.Uint64(),
  2527  		Value:     common.Big0,
  2528  		GasFeeCap: testLowFeeConfig.MinBaseFee, // this is too low for applied config, should fail
  2529  		GasTipCap: common.Big0,
  2530  		Data:      data,
  2531  	})
  2532  
  2533  	signedTx2, err := types.SignTx(tx2, types.LatestSigner(genesis.Config), testKeys[0])
  2534  	if err != nil {
  2535  		t.Fatal(err)
  2536  	}
  2537  
  2538  	err = vm.txPool.AddRemote(signedTx2)
  2539  	require.ErrorIs(t, err, core.ErrUnderpriced)
  2540  }
  2541  
  2542  // Test Allow Fee Recipients is disabled and, etherbase must be blackhole address
  2543  func TestAllowFeeRecipientDisabled(t *testing.T) {
  2544  	genesis := &core.Genesis{}
  2545  	if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil {
  2546  		t.Fatal(err)
  2547  	}
  2548  	genesis.Config.AllowFeeRecipients = false // set to false initially
  2549  	genesisJSON, err := genesis.MarshalJSON()
  2550  	if err != nil {
  2551  		t.Fatal(err)
  2552  	}
  2553  	issuer, vm, _, _ := GenesisVM(t, true, string(genesisJSON), "", "")
  2554  
  2555  	vm.miner.SetEtherbase(common.HexToAddress("0x0123456789")) // set non-blackhole address by force
  2556  	defer func() {
  2557  		if err := vm.Shutdown(context.Background()); err != nil {
  2558  			t.Fatal(err)
  2559  		}
  2560  	}()
  2561  
  2562  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2563  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2564  
  2565  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], new(big.Int).Mul(firstTxAmount, big.NewInt(4)), 21000, big.NewInt(testMinGasPrice*3), nil)
  2566  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2567  	if err != nil {
  2568  		t.Fatal(err)
  2569  	}
  2570  
  2571  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  2572  	for i, err := range txErrors {
  2573  		if err != nil {
  2574  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  2575  		}
  2576  	}
  2577  
  2578  	<-issuer
  2579  
  2580  	blk, err := vm.BuildBlock(context.Background())
  2581  	require.NoError(t, err) // this won't return an error since miner will set the etherbase to blackhole address
  2582  
  2583  	ethBlock := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2584  	require.Equal(t, constants.BlackholeAddr, ethBlock.Coinbase())
  2585  
  2586  	// Create empty block from blk
  2587  	internalBlk := blk.(*chain.BlockWrapper).Block.(*Block)
  2588  	modifiedHeader := types.CopyHeader(internalBlk.ethBlock.Header())
  2589  	modifiedHeader.Coinbase = common.HexToAddress("0x0123456789") // set non-blackhole address by force
  2590  	modifiedBlock := types.NewBlock(
  2591  		modifiedHeader,
  2592  		internalBlk.ethBlock.Transactions(),
  2593  		nil,
  2594  		nil,
  2595  		new(trie.Trie),
  2596  	)
  2597  
  2598  	modifiedBlk := vm.newBlock(modifiedBlock)
  2599  
  2600  	require.ErrorIs(t, modifiedBlk.Verify(context.Background()), vmerrs.ErrInvalidCoinbase)
  2601  }
  2602  
  2603  func TestAllowFeeRecipientEnabled(t *testing.T) {
  2604  	genesis := &core.Genesis{}
  2605  	if err := genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)); err != nil {
  2606  		t.Fatal(err)
  2607  	}
  2608  	genesis.Config.AllowFeeRecipients = true
  2609  	genesisJSON, err := genesis.MarshalJSON()
  2610  	if err != nil {
  2611  		t.Fatal(err)
  2612  	}
  2613  
  2614  	etherBase := common.HexToAddress("0x0123456789")
  2615  	c := Config{}
  2616  	c.SetDefaults()
  2617  	c.FeeRecipient = etherBase.String()
  2618  	configJSON, err := json.Marshal(c)
  2619  	if err != nil {
  2620  		t.Fatal(err)
  2621  	}
  2622  	issuer, vm, _, _ := GenesisVM(t, true, string(genesisJSON), string(configJSON), "")
  2623  
  2624  	defer func() {
  2625  		if err := vm.Shutdown(context.Background()); err != nil {
  2626  			t.Fatal(err)
  2627  		}
  2628  	}()
  2629  
  2630  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2631  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2632  
  2633  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], new(big.Int).Mul(firstTxAmount, big.NewInt(4)), 21000, big.NewInt(testMinGasPrice*3), nil)
  2634  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2635  	if err != nil {
  2636  		t.Fatal(err)
  2637  	}
  2638  
  2639  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  2640  	for i, err := range txErrors {
  2641  		if err != nil {
  2642  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  2643  		}
  2644  	}
  2645  
  2646  	blk := issueAndAccept(t, issuer, vm)
  2647  	newHead := <-newTxPoolHeadChan
  2648  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  2649  		t.Fatalf("Expected new block to match")
  2650  	}
  2651  	ethBlock := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2652  	require.Equal(t, etherBase, ethBlock.Coinbase())
  2653  	// Verify that etherBase has received fees
  2654  	blkState, err := vm.blockChain.StateAt(ethBlock.Root())
  2655  	if err != nil {
  2656  		t.Fatal(err)
  2657  	}
  2658  
  2659  	balance := blkState.GetBalance(etherBase)
  2660  	require.Equal(t, 1, balance.Cmp(common.Big0))
  2661  }
  2662  
  2663  func TestRewardManagerPrecompileSetRewardAddress(t *testing.T) {
  2664  	genesis := &core.Genesis{}
  2665  	require.NoError(t, genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)))
  2666  
  2667  	genesis.Config.RewardManagerConfig = precompile.NewRewardManagerConfig(common.Big0, testEthAddrs[0:1], nil, nil)
  2668  	genesis.Config.AllowFeeRecipients = true // enable this in genesis to test if this is recognized by the reward manager
  2669  	genesisJSON, err := genesis.MarshalJSON()
  2670  	require.NoError(t, err)
  2671  
  2672  	etherBase := common.HexToAddress("0x0123456789") // give custom ether base
  2673  	c := Config{}
  2674  	c.SetDefaults()
  2675  	c.FeeRecipient = etherBase.String()
  2676  	configJSON, err := json.Marshal(c)
  2677  	require.NoError(t, err)
  2678  
  2679  	// arbitrary choice ahead of enableAllowListTimestamp
  2680  	// configure a network upgrade to remove the reward manager
  2681  	disableTime := time.Now().Add(10 * time.Hour)
  2682  
  2683  	// configure a network upgrade to remove the allowlist
  2684  	upgradeConfig := fmt.Sprintf(`
  2685  		{
  2686  			"precompileUpgrades": [
  2687  				{
  2688  					"rewardManagerConfig": {
  2689  						"blockTimestamp": %d,
  2690  						"disable": true
  2691  					}
  2692  				}
  2693  			]
  2694  		}
  2695  		`, disableTime.Unix())
  2696  
  2697  	issuer, vm, _, _ := GenesisVM(t, true, string(genesisJSON), string(configJSON), upgradeConfig)
  2698  
  2699  	defer func() {
  2700  		err := vm.Shutdown(context.Background())
  2701  		require.NoError(t, err)
  2702  	}()
  2703  
  2704  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2705  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2706  
  2707  	testAddr := common.HexToAddress("0x9999991111")
  2708  	data, err := precompile.PackSetRewardAddress(testAddr)
  2709  	require.NoError(t, err)
  2710  
  2711  	gas := 21000 + 240 + precompile.SetRewardAddressGasCost // 21000 for tx, 240 for tx data
  2712  
  2713  	tx := types.NewTransaction(uint64(0), precompile.RewardManagerAddress, big.NewInt(1), gas, big.NewInt(testMinGasPrice), data)
  2714  
  2715  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2716  	require.NoError(t, err)
  2717  
  2718  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  2719  	for _, err := range txErrors {
  2720  		require.NoError(t, err)
  2721  	}
  2722  
  2723  	blk := issueAndAccept(t, issuer, vm)
  2724  	newHead := <-newTxPoolHeadChan
  2725  	require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
  2726  	ethBlock := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2727  	require.Equal(t, etherBase, ethBlock.Coinbase()) // reward address is activated at this block so this is fine
  2728  
  2729  	tx1 := types.NewTransaction(uint64(0), testEthAddrs[0], big.NewInt(2), 21000, big.NewInt(testMinGasPrice*3), nil)
  2730  	signedTx1, err := types.SignTx(tx1, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2731  	require.NoError(t, err)
  2732  
  2733  	txErrors = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
  2734  	for _, err := range txErrors {
  2735  		require.NoError(t, err)
  2736  	}
  2737  
  2738  	blk = issueAndAccept(t, issuer, vm)
  2739  	newHead = <-newTxPoolHeadChan
  2740  	require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
  2741  	ethBlock = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2742  	require.Equal(t, testAddr, ethBlock.Coinbase()) // reward address was activated at previous block
  2743  	// Verify that etherBase has received fees
  2744  	blkState, err := vm.blockChain.StateAt(ethBlock.Root())
  2745  	require.NoError(t, err)
  2746  
  2747  	balance := blkState.GetBalance(testAddr)
  2748  	require.Equal(t, 1, balance.Cmp(common.Big0))
  2749  
  2750  	// Test Case: Disable reward manager
  2751  	// This should revert back to enabling fee recipients
  2752  	previousBalance := blkState.GetBalance(etherBase)
  2753  
  2754  	// issue a new block to trigger the upgrade
  2755  	vm.clock.Set(disableTime) // upgrade takes effect after a block is issued, so we can set vm's clock here.
  2756  	tx2 := types.NewTransaction(uint64(1), testEthAddrs[0], big.NewInt(2), 21000, big.NewInt(testMinGasPrice), nil)
  2757  	signedTx2, err := types.SignTx(tx2, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2758  	require.NoError(t, err)
  2759  
  2760  	txErrors = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx2})
  2761  	for _, err := range txErrors {
  2762  		require.NoError(t, err)
  2763  	}
  2764  
  2765  	blk = issueAndAccept(t, issuer, vm)
  2766  	newHead = <-newTxPoolHeadChan
  2767  	require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
  2768  	ethBlock = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2769  	// Reward manager deactivated at this block, so we expect the parent state
  2770  	// to determine the coinbase for this block before full deactivation in the
  2771  	// next block.
  2772  	require.Equal(t, testAddr, ethBlock.Coinbase())
  2773  	require.True(t, ethBlock.Timestamp().Cmp(big.NewInt(disableTime.Unix())) >= 0)
  2774  
  2775  	vm.clock.Set(vm.clock.Time().Add(3 * time.Hour)) // let time pass to decrease gas price
  2776  	// issue another block to verify that the reward manager is disabled
  2777  	tx2 = types.NewTransaction(uint64(2), testEthAddrs[0], big.NewInt(2), 21000, big.NewInt(testMinGasPrice), nil)
  2778  	signedTx2, err = types.SignTx(tx2, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2779  	require.NoError(t, err)
  2780  
  2781  	txErrors = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx2})
  2782  	for _, err := range txErrors {
  2783  		require.NoError(t, err)
  2784  	}
  2785  
  2786  	blk = issueAndAccept(t, issuer, vm)
  2787  	newHead = <-newTxPoolHeadChan
  2788  	require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
  2789  	ethBlock = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2790  	// reward manager was disabled at previous block
  2791  	// so this block should revert back to enabling fee recipients
  2792  	require.Equal(t, etherBase, ethBlock.Coinbase())
  2793  	require.True(t, ethBlock.Timestamp().Cmp(big.NewInt(disableTime.Unix())) >= 0)
  2794  
  2795  	// Verify that Blackhole has received fees
  2796  	blkState, err = vm.blockChain.StateAt(ethBlock.Root())
  2797  	require.NoError(t, err)
  2798  
  2799  	balance = blkState.GetBalance(etherBase)
  2800  	require.Equal(t, 1, balance.Cmp(previousBalance))
  2801  }
  2802  
  2803  func TestRewardManagerPrecompileAllowFeeRecipients(t *testing.T) {
  2804  	genesis := &core.Genesis{}
  2805  	require.NoError(t, genesis.UnmarshalJSON([]byte(genesisJSONSubnetEVM)))
  2806  
  2807  	genesis.Config.RewardManagerConfig = precompile.NewRewardManagerConfig(common.Big0, testEthAddrs[0:1], nil, nil)
  2808  	genesis.Config.AllowFeeRecipients = false // disable this in genesis
  2809  	genesisJSON, err := genesis.MarshalJSON()
  2810  	require.NoError(t, err)
  2811  	etherBase := common.HexToAddress("0x0123456789") // give custom ether base
  2812  	c := Config{}
  2813  	c.SetDefaults()
  2814  	c.FeeRecipient = etherBase.String()
  2815  	configJSON, err := json.Marshal(c)
  2816  	require.NoError(t, err)
  2817  	// configure a network upgrade to remove the reward manager
  2818  	// arbitrary choice ahead of enableAllowListTimestamp
  2819  	// configure a network upgrade to remove the reward manager
  2820  	disableTime := time.Now().Add(10 * time.Hour)
  2821  
  2822  	// configure a network upgrade to remove the allowlist
  2823  	upgradeConfig := fmt.Sprintf(`
  2824  		{
  2825  			"precompileUpgrades": [
  2826  				{
  2827  					"rewardManagerConfig": {
  2828  						"blockTimestamp": %d,
  2829  						"disable": true
  2830  					}
  2831  				}
  2832  			]
  2833  		}
  2834  		`, disableTime.Unix())
  2835  	issuer, vm, _, _ := GenesisVM(t, true, string(genesisJSON), string(configJSON), upgradeConfig)
  2836  
  2837  	defer func() {
  2838  		require.NoError(t, vm.Shutdown(context.Background()))
  2839  	}()
  2840  
  2841  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2842  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2843  
  2844  	data, err := precompile.PackAllowFeeRecipients()
  2845  	require.NoError(t, err)
  2846  
  2847  	gas := 21000 + 240 + precompile.AllowFeeRecipientsGasCost // 21000 for tx, 240 for tx data
  2848  
  2849  	tx := types.NewTransaction(uint64(0), precompile.RewardManagerAddress, big.NewInt(1), gas, big.NewInt(testMinGasPrice), data)
  2850  
  2851  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2852  	require.NoError(t, err)
  2853  
  2854  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  2855  	for _, err := range txErrors {
  2856  		require.NoError(t, err)
  2857  	}
  2858  
  2859  	blk := issueAndAccept(t, issuer, vm)
  2860  	newHead := <-newTxPoolHeadChan
  2861  	require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
  2862  	ethBlock := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2863  	require.Equal(t, constants.BlackholeAddr, ethBlock.Coinbase()) // reward address is activated at this block so this is fine
  2864  
  2865  	tx1 := types.NewTransaction(uint64(0), testEthAddrs[0], big.NewInt(2), 21000, big.NewInt(testMinGasPrice*3), nil)
  2866  	signedTx1, err := types.SignTx(tx1, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2867  	require.NoError(t, err)
  2868  
  2869  	txErrors = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1})
  2870  	for _, err := range txErrors {
  2871  		require.NoError(t, err)
  2872  	}
  2873  
  2874  	blk = issueAndAccept(t, issuer, vm)
  2875  	newHead = <-newTxPoolHeadChan
  2876  	require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
  2877  	ethBlock = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2878  	require.Equal(t, etherBase, ethBlock.Coinbase()) // reward address was activated at previous block
  2879  	// Verify that etherBase has received fees
  2880  	blkState, err := vm.blockChain.StateAt(ethBlock.Root())
  2881  	require.NoError(t, err)
  2882  
  2883  	balance := blkState.GetBalance(etherBase)
  2884  	require.Equal(t, 1, balance.Cmp(common.Big0))
  2885  
  2886  	// Test Case: Disable reward manager
  2887  	// This should revert back to burning fees
  2888  	previousBalance := blkState.GetBalance(constants.BlackholeAddr)
  2889  
  2890  	vm.clock.Set(disableTime) // upgrade takes effect after a block is issued, so we can set vm's clock here.
  2891  	tx2 := types.NewTransaction(uint64(1), testEthAddrs[0], big.NewInt(2), 21000, big.NewInt(testMinGasPrice), nil)
  2892  	signedTx2, err := types.SignTx(tx2, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2893  	require.NoError(t, err)
  2894  
  2895  	txErrors = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx2})
  2896  	for _, err := range txErrors {
  2897  		require.NoError(t, err)
  2898  	}
  2899  
  2900  	blk = issueAndAccept(t, issuer, vm)
  2901  	newHead = <-newTxPoolHeadChan
  2902  	require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
  2903  	ethBlock = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2904  	require.Equal(t, etherBase, ethBlock.Coinbase()) // reward address was activated at previous block
  2905  	require.True(t, ethBlock.Timestamp().Cmp(big.NewInt(disableTime.Unix())) >= 0)
  2906  
  2907  	vm.clock.Set(vm.clock.Time().Add(3 * time.Hour)) // let time pass so that gas price is reduced
  2908  	tx2 = types.NewTransaction(uint64(2), testEthAddrs[0], big.NewInt(2), 21000, big.NewInt(testMinGasPrice), nil)
  2909  	signedTx2, err = types.SignTx(tx2, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1])
  2910  	require.NoError(t, err)
  2911  
  2912  	txErrors = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx2})
  2913  	for _, err := range txErrors {
  2914  		require.NoError(t, err)
  2915  	}
  2916  
  2917  	blk = issueAndAccept(t, issuer, vm)
  2918  	newHead = <-newTxPoolHeadChan
  2919  	require.Equal(t, newHead.Head.Hash(), common.Hash(blk.ID()))
  2920  	ethBlock = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2921  	require.Equal(t, constants.BlackholeAddr, ethBlock.Coinbase()) // reward address was activated at previous block
  2922  	require.True(t, ethBlock.Timestamp().Cmp(big.NewInt(disableTime.Unix())) >= 0)
  2923  
  2924  	// Verify that Blackhole has received fees
  2925  	blkState, err = vm.blockChain.StateAt(ethBlock.Root())
  2926  	require.NoError(t, err)
  2927  
  2928  	balance = blkState.GetBalance(constants.BlackholeAddr)
  2929  	require.Equal(t, 1, balance.Cmp(previousBalance))
  2930  }
  2931  
  2932  func TestSkipChainConfigCheckCompatible(t *testing.T) {
  2933  	// The most recent network upgrade in Subnet-EVM is SubnetEVM itself, which cannot be disabled for this test since it results in
  2934  	// disabling dynamic fees and causes a panic since some code assumes that this is enabled.
  2935  	// TODO update this test when there is a future network upgrade that can be skipped in the config.
  2936  	t.Skip("no skippable upgrades")
  2937  	// Hack: registering metrics uses global variables, so we need to disable metrics here so that we can initialize the VM twice.
  2938  	metrics.Enabled = false
  2939  	defer func() { metrics.Enabled = true }()
  2940  
  2941  	issuer, vm, dbManager, appSender := GenesisVM(t, true, genesisJSONPreSubnetEVM, "{\"pruning-enabled\":true}", "")
  2942  
  2943  	defer func() {
  2944  		if err := vm.Shutdown(context.Background()); err != nil {
  2945  			t.Fatal(err)
  2946  		}
  2947  	}()
  2948  
  2949  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2950  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2951  
  2952  	key, err := accountKeystore.NewKey(rand.Reader)
  2953  	if err != nil {
  2954  		t.Fatal(err)
  2955  	}
  2956  
  2957  	tx := types.NewTransaction(uint64(0), key.Address, firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  2958  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  2959  	if err != nil {
  2960  		t.Fatal(err)
  2961  	}
  2962  	errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  2963  	for i, err := range errs {
  2964  		if err != nil {
  2965  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  2966  		}
  2967  	}
  2968  
  2969  	blk := issueAndAccept(t, issuer, vm)
  2970  	newHead := <-newTxPoolHeadChan
  2971  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  2972  		t.Fatalf("Expected new block to match")
  2973  	}
  2974  
  2975  	reinitVM := &VM{}
  2976  	// use the block's timestamp instead of 0 since rewind to genesis
  2977  	// is hardcoded to be allowed in core/genesis.go.
  2978  	genesisWithUpgrade := &core.Genesis{}
  2979  	require.NoError(t, json.Unmarshal([]byte(genesisJSONPreSubnetEVM), genesisWithUpgrade))
  2980  	genesisWithUpgrade.Config.SubnetEVMTimestamp = big.NewInt(blk.Timestamp().Unix())
  2981  	genesisWithUpgradeBytes, err := json.Marshal(genesisWithUpgrade)
  2982  	require.NoError(t, err)
  2983  
  2984  	// this will not be allowed
  2985  	err = reinitVM.Initialize(context.Background(), vm.ctx, dbManager, genesisWithUpgradeBytes, []byte{}, []byte{}, issuer, []*engCommon.Fx{}, appSender)
  2986  	require.ErrorContains(t, err, "mismatching SubnetEVM fork block timestamp in database")
  2987  
  2988  	// try again with skip-upgrade-check
  2989  	config := []byte("{\"skip-upgrade-check\": true}")
  2990  	err = reinitVM.Initialize(context.Background(), vm.ctx, dbManager, genesisWithUpgradeBytes, []byte{}, config, issuer, []*engCommon.Fx{}, appSender)
  2991  	require.NoError(t, err)
  2992  	require.NoError(t, reinitVM.Shutdown(context.Background()))
  2993  }
  2994  
  2995  func TestCrossChainMessagestoVM(t *testing.T) {
  2996  	crossChainCodec := message.CrossChainCodec
  2997  	require := require.New(t)
  2998  
  2999  	//  the following is based on this contract:
  3000  	//  contract T {
  3001  	//  	event received(address sender, uint amount, bytes memo);
  3002  	//  	event receivedAddr(address sender);
  3003  	//
  3004  	//  	function receive(bytes calldata memo) external payable returns (string memory res) {
  3005  	//  		emit received(msg.sender, msg.value, memo);
  3006  	//  		emit receivedAddr(msg.sender);
  3007  	//		return "hello world";
  3008  	//  	}
  3009  	//  }
  3010  
  3011  	const abiBin = `0x608060405234801561001057600080fd5b506102a0806100206000396000f3fe60806040526004361061003b576000357c010000000000000000000000000000000000000000000000000000000090048063a69b6ed014610040575b600080fd5b6100b76004803603602081101561005657600080fd5b810190808035906020019064010000000081111561007357600080fd5b82018360208201111561008557600080fd5b803590602001918460018302840111640100000000831117156100a757600080fd5b9091929391929390505050610132565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f75780820151818401526020810190506100dc565b50505050905090810190601f1680156101245780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60607f75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed33348585604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060405180910390a17f46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c833604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a16040805190810160405280600b81526020017f68656c6c6f20776f726c6400000000000000000000000000000000000000000081525090509291505056fea165627a7a72305820ff0c57dad254cfeda48c9cfb47f1353a558bccb4d1bc31da1dae69315772d29e0029`
  3012  	const abiJSON = `[ { "constant": false, "inputs": [ { "name": "memo", "type": "bytes" } ], "name": "receive", "outputs": [ { "name": "res", "type": "string" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "sender", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" }, { "indexed": false, "name": "memo", "type": "bytes" } ], "name": "received", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "sender", "type": "address" } ], "name": "receivedAddr", "type": "event" } ]`
  3013  	parsed, err := abi.JSON(strings.NewReader(abiJSON))
  3014  	require.NoErrorf(err, "could not parse abi: %v")
  3015  
  3016  	calledSendCrossChainAppResponseFn := false
  3017  	issuer, vm, _, appSender := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  3018  
  3019  	defer func() {
  3020  		err := vm.Shutdown(context.Background())
  3021  		require.NoError(err)
  3022  	}()
  3023  
  3024  	appSender.SendCrossChainAppResponseF = func(ctx context.Context, respondingChainID ids.ID, requestID uint32, responseBytes []byte) {
  3025  		calledSendCrossChainAppResponseFn = true
  3026  
  3027  		var response message.EthCallResponse
  3028  		if _, err = crossChainCodec.Unmarshal(responseBytes, &response); err != nil {
  3029  			require.NoErrorf(err, "unexpected error during unmarshal: %w")
  3030  		}
  3031  
  3032  		result := core.ExecutionResult{}
  3033  		err = json.Unmarshal(response.ExecutionResult, &result)
  3034  		require.NoError(err)
  3035  		require.NotNil(result.ReturnData)
  3036  
  3037  		finalResult, err := parsed.Unpack("receive", result.ReturnData)
  3038  		require.NoError(err)
  3039  		require.NotNil(finalResult)
  3040  		require.Equal("hello world", finalResult[0])
  3041  	}
  3042  
  3043  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  3044  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  3045  
  3046  	tx := types.NewTransaction(uint64(0), testEthAddrs[1], firstTxAmount, 21000, big.NewInt(testMinGasPrice), nil)
  3047  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  3048  	require.NoError(err)
  3049  
  3050  	txErrors := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  3051  	for _, err := range txErrors {
  3052  		require.NoError(err)
  3053  	}
  3054  
  3055  	<-issuer
  3056  
  3057  	blk1, err := vm.BuildBlock(context.Background())
  3058  	require.NoError(err)
  3059  
  3060  	err = blk1.Verify(context.Background())
  3061  	require.NoError(err)
  3062  
  3063  	if status := blk1.Status(); status != choices.Processing {
  3064  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  3065  	}
  3066  
  3067  	err = vm.SetPreference(context.Background(), blk1.ID())
  3068  	require.NoError(err)
  3069  
  3070  	err = blk1.Accept(context.Background())
  3071  	require.NoError(err)
  3072  
  3073  	newHead := <-newTxPoolHeadChan
  3074  	if newHead.Head.Hash() != common.Hash(blk1.ID()) {
  3075  		t.Fatalf("Expected new block to match")
  3076  	}
  3077  
  3078  	if status := blk1.Status(); status != choices.Accepted {
  3079  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
  3080  	}
  3081  
  3082  	lastAcceptedID, err := vm.LastAccepted(context.Background())
  3083  	require.NoError(err)
  3084  
  3085  	if lastAcceptedID != blk1.ID() {
  3086  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk1.ID(), lastAcceptedID)
  3087  	}
  3088  
  3089  	contractTx := types.NewContractCreation(1, common.Big0, 200000, big.NewInt(testMinGasPrice), common.FromHex(abiBin))
  3090  	contractSignedTx, err := types.SignTx(contractTx, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0])
  3091  	require.NoError(err)
  3092  
  3093  	errs := vm.txPool.AddRemotesSync([]*types.Transaction{contractSignedTx})
  3094  	for _, err := range errs {
  3095  		require.NoError(err)
  3096  	}
  3097  	testAddr := testEthAddrs[0]
  3098  	contractAddress := crypto.CreateAddress(testAddr, 1)
  3099  
  3100  	<-issuer
  3101  
  3102  	blk2, err := vm.BuildBlock(context.Background())
  3103  	require.NoError(err)
  3104  
  3105  	err = blk2.Verify(context.Background())
  3106  	require.NoError(err)
  3107  
  3108  	if status := blk2.Status(); status != choices.Processing {
  3109  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  3110  	}
  3111  
  3112  	err = vm.SetPreference(context.Background(), blk2.ID())
  3113  	require.NoError(err)
  3114  
  3115  	err = blk2.Accept(context.Background())
  3116  	require.NoError(err)
  3117  
  3118  	newHead = <-newTxPoolHeadChan
  3119  	if newHead.Head.Hash() != common.Hash(blk2.ID()) {
  3120  		t.Fatalf("Expected new block to match")
  3121  	}
  3122  
  3123  	if status := blk2.Status(); status != choices.Accepted {
  3124  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
  3125  	}
  3126  
  3127  	lastAcceptedID, err = vm.LastAccepted(context.Background())
  3128  	require.NoError(err)
  3129  
  3130  	if lastAcceptedID != blk2.ID() {
  3131  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk2.ID(), lastAcceptedID)
  3132  	}
  3133  
  3134  	input, err := parsed.Pack("receive", []byte("X"))
  3135  	require.NoError(err)
  3136  
  3137  	data := hexutil.Bytes(input)
  3138  
  3139  	requestArgs, err := json.Marshal(&ethapi.TransactionArgs{
  3140  		To:   &contractAddress,
  3141  		Data: &data,
  3142  	})
  3143  	require.NoError(err)
  3144  
  3145  	var ethCallRequest message.CrossChainRequest = message.EthCallRequest{
  3146  		RequestArgs: requestArgs,
  3147  	}
  3148  
  3149  	crossChainRequest, err := crossChainCodec.Marshal(message.Version, &ethCallRequest)
  3150  	require.NoError(err)
  3151  
  3152  	requestingChainID := ids.ID(common.BytesToHash([]byte{1, 2, 3, 4, 5}))
  3153  
  3154  	// we need all items in the acceptor queue to be processed before we process a cross chain request
  3155  	vm.blockChain.DrainAcceptorQueue()
  3156  	err = vm.Network.CrossChainAppRequest(context.Background(), requestingChainID, 1, time.Now().Add(60*time.Second), crossChainRequest)
  3157  	require.NoError(err)
  3158  	require.True(calledSendCrossChainAppResponseFn, "sendCrossChainAppResponseFn was not called")
  3159  }
  3160  
  3161  func TestSignatureRequestsToVM(t *testing.T) {
  3162  	_, vm, _, _ := GenesisVM(t, true, genesisJSONSubnetEVM, "", "")
  3163  
  3164  	defer func() {
  3165  		err := vm.Shutdown(context.Background())
  3166  		require.NoError(t, err)
  3167  	}()
  3168  
  3169  	// Generate a SignatureRequest for an unknown message
  3170  	var signatureRequest message.Request = message.SignatureRequest{
  3171  		MessageID: ids.GenerateTestID(),
  3172  	}
  3173  
  3174  	requestBytes, err := message.Codec.Marshal(message.Version, &signatureRequest)
  3175  	require.NoError(t, err)
  3176  
  3177  	// Currently with warp not being initialized we just need to make sure the NoopSignatureRequestHandler does not
  3178  	// panic/crash when sent a SignatureRequest.
  3179  	// TODO: We will need to update the test when warp is initialized to check for expected response.
  3180  	err = vm.Network.AppRequest(context.Background(), ids.GenerateTestNodeID(), 1, time.Now().Add(60*time.Second), requestBytes)
  3181  	require.NoError(t, err)
  3182  }