github.com/MetalBlockchain/subnet-evm@v0.4.9/plugin/evm/vm.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  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  	"sync"
    15  	"time"
    16  
    17  	avalanchegoMetrics "github.com/MetalBlockchain/metalgo/api/metrics"
    18  	"github.com/prometheus/client_golang/prometheus"
    19  
    20  	"github.com/MetalBlockchain/subnet-evm/commontype"
    21  	"github.com/MetalBlockchain/subnet-evm/constants"
    22  	"github.com/MetalBlockchain/subnet-evm/core"
    23  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    24  	"github.com/MetalBlockchain/subnet-evm/core/types"
    25  	"github.com/MetalBlockchain/subnet-evm/eth"
    26  	"github.com/MetalBlockchain/subnet-evm/eth/ethconfig"
    27  	"github.com/MetalBlockchain/subnet-evm/metrics"
    28  	subnetEVMPrometheus "github.com/MetalBlockchain/subnet-evm/metrics/prometheus"
    29  	"github.com/MetalBlockchain/subnet-evm/miner"
    30  	"github.com/MetalBlockchain/subnet-evm/node"
    31  	"github.com/MetalBlockchain/subnet-evm/params"
    32  	"github.com/MetalBlockchain/subnet-evm/peer"
    33  	"github.com/MetalBlockchain/subnet-evm/plugin/evm/message"
    34  	"github.com/MetalBlockchain/subnet-evm/rpc"
    35  	statesyncclient "github.com/MetalBlockchain/subnet-evm/sync/client"
    36  	"github.com/MetalBlockchain/subnet-evm/sync/client/stats"
    37  	"github.com/MetalBlockchain/subnet-evm/trie"
    38  	"github.com/MetalBlockchain/subnet-evm/warp"
    39  
    40  	// Force-load tracer engine to trigger registration
    41  	//
    42  	// We must import this package (not referenced elsewhere) so that the native "callTracer"
    43  	// is added to a map of client-accessible tracers. In geth, this is done
    44  	// inside of cmd/geth.
    45  	_ "github.com/MetalBlockchain/subnet-evm/eth/tracers/native"
    46  
    47  	"github.com/ethereum/go-ethereum/common"
    48  	"github.com/ethereum/go-ethereum/log"
    49  	"github.com/ethereum/go-ethereum/rlp"
    50  
    51  	avalancheRPC "github.com/gorilla/rpc/v2"
    52  
    53  	"github.com/MetalBlockchain/metalgo/codec"
    54  	"github.com/MetalBlockchain/metalgo/database"
    55  	"github.com/MetalBlockchain/metalgo/database/manager"
    56  	"github.com/MetalBlockchain/metalgo/database/prefixdb"
    57  	"github.com/MetalBlockchain/metalgo/database/versiondb"
    58  	"github.com/MetalBlockchain/metalgo/ids"
    59  	"github.com/MetalBlockchain/metalgo/snow"
    60  	"github.com/MetalBlockchain/metalgo/snow/choices"
    61  	"github.com/MetalBlockchain/metalgo/snow/consensus/snowman"
    62  	"github.com/MetalBlockchain/metalgo/snow/engine/snowman/block"
    63  	cjson "github.com/MetalBlockchain/metalgo/utils/json"
    64  	"github.com/MetalBlockchain/metalgo/utils/perms"
    65  	"github.com/MetalBlockchain/metalgo/utils/profiler"
    66  	"github.com/MetalBlockchain/metalgo/utils/timer/mockable"
    67  	"github.com/MetalBlockchain/metalgo/vms/components/chain"
    68  
    69  	commonEng "github.com/MetalBlockchain/metalgo/snow/engine/common"
    70  
    71  	avalancheJSON "github.com/MetalBlockchain/metalgo/utils/json"
    72  )
    73  
    74  var (
    75  	_ block.ChainVM              = &VM{}
    76  	_ block.HeightIndexedChainVM = &VM{}
    77  )
    78  
    79  const (
    80  	// Max time from current time allowed for blocks, before they're considered future blocks
    81  	// and fail verification
    82  	maxFutureBlockTime = 10 * time.Second
    83  
    84  	decidedCacheSize       = 100
    85  	missingCacheSize       = 50
    86  	unverifiedCacheSize    = 50
    87  	warpSignatureCacheSize = 500
    88  
    89  	// Prefixes for metrics gatherers
    90  	ethMetricsPrefix        = "eth"
    91  	chainStateMetricsPrefix = "chain_state"
    92  )
    93  
    94  // Define the API endpoints for the VM
    95  const (
    96  	adminEndpoint  = "/admin"
    97  	ethRPCEndpoint = "/rpc"
    98  	ethWSEndpoint  = "/ws"
    99  )
   100  
   101  var (
   102  	// Set last accepted key to be longer than the keys used to store accepted block IDs.
   103  	lastAcceptedKey = []byte("last_accepted_key")
   104  	acceptedPrefix  = []byte("snowman_accepted")
   105  	metadataPrefix  = []byte("metadata")
   106  	warpPrefix      = []byte("warp")
   107  	ethDBPrefix     = []byte("ethdb")
   108  )
   109  
   110  var (
   111  	errEmptyBlock                 = errors.New("empty block")
   112  	errUnsupportedFXs             = errors.New("unsupported feature extensions")
   113  	errInvalidBlock               = errors.New("invalid block")
   114  	errInvalidNonce               = errors.New("invalid nonce")
   115  	errUnclesUnsupported          = errors.New("uncles unsupported")
   116  	errNilBaseFeeSubnetEVM        = errors.New("nil base fee is invalid after subnetEVM")
   117  	errNilBlockGasCostSubnetEVM   = errors.New("nil blockGasCost is invalid after subnetEVM")
   118  	errSubnetEVMUpgradeNotEnabled = errors.New("SubnetEVM upgrade is not enabled in genesis")
   119  )
   120  
   121  var originalStderr *os.File
   122  
   123  // legacyApiNames maps pre geth v1.10.20 api names to their updated counterparts.
   124  // used in attachEthService for backward configuration compatibility.
   125  var legacyApiNames = map[string]string{
   126  	"internal-public-eth":              "internal-eth",
   127  	"internal-public-blockchain":       "internal-blockchain",
   128  	"internal-public-transaction-pool": "internal-transaction",
   129  	"internal-public-tx-pool":          "internal-tx-pool",
   130  	"internal-public-debug":            "internal-debug",
   131  	"internal-private-debug":           "internal-debug",
   132  	"internal-public-account":          "internal-account",
   133  	"internal-private-personal":        "internal-personal",
   134  
   135  	"public-eth":        "eth",
   136  	"public-eth-filter": "eth-filter",
   137  	"private-admin":     "admin",
   138  	"public-debug":      "debug",
   139  	"private-debug":     "debug",
   140  }
   141  
   142  func init() {
   143  	// Preserve [os.Stderr] prior to the call in plugin/main.go to plugin.Serve(...).
   144  	// Preserving the log level allows us to update the root handler while writing to the original
   145  	// [os.Stderr] that is being piped through to the logger via the rpcchainvm.
   146  	originalStderr = os.Stderr
   147  }
   148  
   149  // VM implements the snowman.ChainVM interface
   150  type VM struct {
   151  	ctx *snow.Context
   152  	// *chain.State helps to implement the VM interface by wrapping blocks
   153  	// with an efficient caching layer.
   154  	*chain.State
   155  
   156  	config Config
   157  
   158  	networkID   uint64
   159  	genesisHash common.Hash
   160  	chainConfig *params.ChainConfig
   161  	ethConfig   ethconfig.Config
   162  
   163  	// pointers to eth constructs
   164  	eth        *eth.Ethereum
   165  	txPool     *core.TxPool
   166  	blockChain *core.BlockChain
   167  	miner      *miner.Miner
   168  
   169  	// [db] is the VM's current database managed by ChainState
   170  	db *versiondb.Database
   171  
   172  	// metadataDB is used to store one off keys.
   173  	metadataDB database.Database
   174  
   175  	// [chaindb] is the database supplied to the Ethereum backend
   176  	chaindb Database
   177  
   178  	// [acceptedBlockDB] is the database to store the last accepted
   179  	// block.
   180  	acceptedBlockDB database.Database
   181  
   182  	// [warpDB] is used to store warp message signatures
   183  	// set to a prefixDB with the prefix [warpPrefix]
   184  	warpDB database.Database
   185  
   186  	toEngine chan<- commonEng.Message
   187  
   188  	syntacticBlockValidator BlockValidator
   189  
   190  	builder *blockBuilder
   191  
   192  	gossiper Gossiper
   193  
   194  	clock mockable.Clock
   195  
   196  	shutdownChan chan struct{}
   197  	shutdownWg   sync.WaitGroup
   198  
   199  	// Continuous Profiler
   200  	profiler profiler.ContinuousProfiler
   201  
   202  	peer.Network
   203  	client       peer.NetworkClient
   204  	networkCodec codec.Manager
   205  
   206  	// Metrics
   207  	multiGatherer avalanchegoMetrics.MultiGatherer
   208  
   209  	bootstrapped bool
   210  
   211  	logger SubnetEVMLogger
   212  	// State sync server and client
   213  	StateSyncServer
   214  	StateSyncClient
   215  
   216  	// Avalanche Warp Messaging backend
   217  	// Used to serve BLS signatures of warp messages over RPC
   218  	warpBackend warp.WarpBackend
   219  }
   220  
   221  /*
   222   ******************************************************************************
   223   ********************************* Snowman API ********************************
   224   ******************************************************************************
   225   */
   226  
   227  // implements SnowmanPlusPlusVM interface
   228  func (vm *VM) GetActivationTime() time.Time {
   229  	return time.Unix(vm.chainConfig.SubnetEVMTimestamp.Int64(), 0)
   230  }
   231  
   232  // Initialize implements the snowman.ChainVM interface
   233  func (vm *VM) Initialize(
   234  	_ context.Context,
   235  	chainCtx *snow.Context,
   236  	dbManager manager.Manager,
   237  	genesisBytes []byte,
   238  	upgradeBytes []byte,
   239  	configBytes []byte,
   240  	toEngine chan<- commonEng.Message,
   241  	fxs []*commonEng.Fx,
   242  	appSender commonEng.AppSender,
   243  ) error {
   244  	vm.config.SetDefaults()
   245  	if len(configBytes) > 0 {
   246  		if err := json.Unmarshal(configBytes, &vm.config); err != nil {
   247  			return fmt.Errorf("failed to unmarshal config %s: %w", string(configBytes), err)
   248  		}
   249  	}
   250  	if err := vm.config.Validate(); err != nil {
   251  		return err
   252  	}
   253  
   254  	vm.ctx = chainCtx
   255  
   256  	// Create logger
   257  	alias, err := vm.ctx.BCLookup.PrimaryAlias(vm.ctx.ChainID)
   258  	if err != nil {
   259  		// fallback to ChainID string instead of erroring
   260  		alias = vm.ctx.ChainID.String()
   261  	}
   262  
   263  	subnetEVMLogger, err := InitLogger(alias, vm.config.LogLevel, vm.config.LogJSONFormat, originalStderr)
   264  	if err != nil {
   265  		return fmt.Errorf("failed to initialize logger due to: %w ", err)
   266  	}
   267  	vm.logger = subnetEVMLogger
   268  
   269  	log.Info("Initializing Subnet EVM VM", "Version", Version, "Config", vm.config)
   270  
   271  	if len(fxs) > 0 {
   272  		return errUnsupportedFXs
   273  	}
   274  
   275  	// Enable debug-level metrics that might impact runtime performance
   276  	metrics.EnabledExpensive = vm.config.MetricsExpensiveEnabled
   277  
   278  	vm.toEngine = toEngine
   279  	vm.shutdownChan = make(chan struct{}, 1)
   280  	baseDB := dbManager.Current().Database
   281  	// Use NewNested rather than New so that the structure of the database
   282  	// remains the same regardless of the provided baseDB type.
   283  	vm.chaindb = Database{prefixdb.NewNested(ethDBPrefix, baseDB)}
   284  	vm.db = versiondb.New(baseDB)
   285  	vm.acceptedBlockDB = prefixdb.New(acceptedPrefix, vm.db)
   286  	vm.metadataDB = prefixdb.New(metadataPrefix, vm.db)
   287  	vm.warpDB = prefixdb.New(warpPrefix, vm.db)
   288  
   289  	if vm.config.InspectDatabase {
   290  		start := time.Now()
   291  		log.Info("Starting database inspection")
   292  		if err := rawdb.InspectDatabase(vm.chaindb, nil, nil); err != nil {
   293  			return err
   294  		}
   295  		log.Info("Completed database inspection", "elapsed", time.Since(start))
   296  	}
   297  
   298  	g := new(core.Genesis)
   299  	if err := json.Unmarshal(genesisBytes, g); err != nil {
   300  		return err
   301  	}
   302  
   303  	if g.Config == nil {
   304  		g.Config = params.SubnetEVMDefaultChainConfig
   305  	}
   306  
   307  	// Load airdrop file if provided
   308  	if vm.config.AirdropFile != "" {
   309  		g.AirdropData, err = os.ReadFile(vm.config.AirdropFile)
   310  		if err != nil {
   311  			return fmt.Errorf("could not read airdrop file '%s': %w", vm.config.AirdropFile, err)
   312  		}
   313  	}
   314  	// Set the Avalanche Context on the ChainConfig
   315  	g.Config.AvalancheContext = params.AvalancheContext{
   316  		SnowCtx: chainCtx,
   317  	}
   318  	vm.syntacticBlockValidator = NewBlockValidator()
   319  
   320  	if g.Config.FeeConfig == commontype.EmptyFeeConfig {
   321  		log.Warn("No fee config given in genesis, setting default fee config", "DefaultFeeConfig", params.DefaultFeeConfig)
   322  		g.Config.FeeConfig = params.DefaultFeeConfig
   323  	}
   324  
   325  	vm.ethConfig = ethconfig.NewDefaultConfig()
   326  	vm.ethConfig.Genesis = g
   327  	vm.ethConfig.NetworkId = g.Config.ChainID.Uint64()
   328  
   329  	// Set minimum price for mining and default gas price oracle value to the min
   330  	// gas price to prevent so transactions and blocks all use the correct fees
   331  	vm.ethConfig.RPCGasCap = vm.config.RPCGasCap
   332  	vm.ethConfig.RPCEVMTimeout = vm.config.APIMaxDuration.Duration
   333  	vm.ethConfig.RPCTxFeeCap = vm.config.RPCTxFeeCap
   334  
   335  	vm.ethConfig.TxPool.Locals = vm.config.PriorityRegossipAddresses
   336  	vm.ethConfig.TxPool.NoLocals = !vm.config.LocalTxsEnabled
   337  	vm.ethConfig.TxPool.Journal = vm.config.TxPoolJournal
   338  	vm.ethConfig.TxPool.Rejournal = vm.config.TxPoolRejournal.Duration
   339  	vm.ethConfig.TxPool.PriceLimit = vm.config.TxPoolPriceLimit
   340  	vm.ethConfig.TxPool.PriceBump = vm.config.TxPoolPriceBump
   341  	vm.ethConfig.TxPool.AccountSlots = vm.config.TxPoolAccountSlots
   342  	vm.ethConfig.TxPool.GlobalSlots = vm.config.TxPoolGlobalSlots
   343  	vm.ethConfig.TxPool.AccountQueue = vm.config.TxPoolAccountQueue
   344  	vm.ethConfig.TxPool.GlobalQueue = vm.config.TxPoolGlobalQueue
   345  
   346  	vm.ethConfig.AllowUnfinalizedQueries = vm.config.AllowUnfinalizedQueries
   347  	vm.ethConfig.AllowUnprotectedTxs = vm.config.AllowUnprotectedTxs
   348  	vm.ethConfig.AllowUnprotectedTxHashes = vm.config.AllowUnprotectedTxHashes
   349  	vm.ethConfig.Preimages = vm.config.Preimages
   350  	vm.ethConfig.Pruning = vm.config.Pruning
   351  	vm.ethConfig.TrieCleanCache = vm.config.TrieCleanCache
   352  	vm.ethConfig.TrieCleanJournal = vm.config.TrieCleanJournal
   353  	vm.ethConfig.TrieCleanRejournal = vm.config.TrieCleanRejournal.Duration
   354  	vm.ethConfig.TrieDirtyCache = vm.config.TrieDirtyCache
   355  	vm.ethConfig.TrieDirtyCommitTarget = vm.config.TrieDirtyCommitTarget
   356  	vm.ethConfig.SnapshotCache = vm.config.SnapshotCache
   357  	vm.ethConfig.AcceptorQueueLimit = vm.config.AcceptorQueueLimit
   358  	vm.ethConfig.PopulateMissingTries = vm.config.PopulateMissingTries
   359  	vm.ethConfig.PopulateMissingTriesParallelism = vm.config.PopulateMissingTriesParallelism
   360  	vm.ethConfig.AllowMissingTries = vm.config.AllowMissingTries
   361  	vm.ethConfig.SnapshotDelayInit = vm.config.StateSyncEnabled
   362  	vm.ethConfig.SnapshotAsync = vm.config.SnapshotAsync
   363  	vm.ethConfig.SnapshotVerify = vm.config.SnapshotVerify
   364  	vm.ethConfig.OfflinePruning = vm.config.OfflinePruning
   365  	vm.ethConfig.OfflinePruningBloomFilterSize = vm.config.OfflinePruningBloomFilterSize
   366  	vm.ethConfig.OfflinePruningDataDirectory = vm.config.OfflinePruningDataDirectory
   367  	vm.ethConfig.CommitInterval = vm.config.CommitInterval
   368  	vm.ethConfig.SkipUpgradeCheck = vm.config.SkipUpgradeCheck
   369  	vm.ethConfig.AcceptedCacheSize = vm.config.AcceptedCacheSize
   370  	vm.ethConfig.TxLookupLimit = vm.config.TxLookupLimit
   371  
   372  	// Create directory for offline pruning
   373  	if len(vm.ethConfig.OfflinePruningDataDirectory) != 0 {
   374  		if err := os.MkdirAll(vm.ethConfig.OfflinePruningDataDirectory, perms.ReadWriteExecute); err != nil {
   375  			log.Error("failed to create offline pruning data directory", "error", err)
   376  			return err
   377  		}
   378  	}
   379  
   380  	// Handle custom fee recipient
   381  	if common.IsHexAddress(vm.config.FeeRecipient) {
   382  		address := common.HexToAddress(vm.config.FeeRecipient)
   383  		log.Info("Setting fee recipient", "address", address)
   384  		vm.ethConfig.Miner.Etherbase = address
   385  	} else {
   386  		log.Warn("Config has not specified any coinbase address. Defaulting to the blackhole address.")
   387  		vm.ethConfig.Miner.Etherbase = constants.BlackholeAddr
   388  	}
   389  
   390  	vm.chainConfig = g.Config
   391  	vm.networkID = vm.ethConfig.NetworkId
   392  
   393  	if !vm.config.SkipSubnetEVMUpgradeCheck {
   394  		// check that subnetEVM upgrade is enabled from genesis before upgradeBytes
   395  		if !vm.chainConfig.IsSubnetEVM(common.Big0) {
   396  			return errSubnetEVMUpgradeNotEnabled
   397  		}
   398  	}
   399  
   400  	// Apply upgradeBytes (if any) by unmarshalling them into [chainConfig.UpgradeConfig].
   401  	// Initializing the chain will verify upgradeBytes are compatible with existing values.
   402  	if len(upgradeBytes) > 0 {
   403  		var upgradeConfig params.UpgradeConfig
   404  		if err := json.Unmarshal(upgradeBytes, &upgradeConfig); err != nil {
   405  			return fmt.Errorf("failed to parse upgrade bytes: %w", err)
   406  		}
   407  		vm.chainConfig.UpgradeConfig = upgradeConfig
   408  	}
   409  
   410  	// create genesisHash after applying upgradeBytes in case
   411  	// upgradeBytes modifies genesis.
   412  	vm.genesisHash = vm.ethConfig.Genesis.ToBlock(nil).Hash()
   413  
   414  	lastAcceptedHash, lastAcceptedHeight, err := vm.readLastAccepted()
   415  	if err != nil {
   416  		return err
   417  	}
   418  	log.Info("reading accepted block db", "lastAcceptedHash", lastAcceptedHash)
   419  
   420  	if err := vm.initializeMetrics(); err != nil {
   421  		return err
   422  	}
   423  
   424  	// initialize peer network
   425  	vm.networkCodec = message.Codec
   426  	vm.Network = peer.NewNetwork(appSender, vm.networkCodec, message.CrossChainCodec, chainCtx.NodeID, vm.config.MaxOutboundActiveRequests, vm.config.MaxOutboundActiveCrossChainRequests)
   427  	vm.client = peer.NewNetworkClient(vm.Network)
   428  
   429  	// initialize warp backend
   430  	vm.warpBackend = warp.NewWarpBackend(vm.ctx, vm.warpDB, warpSignatureCacheSize)
   431  
   432  	if err := vm.initializeChain(lastAcceptedHash, vm.ethConfig); err != nil {
   433  		return err
   434  	}
   435  
   436  	go vm.ctx.Log.RecoverAndPanic(vm.startContinuousProfiler)
   437  
   438  	vm.initializeStateSyncServer()
   439  	return vm.initializeStateSyncClient(lastAcceptedHeight)
   440  }
   441  
   442  func (vm *VM) initializeMetrics() error {
   443  	vm.multiGatherer = avalanchegoMetrics.NewMultiGatherer()
   444  	// If metrics are enabled, register the default metrics regitry
   445  	if metrics.Enabled {
   446  		gatherer := subnetEVMPrometheus.Gatherer(metrics.DefaultRegistry)
   447  		if err := vm.multiGatherer.Register(ethMetricsPrefix, gatherer); err != nil {
   448  			return err
   449  		}
   450  		// Register [multiGatherer] after registerers have been registered to it
   451  		if err := vm.ctx.Metrics.Register(vm.multiGatherer); err != nil {
   452  			return err
   453  		}
   454  	}
   455  	return nil
   456  }
   457  
   458  func (vm *VM) initializeChain(lastAcceptedHash common.Hash, ethConfig ethconfig.Config) error {
   459  	nodecfg := &node.Config{
   460  		SubnetEVMVersion:      Version,
   461  		KeyStoreDir:           vm.config.KeystoreDirectory,
   462  		ExternalSigner:        vm.config.KeystoreExternalSigner,
   463  		InsecureUnlockAllowed: vm.config.KeystoreInsecureUnlockAllowed,
   464  	}
   465  	node, err := node.New(nodecfg)
   466  	if err != nil {
   467  		return err
   468  	}
   469  	vm.eth, err = eth.New(
   470  		node,
   471  		&vm.ethConfig,
   472  		vm.chaindb,
   473  		vm.config.EthBackendSettings(),
   474  		lastAcceptedHash,
   475  		&vm.clock,
   476  	)
   477  	if err != nil {
   478  		return err
   479  	}
   480  	vm.eth.SetEtherbase(ethConfig.Miner.Etherbase)
   481  	vm.txPool = vm.eth.TxPool()
   482  	vm.blockChain = vm.eth.BlockChain()
   483  	vm.miner = vm.eth.Miner()
   484  
   485  	// start goroutines to update the tx pool gas minimum gas price when upgrades go into effect
   486  	vm.handleGasPriceUpdates()
   487  
   488  	vm.eth.Start()
   489  	return vm.initChainState(vm.blockChain.LastAcceptedBlock())
   490  }
   491  
   492  // initializeStateSyncClient initializes the client for performing state sync.
   493  // If state sync is disabled, this function will wipe any ongoing summary from
   494  // disk to ensure that we do not continue syncing from an invalid snapshot.
   495  func (vm *VM) initializeStateSyncClient(lastAcceptedHeight uint64) error {
   496  	// parse nodeIDs from state sync IDs in vm config
   497  	var stateSyncIDs []ids.NodeID
   498  	if vm.config.StateSyncEnabled && len(vm.config.StateSyncIDs) > 0 {
   499  		nodeIDs := strings.Split(vm.config.StateSyncIDs, ",")
   500  		stateSyncIDs = make([]ids.NodeID, len(nodeIDs))
   501  		for i, nodeIDString := range nodeIDs {
   502  			nodeID, err := ids.NodeIDFromString(nodeIDString)
   503  			if err != nil {
   504  				return fmt.Errorf("failed to parse %s as NodeID: %w", nodeIDString, err)
   505  			}
   506  			stateSyncIDs[i] = nodeID
   507  		}
   508  	}
   509  
   510  	vm.StateSyncClient = NewStateSyncClient(&stateSyncClientConfig{
   511  		chain: vm.eth,
   512  		state: vm.State,
   513  		client: statesyncclient.NewClient(
   514  			&statesyncclient.ClientConfig{
   515  				NetworkClient:    vm.client,
   516  				Codec:            vm.networkCodec,
   517  				Stats:            stats.NewClientSyncerStats(),
   518  				StateSyncNodeIDs: stateSyncIDs,
   519  				BlockParser:      vm,
   520  			},
   521  		),
   522  		enabled:            vm.config.StateSyncEnabled,
   523  		skipResume:         vm.config.StateSyncSkipResume,
   524  		stateSyncMinBlocks: vm.config.StateSyncMinBlocks,
   525  		lastAcceptedHeight: lastAcceptedHeight, // TODO clean up how this is passed around
   526  		chaindb:            vm.chaindb,
   527  		metadataDB:         vm.metadataDB,
   528  		acceptedBlockDB:    vm.acceptedBlockDB,
   529  		db:                 vm.db,
   530  		toEngine:           vm.toEngine,
   531  	})
   532  
   533  	// If StateSync is disabled, clear any ongoing summary so that we will not attempt to resume
   534  	// sync using a snapshot that has been modified by the node running normal operations.
   535  	if !vm.config.StateSyncEnabled {
   536  		return vm.StateSyncClient.StateSyncClearOngoingSummary()
   537  	}
   538  
   539  	return nil
   540  }
   541  
   542  // initializeStateSyncServer should be called after [vm.chain] is initialized.
   543  func (vm *VM) initializeStateSyncServer() {
   544  	vm.StateSyncServer = NewStateSyncServer(&stateSyncServerConfig{
   545  		Chain:            vm.blockChain,
   546  		SyncableInterval: vm.config.StateSyncCommitInterval,
   547  	})
   548  
   549  	vm.setAppRequestHandlers()
   550  	vm.setCrossChainAppRequestHandler()
   551  }
   552  
   553  func (vm *VM) initChainState(lastAcceptedBlock *types.Block) error {
   554  	block := vm.newBlock(lastAcceptedBlock)
   555  	block.status = choices.Accepted
   556  
   557  	config := &chain.Config{
   558  		DecidedCacheSize:    decidedCacheSize,
   559  		MissingCacheSize:    missingCacheSize,
   560  		UnverifiedCacheSize: unverifiedCacheSize,
   561  		GetBlockIDAtHeight:  vm.GetBlockIDAtHeight,
   562  		GetBlock:            vm.getBlock,
   563  		UnmarshalBlock:      vm.parseBlock,
   564  		BuildBlock:          vm.buildBlock,
   565  		LastAcceptedBlock:   block,
   566  	}
   567  
   568  	// Register chain state metrics
   569  	chainStateRegisterer := prometheus.NewRegistry()
   570  	state, err := chain.NewMeteredState(chainStateRegisterer, config)
   571  	if err != nil {
   572  		return fmt.Errorf("could not create metered state: %w", err)
   573  	}
   574  	vm.State = state
   575  
   576  	return vm.multiGatherer.Register(chainStateMetricsPrefix, chainStateRegisterer)
   577  }
   578  
   579  func (vm *VM) SetState(_ context.Context, state snow.State) error {
   580  	switch state {
   581  	case snow.StateSyncing:
   582  		vm.bootstrapped = false
   583  		return nil
   584  	case snow.Bootstrapping:
   585  		vm.bootstrapped = false
   586  		if err := vm.StateSyncClient.Error(); err != nil {
   587  			return err
   588  		}
   589  		return nil
   590  	case snow.NormalOp:
   591  		// Initialize gossip handling once we enter normal operation as there is no need to handle mempool gossip before this point.
   592  		vm.initBlockBuilding()
   593  		vm.bootstrapped = true
   594  		return nil
   595  	default:
   596  		return snow.ErrUnknownState
   597  	}
   598  }
   599  
   600  // initBlockBuilding starts goroutines to manage block building
   601  func (vm *VM) initBlockBuilding() {
   602  	// NOTE: gossip network must be initialized first otherwise ETH tx gossip will not work.
   603  	gossipStats := NewGossipStats()
   604  	vm.gossiper = vm.createGossiper(gossipStats)
   605  	vm.builder = vm.NewBlockBuilder(vm.toEngine)
   606  	vm.builder.awaitSubmittedTxs()
   607  	vm.Network.SetGossipHandler(NewGossipHandler(vm, gossipStats))
   608  }
   609  
   610  // setAppRequestHandlers sets the request handlers for the VM to serve state sync
   611  // requests.
   612  func (vm *VM) setAppRequestHandlers() {
   613  	// Create separate EVM TrieDB (read only) for serving leafs requests.
   614  	// We create a separate TrieDB here, so that it has a separate cache from the one
   615  	// used by the node when processing blocks.
   616  	evmTrieDB := trie.NewDatabaseWithConfig(
   617  		vm.chaindb,
   618  		&trie.Config{
   619  			Cache: vm.config.StateSyncServerTrieCache,
   620  		},
   621  	)
   622  
   623  	networkHandler := newNetworkHandler(vm.blockChain, evmTrieDB, vm.networkCodec)
   624  	vm.Network.SetRequestHandler(networkHandler)
   625  }
   626  
   627  // setCrossChainAppRequestHandler sets the request handlers for the VM to serve cross chain
   628  // requests.
   629  func (vm *VM) setCrossChainAppRequestHandler() {
   630  	crossChainRequestHandler := message.NewCrossChainHandler(vm.eth.APIBackend, message.CrossChainCodec)
   631  	vm.Network.SetCrossChainRequestHandler(crossChainRequestHandler)
   632  }
   633  
   634  // Shutdown implements the snowman.ChainVM interface
   635  func (vm *VM) Shutdown(context.Context) error {
   636  	if vm.ctx == nil {
   637  		return nil
   638  	}
   639  	vm.Network.Shutdown()
   640  	if err := vm.StateSyncClient.Shutdown(); err != nil {
   641  		log.Error("error stopping state syncer", "err", err)
   642  	}
   643  	close(vm.shutdownChan)
   644  	vm.eth.Stop()
   645  	vm.shutdownWg.Wait()
   646  	return nil
   647  }
   648  
   649  // buildBlock builds a block to be wrapped by ChainState
   650  func (vm *VM) buildBlock(context.Context) (snowman.Block, error) {
   651  	block, err := vm.miner.GenerateBlock()
   652  	vm.builder.handleGenerateBlock()
   653  	if err != nil {
   654  		return nil, err
   655  	}
   656  
   657  	// Note: the status of block is set by ChainState
   658  	blk := vm.newBlock(block)
   659  
   660  	// Verify is called on a non-wrapped block here, such that this
   661  	// does not add [blk] to the processing blocks map in ChainState.
   662  	//
   663  	// TODO cache verification since Verify() will be called by the
   664  	// consensus engine as well.
   665  	//
   666  	// Note: this is only called when building a new block, so caching
   667  	// verification will only be a significant optimization for nodes
   668  	// that produce a large number of blocks.
   669  	// We call verify without writes here to avoid generating a reference
   670  	// to the blk state root in the triedb when we are going to call verify
   671  	// again from the consensus engine with writes enabled.
   672  	if err := blk.verify(false /*=writes*/); err != nil {
   673  		return nil, fmt.Errorf("block failed verification due to: %w", err)
   674  	}
   675  
   676  	log.Debug(fmt.Sprintf("Built block %s", blk.ID()))
   677  	// Marks the current transactions from the mempool as being successfully issued
   678  	// into a block.
   679  	return blk, nil
   680  }
   681  
   682  // parseBlock parses [b] into a block to be wrapped by ChainState.
   683  func (vm *VM) parseBlock(_ context.Context, b []byte) (snowman.Block, error) {
   684  	ethBlock := new(types.Block)
   685  	if err := rlp.DecodeBytes(b, ethBlock); err != nil {
   686  		return nil, err
   687  	}
   688  
   689  	// Note: the status of block is set by ChainState
   690  	block := vm.newBlock(ethBlock)
   691  	// Performing syntactic verification in ParseBlock allows for
   692  	// short-circuiting bad blocks before they are processed by the VM.
   693  	if err := block.syntacticVerify(); err != nil {
   694  		return nil, fmt.Errorf("syntactic block verification failed: %w", err)
   695  	}
   696  	return block, nil
   697  }
   698  
   699  func (vm *VM) ParseEthBlock(b []byte) (*types.Block, error) {
   700  	block, err := vm.parseBlock(context.TODO(), b)
   701  	if err != nil {
   702  		return nil, err
   703  	}
   704  
   705  	return block.(*Block).ethBlock, nil
   706  }
   707  
   708  // getBlock attempts to retrieve block [id] from the VM to be wrapped
   709  // by ChainState.
   710  func (vm *VM) getBlock(_ context.Context, id ids.ID) (snowman.Block, error) {
   711  	ethBlock := vm.blockChain.GetBlockByHash(common.Hash(id))
   712  	// If [ethBlock] is nil, return [database.ErrNotFound] here
   713  	// so that the miss is considered cacheable.
   714  	if ethBlock == nil {
   715  		return nil, database.ErrNotFound
   716  	}
   717  	// Note: the status of block is set by ChainState
   718  	return vm.newBlock(ethBlock), nil
   719  }
   720  
   721  // SetPreference sets what the current tail of the chain is
   722  func (vm *VM) SetPreference(ctx context.Context, blkID ids.ID) error {
   723  	// Since each internal handler used by [vm.State] always returns a block
   724  	// with non-nil ethBlock value, GetBlockInternal should never return a
   725  	// (*Block) with a nil ethBlock value.
   726  	block, err := vm.GetBlockInternal(ctx, blkID)
   727  	if err != nil {
   728  		return fmt.Errorf("failed to set preference to %s: %w", blkID, err)
   729  	}
   730  
   731  	return vm.blockChain.SetPreference(block.(*Block).ethBlock)
   732  }
   733  
   734  // VerifyHeightIndex always returns a nil error since the index is maintained by
   735  // vm.blockChain.
   736  func (vm *VM) VerifyHeightIndex(context.Context) error {
   737  	return nil
   738  }
   739  
   740  // GetBlockAtHeight implements the HeightIndexedChainVM interface and returns the
   741  // canonical block at [blkHeight].
   742  // If [blkHeight] is less than the height of the last accepted block, this will return
   743  // the block accepted at that height. Otherwise, it may return a blkID that has not yet
   744  // been accepted.
   745  // Note: the engine assumes that if a block is not found at [blkHeight], then
   746  // [database.ErrNotFound] will be returned. This indicates that the VM has state synced
   747  // and does not have all historical blocks available.
   748  func (vm *VM) GetBlockIDAtHeight(_ context.Context, blkHeight uint64) (ids.ID, error) {
   749  	ethBlock := vm.blockChain.GetBlockByNumber(blkHeight)
   750  	if ethBlock == nil {
   751  		return ids.ID{}, database.ErrNotFound
   752  	}
   753  
   754  	return ids.ID(ethBlock.Hash()), nil
   755  }
   756  
   757  func (vm *VM) Version(context.Context) (string, error) {
   758  	return Version, nil
   759  }
   760  
   761  // NewHandler returns a new Handler for a service where:
   762  //   - The handler's functionality is defined by [service]
   763  //     [service] should be a gorilla RPC service (see https://www.gorillatoolkit.org/pkg/rpc/v2)
   764  //   - The name of the service is [name]
   765  //   - The LockOption is the first element of [lockOption]
   766  //     By default the LockOption is WriteLock
   767  //     [lockOption] should have either 0 or 1 elements. Elements beside the first are ignored.
   768  func newHandler(name string, service interface{}, lockOption ...commonEng.LockOption) (*commonEng.HTTPHandler, error) {
   769  	server := avalancheRPC.NewServer()
   770  	server.RegisterCodec(avalancheJSON.NewCodec(), "application/json")
   771  	server.RegisterCodec(avalancheJSON.NewCodec(), "application/json;charset=UTF-8")
   772  	if err := server.RegisterService(service, name); err != nil {
   773  		return nil, err
   774  	}
   775  
   776  	var lock commonEng.LockOption = commonEng.WriteLock
   777  	if len(lockOption) != 0 {
   778  		lock = lockOption[0]
   779  	}
   780  	return &commonEng.HTTPHandler{LockOptions: lock, Handler: server}, nil
   781  }
   782  
   783  // CreateHandlers makes new http handlers that can handle API calls
   784  func (vm *VM) CreateHandlers(context.Context) (map[string]*commonEng.HTTPHandler, error) {
   785  	handler := rpc.NewServer(vm.config.APIMaxDuration.Duration)
   786  	enabledAPIs := vm.config.EthAPIs()
   787  	if err := attachEthService(handler, vm.eth.APIs(), enabledAPIs); err != nil {
   788  		return nil, err
   789  	}
   790  
   791  	primaryAlias, err := vm.ctx.BCLookup.PrimaryAlias(vm.ctx.ChainID)
   792  	if err != nil {
   793  		return nil, fmt.Errorf("failed to get primary alias for chain due to %w", err)
   794  	}
   795  	apis := make(map[string]*commonEng.HTTPHandler)
   796  	if vm.config.AdminAPIEnabled {
   797  		adminAPI, err := newHandler("admin", NewAdminService(vm, os.ExpandEnv(fmt.Sprintf("%s_subnet_evm_performance_%s", vm.config.AdminAPIDir, primaryAlias))))
   798  		if err != nil {
   799  			return nil, fmt.Errorf("failed to register service for admin API due to %w", err)
   800  		}
   801  		apis[adminEndpoint] = adminAPI
   802  		enabledAPIs = append(enabledAPIs, "subnet-evm-admin")
   803  	}
   804  
   805  	if vm.config.SnowmanAPIEnabled {
   806  		if err := handler.RegisterName("snowman", &SnowmanAPI{vm}); err != nil {
   807  			return nil, err
   808  		}
   809  		enabledAPIs = append(enabledAPIs, "snowman")
   810  	}
   811  
   812  	if vm.config.WarpAPIEnabled {
   813  		if err := handler.RegisterName("warp", &warp.WarpAPI{Backend: vm.warpBackend}); err != nil {
   814  			return nil, err
   815  		}
   816  		enabledAPIs = append(enabledAPIs, "warp")
   817  	}
   818  
   819  	log.Info(fmt.Sprintf("Enabled APIs: %s", strings.Join(enabledAPIs, ", ")))
   820  	apis[ethRPCEndpoint] = &commonEng.HTTPHandler{
   821  		LockOptions: commonEng.NoLock,
   822  		Handler:     handler,
   823  	}
   824  	apis[ethWSEndpoint] = &commonEng.HTTPHandler{
   825  		LockOptions: commonEng.NoLock,
   826  		Handler: handler.WebsocketHandlerWithDuration(
   827  			[]string{"*"},
   828  			vm.config.APIMaxDuration.Duration,
   829  			vm.config.WSCPURefillRate.Duration,
   830  			vm.config.WSCPUMaxStored.Duration,
   831  		),
   832  	}
   833  
   834  	return apis, nil
   835  }
   836  
   837  // CreateStaticHandlers makes new http handlers that can handle API calls
   838  func (vm *VM) CreateStaticHandlers(context.Context) (map[string]*commonEng.HTTPHandler, error) {
   839  	server := avalancheRPC.NewServer()
   840  	codec := cjson.NewCodec()
   841  	server.RegisterCodec(codec, "application/json")
   842  	server.RegisterCodec(codec, "application/json;charset=UTF-8")
   843  	serviceName := "subnetevm"
   844  	if err := server.RegisterService(&StaticService{}, serviceName); err != nil {
   845  		return nil, err
   846  	}
   847  
   848  	return map[string]*commonEng.HTTPHandler{
   849  		"/rpc": {LockOptions: commonEng.NoLock, Handler: server},
   850  	}, nil
   851  }
   852  
   853  /*
   854   ******************************************************************************
   855   *********************************** Helpers **********************************
   856   ******************************************************************************
   857   */
   858  
   859  // GetCurrentNonce returns the nonce associated with the address at the
   860  // preferred block
   861  func (vm *VM) GetCurrentNonce(address common.Address) (uint64, error) {
   862  	// Note: current state uses the state of the preferred block.
   863  	state, err := vm.blockChain.State()
   864  	if err != nil {
   865  		return 0, err
   866  	}
   867  	return state.GetNonce(address), nil
   868  }
   869  
   870  func (vm *VM) startContinuousProfiler() {
   871  	// If the profiler directory is empty, return immediately
   872  	// without creating or starting a continuous profiler.
   873  	if vm.config.ContinuousProfilerDir == "" {
   874  		return
   875  	}
   876  	vm.profiler = profiler.NewContinuous(
   877  		filepath.Join(vm.config.ContinuousProfilerDir),
   878  		vm.config.ContinuousProfilerFrequency.Duration,
   879  		vm.config.ContinuousProfilerMaxFiles,
   880  	)
   881  	defer vm.profiler.Shutdown()
   882  
   883  	vm.shutdownWg.Add(1)
   884  	go func() {
   885  		defer vm.shutdownWg.Done()
   886  		log.Info("Dispatching continuous profiler", "dir", vm.config.ContinuousProfilerDir, "freq", vm.config.ContinuousProfilerFrequency, "maxFiles", vm.config.ContinuousProfilerMaxFiles)
   887  		err := vm.profiler.Dispatch()
   888  		if err != nil {
   889  			log.Error("continuous profiler failed", "err", err)
   890  		}
   891  	}()
   892  	// Wait for shutdownChan to be closed
   893  	<-vm.shutdownChan
   894  }
   895  
   896  // readLastAccepted reads the last accepted hash from [acceptedBlockDB] and returns the
   897  // last accepted block hash and height by reading directly from [vm.chaindb] instead of relying
   898  // on [chain].
   899  // Note: assumes chaindb, ethConfig, and genesisHash have been initialized.
   900  func (vm *VM) readLastAccepted() (common.Hash, uint64, error) {
   901  	// Attempt to load last accepted block to determine if it is necessary to
   902  	// initialize state with the genesis block.
   903  	lastAcceptedBytes, lastAcceptedErr := vm.acceptedBlockDB.Get(lastAcceptedKey)
   904  	switch {
   905  	case lastAcceptedErr == database.ErrNotFound:
   906  		// If there is nothing in the database, return the genesis block hash and height
   907  		return vm.genesisHash, 0, nil
   908  	case lastAcceptedErr != nil:
   909  		return common.Hash{}, 0, fmt.Errorf("failed to get last accepted block ID due to: %w", lastAcceptedErr)
   910  	case len(lastAcceptedBytes) != common.HashLength:
   911  		return common.Hash{}, 0, fmt.Errorf("last accepted bytes should have been length %d, but found %d", common.HashLength, len(lastAcceptedBytes))
   912  	default:
   913  		lastAcceptedHash := common.BytesToHash(lastAcceptedBytes)
   914  		height := rawdb.ReadHeaderNumber(vm.chaindb, lastAcceptedHash)
   915  		if height == nil {
   916  			return common.Hash{}, 0, fmt.Errorf("failed to retrieve header number of last accepted block: %s", lastAcceptedHash)
   917  		}
   918  		return lastAcceptedHash, *height, nil
   919  	}
   920  }
   921  
   922  // attachEthService registers the backend RPC services provided by Ethereum
   923  // to the provided handler under their assigned namespaces.
   924  func attachEthService(handler *rpc.Server, apis []rpc.API, names []string) error {
   925  	enabledServicesSet := make(map[string]struct{})
   926  	for _, ns := range names {
   927  		// handle pre geth v1.10.20 api names as aliases for their updated values
   928  		// to allow configurations to be backwards compatible.
   929  		if newName, isLegacy := legacyApiNames[ns]; isLegacy {
   930  			log.Info("deprecated api name referenced in configuration.", "deprecated", ns, "new", newName)
   931  			enabledServicesSet[newName] = struct{}{}
   932  			continue
   933  		}
   934  
   935  		enabledServicesSet[ns] = struct{}{}
   936  	}
   937  
   938  	apiSet := make(map[string]rpc.API)
   939  	for _, api := range apis {
   940  		if existingAPI, exists := apiSet[api.Name]; exists {
   941  			return fmt.Errorf("duplicated API name: %s, namespaces %s and %s", api.Name, api.Namespace, existingAPI.Namespace)
   942  		}
   943  		apiSet[api.Name] = api
   944  	}
   945  
   946  	for name := range enabledServicesSet {
   947  		api, exists := apiSet[name]
   948  		if !exists {
   949  			return fmt.Errorf("API service %s not found", name)
   950  		}
   951  		if err := handler.RegisterName(api.Namespace, api.Service); err != nil {
   952  			return err
   953  		}
   954  	}
   955  
   956  	return nil
   957  }