gitlab.com/flarenetwork/coreth@v0.1.1/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/binary"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"math/big"
    13  	"os"
    14  	"path/filepath"
    15  	"strings"
    16  	"sync"
    17  	"time"
    18  
    19  	"github.com/ava-labs/avalanchego/database/versiondb"
    20  	coreth "gitlab.com/flarenetwork/coreth/chain"
    21  	"gitlab.com/flarenetwork/coreth/consensus/dummy"
    22  	"gitlab.com/flarenetwork/coreth/core"
    23  	"gitlab.com/flarenetwork/coreth/core/state"
    24  	"gitlab.com/flarenetwork/coreth/core/types"
    25  	"gitlab.com/flarenetwork/coreth/eth/ethconfig"
    26  	"gitlab.com/flarenetwork/coreth/node"
    27  	"gitlab.com/flarenetwork/coreth/params"
    28  
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/log"
    31  	"github.com/ethereum/go-ethereum/rlp"
    32  	"gitlab.com/flarenetwork/coreth/rpc"
    33  
    34  	avalancheRPC "github.com/gorilla/rpc/v2"
    35  
    36  	"github.com/ava-labs/avalanchego/cache"
    37  	"github.com/ava-labs/avalanchego/codec"
    38  	"github.com/ava-labs/avalanchego/codec/linearcodec"
    39  	"github.com/ava-labs/avalanchego/database"
    40  	"github.com/ava-labs/avalanchego/database/manager"
    41  	"github.com/ava-labs/avalanchego/database/prefixdb"
    42  	"github.com/ava-labs/avalanchego/ids"
    43  	"github.com/ava-labs/avalanchego/snow"
    44  	"github.com/ava-labs/avalanchego/snow/choices"
    45  	"github.com/ava-labs/avalanchego/snow/consensus/snowman"
    46  	"github.com/ava-labs/avalanchego/snow/engine/snowman/block"
    47  	"github.com/ava-labs/avalanchego/utils/constants"
    48  	"github.com/ava-labs/avalanchego/utils/crypto"
    49  	"github.com/ava-labs/avalanchego/utils/formatting"
    50  	"github.com/ava-labs/avalanchego/utils/logging"
    51  	"github.com/ava-labs/avalanchego/utils/math"
    52  	"github.com/ava-labs/avalanchego/utils/profiler"
    53  	"github.com/ava-labs/avalanchego/utils/timer"
    54  	"github.com/ava-labs/avalanchego/utils/wrappers"
    55  	"github.com/ava-labs/avalanchego/vms/components/avax"
    56  	"github.com/ava-labs/avalanchego/vms/components/chain"
    57  	"github.com/ava-labs/avalanchego/vms/secp256k1fx"
    58  
    59  	commonEng "github.com/ava-labs/avalanchego/snow/engine/common"
    60  	avalancheJSON "github.com/ava-labs/avalanchego/utils/json"
    61  )
    62  
    63  const (
    64  	x2cRateInt64       int64 = 1000000000
    65  	x2cRateMinus1Int64 int64 = x2cRateInt64 - 1
    66  )
    67  
    68  var (
    69  	// x2cRate is the conversion rate between the smallest denomination on the X-Chain
    70  	// 1 nAVAX and the smallest denomination on the C-Chain 1 wei. Where 1 nAVAX = 1 gWei.
    71  	// This is only required for AVAX because the denomination of 1 AVAX is 9 decimal
    72  	// places on the X and P chains, but is 18 decimal places within the EVM.
    73  	x2cRate       = big.NewInt(x2cRateInt64)
    74  	x2cRateMinus1 = big.NewInt(x2cRateMinus1Int64)
    75  
    76  	// GitCommit is set by the build script
    77  	GitCommit string
    78  	// Version is the version of Coreth
    79  	Version string
    80  
    81  	_ block.ChainVM = &VM{}
    82  )
    83  
    84  const (
    85  	minBlockTime = 2 * time.Second
    86  	maxBlockTime = 3 * time.Second
    87  	// Max time from current time allowed for blocks, before they're considered future blocks
    88  	// and fail verification
    89  	maxFutureBlockTime   = 10 * time.Second
    90  	batchSize            = 250
    91  	maxUTXOsToFetch      = 1024
    92  	defaultMempoolSize   = 1024
    93  	codecVersion         = uint16(0)
    94  	secpFactoryCacheSize = 1024
    95  
    96  	decidedCacheSize    = 100
    97  	missingCacheSize    = 50
    98  	unverifiedCacheSize = 50
    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  	ethDBPrefix            = []byte("ethdb")
   106  	atomicTxPrefix         = []byte("atomicTxDB")
   107  	pruneRejectedBlocksKey = []byte("pruned_rejected_blocks")
   108  )
   109  
   110  var (
   111  	errEmptyBlock                 = errors.New("empty block")
   112  	errUnsupportedFXs             = errors.New("unsupported feature extensions")
   113  	errInvalidBlock               = errors.New("invalid block")
   114  	errInvalidAddr                = errors.New("invalid hex address")
   115  	errTooManyAtomicTx            = errors.New("too many pending atomic txs")
   116  	errAssetIDMismatch            = errors.New("asset IDs in the input don't match the utxo")
   117  	errNoImportInputs             = errors.New("tx has no imported inputs")
   118  	errInputsNotSortedUnique      = errors.New("inputs not sorted and unique")
   119  	errPublicKeySignatureMismatch = errors.New("signature doesn't match public key")
   120  	errWrongChainID               = errors.New("tx has wrong chain ID")
   121  	errInsufficientFunds          = errors.New("insufficient funds")
   122  	errNoExportOutputs            = errors.New("tx has no export outputs")
   123  	errOutputsNotSorted           = errors.New("tx outputs not sorted")
   124  	errOutputsNotSortedUnique     = errors.New("outputs not sorted and unique")
   125  	errOverflowExport             = errors.New("overflow when computing export amount + txFee")
   126  	errInvalidNonce               = errors.New("invalid nonce")
   127  	errConflictingAtomicInputs    = errors.New("invalid block due to conflicting atomic inputs")
   128  	errUnclesUnsupported          = errors.New("uncles unsupported")
   129  	errTxHashMismatch             = errors.New("txs hash does not match header")
   130  	errUncleHashMismatch          = errors.New("uncle hash mismatch")
   131  	errRejectedParent             = errors.New("rejected parent")
   132  	errInvalidDifficulty          = errors.New("invalid difficulty")
   133  	errInvalidBlockVersion        = errors.New("invalid block version")
   134  	errInvalidMixDigest           = errors.New("invalid mix digest")
   135  	errInvalidExtDataHash         = errors.New("invalid extra data hash")
   136  	errHeaderExtraDataTooBig      = errors.New("header extra data too big")
   137  	errInsufficientFundsForFee    = errors.New("insufficient AVAX funds to pay transaction fee")
   138  	errNoEVMOutputs               = errors.New("tx has no EVM outputs")
   139  	errNilBaseFeeApricotPhase3    = errors.New("nil base fee is invalid in apricotPhase3")
   140  )
   141  
   142  // buildingBlkStatus denotes the current status of the VM in block production.
   143  type buildingBlkStatus uint8
   144  
   145  const (
   146  	dontBuild buildingBlkStatus = iota
   147  	conditionalBuild
   148  	mayBuild
   149  	building
   150  )
   151  
   152  // Codec does serialization and deserialization
   153  var Codec codec.Manager
   154  
   155  func init() {
   156  	Codec = codec.NewDefaultManager()
   157  	c := linearcodec.NewDefault()
   158  
   159  	errs := wrappers.Errs{}
   160  	errs.Add(
   161  		c.RegisterType(&UnsignedImportTx{}),
   162  		c.RegisterType(&UnsignedExportTx{}),
   163  	)
   164  	c.SkipRegistrations(3)
   165  	errs.Add(
   166  		c.RegisterType(&secp256k1fx.TransferInput{}),
   167  		c.RegisterType(&secp256k1fx.MintOutput{}),
   168  		c.RegisterType(&secp256k1fx.TransferOutput{}),
   169  		c.RegisterType(&secp256k1fx.MintOperation{}),
   170  		c.RegisterType(&secp256k1fx.Credential{}),
   171  		c.RegisterType(&secp256k1fx.Input{}),
   172  		c.RegisterType(&secp256k1fx.OutputOwners{}),
   173  		Codec.RegisterCodec(codecVersion, c),
   174  	)
   175  
   176  	if len(GitCommit) != 0 {
   177  		Version = fmt.Sprintf("%s@%s", Version, GitCommit)
   178  	}
   179  
   180  	if errs.Errored() {
   181  		panic(errs.Err)
   182  	}
   183  }
   184  
   185  // VM implements the snowman.ChainVM interface
   186  type VM struct {
   187  	ctx *snow.Context
   188  	// *chain.State helps to implement the VM interface by wrapping blocks
   189  	// with an efficient caching layer.
   190  	*chain.State
   191  
   192  	config Config
   193  
   194  	chainID     *big.Int
   195  	networkID   uint64
   196  	genesisHash common.Hash
   197  	chain       *coreth.ETHChain
   198  	chainConfig *params.ChainConfig
   199  	// [db] is the VM's current database managed by ChainState
   200  	db *versiondb.Database
   201  	// [chaindb] is the database supplied to the Ethereum backend
   202  	chaindb Database
   203  	// [acceptedBlockDB] is the database to store the last accepted
   204  	// block.
   205  	acceptedBlockDB database.Database
   206  	// [acceptedAtomicTxDB] maintains an index of accepted atomic txs.
   207  	acceptedAtomicTxDB database.Database
   208  
   209  	// A message is sent on this channel when a new block
   210  	// is ready to be build. This notifies the consensus engine.
   211  	notifyBuildBlockChan chan<- commonEng.Message
   212  
   213  	// [buildBlockLock] must be held when accessing [buildStatus]
   214  	buildBlockLock sync.Mutex
   215  	// [buildBlockTimer] is a two stage timer handling block production.
   216  	// Stage1 build a block if the batch size has been reached.
   217  	// Stage2 build a block regardless of the size.
   218  	buildBlockTimer *timer.Timer
   219  	// buildStatus signals the phase of block building the VM is currently in.
   220  	// [dontBuild] indicates there's no need to build a block.
   221  	// [conditionalBuild] indicates build a block if the batch size has been reached.
   222  	// [mayBuild] indicates the VM should proceed to build a block.
   223  	// [building] indicates the VM has sent a request to the engine to build a block.
   224  	buildStatus buildingBlkStatus
   225  
   226  	baseCodec codec.Registry
   227  	codec     codec.Manager
   228  	clock     timer.Clock
   229  	mempool   *Mempool
   230  
   231  	shutdownChan chan struct{}
   232  	shutdownWg   sync.WaitGroup
   233  
   234  	fx          secp256k1fx.Fx
   235  	secpFactory crypto.FactorySECP256K1R
   236  
   237  	// Continuous Profiler
   238  	profiler profiler.ContinuousProfiler
   239  }
   240  
   241  func (vm *VM) Connected(id ids.ShortID) error {
   242  	return nil // noop
   243  }
   244  
   245  func (vm *VM) Disconnected(id ids.ShortID) error {
   246  	return nil // noop
   247  }
   248  
   249  // Codec implements the secp256k1fx interface
   250  func (vm *VM) Codec() codec.Manager { return vm.codec }
   251  
   252  // CodecRegistry implements the secp256k1fx interface
   253  func (vm *VM) CodecRegistry() codec.Registry { return vm.baseCodec }
   254  
   255  // Clock implements the secp256k1fx interface
   256  func (vm *VM) Clock() *timer.Clock { return &vm.clock }
   257  
   258  // Logger implements the secp256k1fx interface
   259  func (vm *VM) Logger() logging.Logger { return vm.ctx.Log }
   260  
   261  /*
   262   ******************************************************************************
   263   ********************************* Snowman API ********************************
   264   ******************************************************************************
   265   */
   266  
   267  // Initialize implements the snowman.ChainVM interface
   268  func (vm *VM) Initialize(
   269  	ctx *snow.Context,
   270  	dbManager manager.Manager,
   271  	genesisBytes []byte,
   272  	upgradeBytes []byte,
   273  	configBytes []byte,
   274  	toEngine chan<- commonEng.Message,
   275  	fxs []*commonEng.Fx,
   276  ) error {
   277  	vm.config.SetDefaults()
   278  	if len(configBytes) > 0 {
   279  		if err := json.Unmarshal(configBytes, &vm.config); err != nil {
   280  			return fmt.Errorf("failed to unmarshal config %s: %w", string(configBytes), err)
   281  		}
   282  	}
   283  	vm.config.EthAPIEnabled = false
   284  	vm.config.NetAPIEnabled = false
   285  	vm.config.Web3APIEnabled = false
   286  	vm.config.DebugAPIEnabled = false
   287  	vm.config.MaxBlocksPerRequest = 1
   288  	web3API := os.Getenv("WEB3_API")
   289  	if web3API == "enabled" {
   290  		vm.config.EthAPIEnabled = true
   291  		vm.config.NetAPIEnabled = true
   292  		vm.config.Web3APIEnabled = true
   293  	} else if web3API == "debug" {
   294  		vm.config.EthAPIEnabled = true
   295  		vm.config.NetAPIEnabled = true
   296  		vm.config.Web3APIEnabled = true
   297  		vm.config.DebugAPIEnabled = true
   298  		vm.config.TxPoolAPIEnabled = true
   299  		vm.config.Pruning = false
   300  		vm.config.MaxBlocksPerRequest = 0
   301  	}
   302  
   303  	if b, err := json.Marshal(vm.config); err == nil {
   304  		log.Info("Initializing Coreth VM", "Version", Version, "Config", string(b))
   305  	} else {
   306  		// Log a warning message since we have already successfully unmarshalled into the struct
   307  		log.Warn("Problem initializing Coreth VM", "Version", Version, "Config", string(b), "err", err)
   308  	}
   309  
   310  	if len(fxs) > 0 {
   311  		return errUnsupportedFXs
   312  	}
   313  
   314  	vm.shutdownChan = make(chan struct{}, 1)
   315  	vm.ctx = ctx
   316  	baseDB := dbManager.Current().Database
   317  	// Use NewNested rather than New so that the structure of the database
   318  	// remains the same regardless of the provided baseDB type.
   319  	vm.chaindb = Database{prefixdb.NewNested(ethDBPrefix, baseDB)}
   320  	vm.db = versiondb.New(baseDB)
   321  	vm.acceptedBlockDB = prefixdb.New(acceptedPrefix, vm.db)
   322  	vm.acceptedAtomicTxDB = prefixdb.New(atomicTxPrefix, vm.db)
   323  	g := new(core.Genesis)
   324  	if err := json.Unmarshal(genesisBytes, g); err != nil {
   325  		return err
   326  	}
   327  
   328  	// Set the chain config for mainnet/fuji chain IDs
   329  	switch {
   330  	case g.Config.ChainID.Cmp(params.AvalancheMainnetChainID) == 0:
   331  		g.Config = params.AvalancheMainnetChainConfig
   332  		phase0BlockValidator.extDataHashes = mainnetExtDataHashes
   333  	case g.Config.ChainID.Cmp(params.AvalancheFujiChainID) == 0:
   334  		g.Config = params.AvalancheFujiChainConfig
   335  		phase0BlockValidator.extDataHashes = fujiExtDataHashes
   336  	case g.Config.ChainID.Cmp(params.AvalancheLocalChainID) == 0:
   337  		g.Config = params.AvalancheLocalChainConfig
   338  	}
   339  
   340  	// Allow ExtDataHashes to be garbage collected as soon as freed from block
   341  	// validator
   342  	fujiExtDataHashes = nil
   343  	mainnetExtDataHashes = nil
   344  
   345  	vm.chainID = g.Config.ChainID
   346  
   347  	ethConfig := ethconfig.NewDefaultConfig()
   348  	ethConfig.Genesis = g
   349  
   350  	// Set minimum price for mining and default gas price oracle value to the min
   351  	// gas price to prevent so transactions and blocks all use the correct fees
   352  	ethConfig.RPCGasCap = vm.config.RPCGasCap
   353  	ethConfig.RPCTxFeeCap = vm.config.RPCTxFeeCap
   354  	ethConfig.TxPool.NoLocals = !vm.config.LocalTxsEnabled
   355  	ethConfig.AllowUnfinalizedQueries = vm.config.AllowUnfinalizedQueries
   356  	ethConfig.Pruning = vm.config.Pruning
   357  	ethConfig.SnapshotAsync = vm.config.SnapshotAsync
   358  	ethConfig.SnapshotVerify = vm.config.SnapshotVerify
   359  
   360  	vm.chainConfig = g.Config
   361  	vm.networkID = g.Config.ChainID.Uint64()
   362  	vm.secpFactory = crypto.FactorySECP256K1R{Cache: cache.LRU{Size: secpFactoryCacheSize}}
   363  
   364  	nodecfg := node.Config{
   365  		CorethVersion:         Version,
   366  		KeyStoreDir:           vm.config.KeystoreDirectory,
   367  		ExternalSigner:        vm.config.KeystoreExternalSigner,
   368  		InsecureUnlockAllowed: vm.config.KeystoreInsecureUnlockAllowed,
   369  	}
   370  
   371  	vm.codec = Codec
   372  	// TODO: read size from settings
   373  	vm.mempool = NewMempool(defaultMempoolSize)
   374  
   375  	// Attempt to load last accepted block to determine if it is necessary to
   376  	// initialize state with the genesis block.
   377  	lastAcceptedBytes, lastAcceptedErr := vm.acceptedBlockDB.Get(lastAcceptedKey)
   378  	var lastAcceptedHash common.Hash
   379  	switch {
   380  	case lastAcceptedErr == database.ErrNotFound:
   381  		// // Set [lastAcceptedHash] to the genesis block hash.
   382  		lastAcceptedHash = ethConfig.Genesis.ToBlock(nil).Hash()
   383  	case lastAcceptedErr != nil:
   384  		return fmt.Errorf("failed to get last accepted block ID due to: %w", lastAcceptedErr)
   385  	case len(lastAcceptedBytes) != common.HashLength:
   386  		return fmt.Errorf("last accepted bytes should have been length %d, but found %d", common.HashLength, len(lastAcceptedBytes))
   387  	default:
   388  		lastAcceptedHash = common.BytesToHash(lastAcceptedBytes)
   389  	}
   390  	ethChain, err := coreth.NewETHChain(&ethConfig, &nodecfg, vm.chaindb, vm.config.EthBackendSettings(), vm.createConsensusCallbacks(), lastAcceptedHash)
   391  	if err != nil {
   392  		return err
   393  	}
   394  	vm.chain = ethChain
   395  	lastAccepted := vm.chain.LastAcceptedBlock()
   396  
   397  	// start goroutines to update the tx pool gas minimum gas price when upgrades go into effect
   398  	vm.handleGasPriceUpdates()
   399  
   400  	vm.notifyBuildBlockChan = toEngine
   401  
   402  	// buildBlockTimer handles passing PendingTxs messages to the consensus engine.
   403  	vm.buildBlockTimer = timer.NewStagedTimer(vm.buildBlockTwoStageTimer)
   404  	vm.buildStatus = dontBuild
   405  	go ctx.Log.RecoverAndPanic(vm.buildBlockTimer.Dispatch)
   406  
   407  	vm.chain.Start()
   408  
   409  	vm.genesisHash = vm.chain.GetGenesisBlock().Hash()
   410  	log.Info(fmt.Sprintf("lastAccepted = %s", lastAccepted.Hash().Hex()))
   411  
   412  	vm.State = chain.NewState(&chain.Config{
   413  		DecidedCacheSize:    decidedCacheSize,
   414  		MissingCacheSize:    missingCacheSize,
   415  		UnverifiedCacheSize: unverifiedCacheSize,
   416  		LastAcceptedBlock: &Block{
   417  			id:       ids.ID(lastAccepted.Hash()),
   418  			ethBlock: lastAccepted,
   419  			vm:       vm,
   420  			status:   choices.Accepted,
   421  		},
   422  		GetBlockIDAtHeight: vm.getBlockIDAtHeight,
   423  		GetBlock:           vm.getBlock,
   424  		UnmarshalBlock:     vm.parseBlock,
   425  		BuildBlock:         vm.buildBlock,
   426  	})
   427  
   428  	vm.shutdownWg.Add(1)
   429  	go vm.ctx.Log.RecoverAndPanic(vm.awaitSubmittedTxs)
   430  
   431  	go vm.ctx.Log.RecoverAndPanic(vm.startContinuousProfiler)
   432  
   433  	// The Codec explicitly registers the types it requires from the secp256k1fx
   434  	// so [vm.baseCodec] is a dummy codec use to fulfill the secp256k1fx VM
   435  	// interface. The fx will register all of its types, which can be safely
   436  	// ignored by the VM's codec.
   437  	vm.baseCodec = linearcodec.NewDefault()
   438  
   439  	// pruneChain removes all rejected blocks stored in the database.
   440  	//
   441  	// TODO: This function can take over 60 minutes to run on mainnet and
   442  	// should be converted to run asynchronously.
   443  	// if err := vm.pruneChain(); err != nil {
   444  	// 	return err
   445  	// }
   446  
   447  	return vm.fx.Initialize(vm)
   448  }
   449  
   450  func (vm *VM) createConsensusCallbacks() *dummy.ConsensusCallbacks {
   451  	return &dummy.ConsensusCallbacks{
   452  		OnFinalizeAndAssemble: vm.onFinalizeAndAssemble,
   453  		OnExtraStateChange:    vm.onExtraStateChange,
   454  	}
   455  }
   456  
   457  func (vm *VM) onFinalizeAndAssemble(header *types.Header, state *state.StateDB, txs []*types.Transaction) ([]byte, error) {
   458  	snapshot := state.Snapshot()
   459  	for {
   460  		tx, exists := vm.mempool.NextTx()
   461  		if !exists {
   462  			break
   463  		}
   464  		rules := vm.chainConfig.AvalancheRules(header.Number, new(big.Int).SetUint64(header.Time))
   465  		if err := vm.verifyTx(tx, header.ParentHash, header.BaseFee, state, rules); err != nil {
   466  			// Discard the transaction from the mempool on failed verification.
   467  			vm.mempool.DiscardCurrentTx()
   468  			state.RevertToSnapshot(snapshot)
   469  			continue
   470  		}
   471  
   472  		atomicTxBytes, err := vm.codec.Marshal(codecVersion, tx)
   473  		if err != nil {
   474  			// Discard the transaction from the mempool and error if the transaction
   475  			// cannot be marshalled. This should never happen.
   476  			vm.mempool.DiscardCurrentTx()
   477  			return nil, fmt.Errorf("failed to marshal atomic transaction %s due to %w", tx.ID(), err)
   478  		}
   479  		return atomicTxBytes, nil
   480  	}
   481  
   482  	if len(txs) == 0 {
   483  		// this could happen due to the async logic of geth tx pool
   484  		return nil, errEmptyBlock
   485  	}
   486  
   487  	return nil, nil
   488  }
   489  
   490  func (vm *VM) onExtraStateChange(block *types.Block, state *state.StateDB) error {
   491  	tx, err := vm.extractAtomicTx(block)
   492  	if err != nil {
   493  		return err
   494  	}
   495  	if tx == nil {
   496  		return nil
   497  	}
   498  	return tx.UnsignedAtomicTx.EVMStateTransfer(vm.ctx, state)
   499  }
   500  
   501  func (vm *VM) pruneChain() error {
   502  	if !vm.config.Pruning {
   503  		return nil
   504  	}
   505  	pruned, err := vm.db.Has(pruneRejectedBlocksKey)
   506  	if err != nil {
   507  		return fmt.Errorf("failed to check if the VM has pruned rejected blocks: %w", err)
   508  	}
   509  	if pruned {
   510  		return nil
   511  	}
   512  
   513  	lastAcceptedHeight := vm.LastAcceptedBlock().Height()
   514  	if err := vm.chain.RemoveRejectedBlocks(0, lastAcceptedHeight); err != nil {
   515  		return err
   516  	}
   517  	heightBytes := make([]byte, 8)
   518  	binary.PutUvarint(heightBytes, lastAcceptedHeight)
   519  	if err := vm.db.Put(pruneRejectedBlocksKey, heightBytes); err != nil {
   520  		return err
   521  	}
   522  
   523  	return vm.db.Commit()
   524  }
   525  
   526  // Bootstrapping notifies this VM that the consensus engine is performing
   527  // bootstrapping
   528  func (vm *VM) Bootstrapping() error { return vm.fx.Bootstrapping() }
   529  
   530  // Bootstrapped notifies this VM that the consensus engine has finished
   531  // bootstrapping
   532  func (vm *VM) Bootstrapped() error {
   533  	vm.ctx.Bootstrapped()
   534  	return vm.fx.Bootstrapped()
   535  }
   536  
   537  // Shutdown implements the snowman.ChainVM interface
   538  func (vm *VM) Shutdown() error {
   539  	if vm.ctx == nil {
   540  		return nil
   541  	}
   542  
   543  	vm.buildBlockTimer.Stop()
   544  	close(vm.shutdownChan)
   545  	vm.chain.Stop()
   546  	vm.shutdownWg.Wait()
   547  	return nil
   548  }
   549  
   550  // buildBlock builds a block to be wrapped by ChainState
   551  func (vm *VM) buildBlock() (snowman.Block, error) {
   552  	block, err := vm.chain.GenerateBlock()
   553  	// Set the buildStatus before calling Cancel or Issue on
   554  	// the mempool and after generating the block.
   555  	// This prevents [needToBuild] from returning true when the
   556  	// produced block will change whether or not we need to produce
   557  	// another block and also ensures that when the mempool adds a
   558  	// new item to Pending it will be handled appropriately by [signalTxsReady]
   559  	vm.buildBlockLock.Lock()
   560  	if vm.needToBuild() {
   561  		vm.buildStatus = conditionalBuild
   562  		vm.buildBlockTimer.SetTimeoutIn(minBlockTime)
   563  	} else {
   564  		vm.buildStatus = dontBuild
   565  	}
   566  	vm.buildBlockLock.Unlock()
   567  
   568  	if err != nil {
   569  		vm.mempool.CancelCurrentTx()
   570  		return nil, err
   571  	}
   572  
   573  	// Note: the status of block is set by ChainState
   574  	blk := &Block{
   575  		id:       ids.ID(block.Hash()),
   576  		ethBlock: block,
   577  		vm:       vm,
   578  	}
   579  
   580  	// Verify is called on a non-wrapped block here, such that this
   581  	// does not add [blk] to the processing blocks map in ChainState.
   582  	// TODO cache verification since Verify() will be called by the
   583  	// consensus engine as well.
   584  	// Note: this is only called when building a new block, so caching
   585  	// verification will only be a significant optimization for nodes
   586  	// that produce a large number of blocks.
   587  	// We call verify without writes here to avoid generating a reference
   588  	// to the blk state root in the triedb when we are going to call verify
   589  	// again from the consensus engine with writes enabled.
   590  	if err := blk.verify(false); err != nil {
   591  		vm.mempool.CancelCurrentTx()
   592  		return nil, fmt.Errorf("block failed verification due to: %w", err)
   593  	}
   594  
   595  	log.Debug(fmt.Sprintf("Built block %s", blk.ID()))
   596  	// Marks the current tx from the mempool as being successfully issued
   597  	// into a block.
   598  	vm.mempool.IssueCurrentTx()
   599  	return blk, nil
   600  }
   601  
   602  // parseBlock parses [b] into a block to be wrapped by ChainState.
   603  func (vm *VM) parseBlock(b []byte) (snowman.Block, error) {
   604  	ethBlock := new(types.Block)
   605  	if err := rlp.DecodeBytes(b, ethBlock); err != nil {
   606  		return nil, err
   607  	}
   608  	// Note: the status of block is set by ChainState
   609  	block := &Block{
   610  		id:       ids.ID(ethBlock.Hash()),
   611  		ethBlock: ethBlock,
   612  		vm:       vm,
   613  	}
   614  	// Performing syntactic verification in ParseBlock allows for
   615  	// short-circuiting bad blocks before they are processed by the VM.
   616  	if _, err := block.syntacticVerify(); err != nil {
   617  		return nil, fmt.Errorf("syntactic block verification failed: %w", err)
   618  	}
   619  	return block, nil
   620  }
   621  
   622  // getBlock attempts to retrieve block [id] from the VM to be wrapped
   623  // by ChainState.
   624  func (vm *VM) getBlock(id ids.ID) (snowman.Block, error) {
   625  	ethBlock := vm.chain.GetBlockByHash(common.Hash(id))
   626  	// If [ethBlock] is nil, return [database.ErrNotFound] here
   627  	// so that the miss is considered cacheable.
   628  	if ethBlock == nil {
   629  		return nil, database.ErrNotFound
   630  	}
   631  	// Note: the status of block is set by ChainState
   632  	blk := &Block{
   633  		id:       ids.ID(ethBlock.Hash()),
   634  		ethBlock: ethBlock,
   635  		vm:       vm,
   636  	}
   637  	return blk, nil
   638  }
   639  
   640  // SetPreference sets what the current tail of the chain is
   641  func (vm *VM) SetPreference(blkID ids.ID) error {
   642  	// Since each internal handler used by [vm.State] always returns a block
   643  	// with non-nil ethBlock value, GetBlockInternal should never return a
   644  	// (*Block) with a nil ethBlock value.
   645  	block, err := vm.GetBlockInternal(blkID)
   646  	if err != nil {
   647  		return fmt.Errorf("failed to set preference to %s: %w", blkID, err)
   648  	}
   649  
   650  	return vm.chain.SetPreference(block.(*Block).ethBlock)
   651  }
   652  
   653  // getBlockIDAtHeight retrieves the blkID of the canonical block at [blkHeight]
   654  // if [blkHeight] is less than the height of the last accepted block, this will return
   655  // a canonical block. Otherwise, it may return a blkID that has not yet been accepted.
   656  func (vm *VM) getBlockIDAtHeight(blkHeight uint64) (ids.ID, error) {
   657  	ethBlock := vm.chain.GetBlockByNumber(blkHeight)
   658  	if ethBlock == nil {
   659  		return ids.ID{}, fmt.Errorf("could not find block at height: %d", blkHeight)
   660  	}
   661  
   662  	return ids.ID(ethBlock.Hash()), nil
   663  }
   664  
   665  func (vm *VM) Version() (string, error) {
   666  	return Version, nil
   667  }
   668  
   669  // NewHandler returns a new Handler for a service where:
   670  //   * The handler's functionality is defined by [service]
   671  //     [service] should be a gorilla RPC service (see https://www.gorillatoolkit.org/pkg/rpc/v2)
   672  //   * The name of the service is [name]
   673  //   * The LockOption is the first element of [lockOption]
   674  //     By default the LockOption is WriteLock
   675  //     [lockOption] should have either 0 or 1 elements. Elements beside the first are ignored.
   676  func newHandler(name string, service interface{}, lockOption ...commonEng.LockOption) (*commonEng.HTTPHandler, error) {
   677  	server := avalancheRPC.NewServer()
   678  	server.RegisterCodec(avalancheJSON.NewCodec(), "application/json")
   679  	server.RegisterCodec(avalancheJSON.NewCodec(), "application/json;charset=UTF-8")
   680  	if err := server.RegisterService(service, name); err != nil {
   681  		return nil, err
   682  	}
   683  
   684  	var lock commonEng.LockOption = commonEng.WriteLock
   685  	if len(lockOption) != 0 {
   686  		lock = lockOption[0]
   687  	}
   688  	return &commonEng.HTTPHandler{LockOptions: lock, Handler: server}, nil
   689  }
   690  
   691  // CreateHandlers makes new http handlers that can handle API calls
   692  func (vm *VM) CreateHandlers() (map[string]*commonEng.HTTPHandler, error) {
   693  	handler := vm.chain.NewRPCHandler(vm.config.APIMaxDuration.Duration)
   694  	enabledAPIs := vm.config.EthAPIs()
   695  	vm.chain.AttachEthService(handler, enabledAPIs)
   696  
   697  	errs := wrappers.Errs{}
   698  	if vm.config.SnowmanAPIEnabled {
   699  		errs.Add(handler.RegisterName("snowman", &SnowmanAPI{vm}))
   700  		enabledAPIs = append(enabledAPIs, "snowman")
   701  	}
   702  	if vm.config.CorethAdminAPIEnabled {
   703  		primaryAlias, err := vm.ctx.BCLookup.PrimaryAlias(vm.ctx.ChainID)
   704  		if err != nil {
   705  			return nil, fmt.Errorf("failed to get primary alias for chain due to %w", err)
   706  		}
   707  		errs.Add(handler.RegisterName("performance", NewPerformanceService(fmt.Sprintf("coreth_performance_%s", primaryAlias))))
   708  		enabledAPIs = append(enabledAPIs, "coreth-admin")
   709  	}
   710  	if vm.config.NetAPIEnabled {
   711  		errs.Add(handler.RegisterName("net", &NetAPI{vm}))
   712  		enabledAPIs = append(enabledAPIs, "net")
   713  	}
   714  	if vm.config.Web3APIEnabled {
   715  		errs.Add(handler.RegisterName("web3", &Web3API{}))
   716  		enabledAPIs = append(enabledAPIs, "web3")
   717  	}
   718  	if errs.Errored() {
   719  		return nil, errs.Err
   720  	}
   721  
   722  	avaxAPI, err := newHandler("avax", &AvaxAPI{vm})
   723  	if err != nil {
   724  		return nil, fmt.Errorf("failed to register service for AVAX API due to %w", err)
   725  	}
   726  
   727  	log.Info(fmt.Sprintf("Enabled APIs: %s", strings.Join(enabledAPIs, ", ")))
   728  
   729  	return map[string]*commonEng.HTTPHandler{
   730  		"/rpc":  {LockOptions: commonEng.NoLock, Handler: handler},
   731  		"/avax": avaxAPI,
   732  		"/ws":   {LockOptions: commonEng.NoLock, Handler: handler.WebsocketHandlerWithDuration([]string{"*"}, vm.config.APIMaxDuration.Duration)},
   733  	}, nil
   734  }
   735  
   736  // CreateStaticHandlers makes new http handlers that can handle API calls
   737  func (vm *VM) CreateStaticHandlers() (map[string]*commonEng.HTTPHandler, error) {
   738  	handler := rpc.NewServer(0)
   739  	if err := handler.RegisterName("static", &StaticService{}); err != nil {
   740  		return nil, err
   741  	}
   742  
   743  	return map[string]*commonEng.HTTPHandler{
   744  		"/rpc": {LockOptions: commonEng.NoLock, Handler: handler},
   745  		"/ws":  {LockOptions: commonEng.NoLock, Handler: handler.WebsocketHandler([]string{"*"})},
   746  	}, nil
   747  }
   748  
   749  /*
   750   ******************************************************************************
   751   *********************************** Helpers **********************************
   752   ******************************************************************************
   753   */
   754  // extractAtomicTx returns the atomic transaction in [block] if
   755  // one exists.
   756  func (vm *VM) extractAtomicTx(block *types.Block) (*Tx, error) {
   757  	extdata := block.ExtData()
   758  	if len(extdata) == 0 {
   759  		return nil, nil
   760  	}
   761  	atx := new(Tx)
   762  	if _, err := vm.codec.Unmarshal(extdata, atx); err != nil {
   763  		return nil, fmt.Errorf("failed to unmarshal atomic tx due to %w", err)
   764  	}
   765  	if err := atx.Sign(vm.codec, nil); err != nil {
   766  		return nil, fmt.Errorf("failed to initialize atomic tx in block %s", block.Hash().Hex())
   767  	}
   768  
   769  	return atx, nil
   770  }
   771  
   772  func (vm *VM) conflicts(inputs ids.Set, ancestor *Block) error {
   773  	for ancestor.Status() != choices.Accepted {
   774  		atx, err := vm.extractAtomicTx(ancestor.ethBlock)
   775  		if err != nil {
   776  			return fmt.Errorf("problem parsing atomic tx of ancestor block %s: %w", ancestor.ID(), err)
   777  		}
   778  		// If the ancestor isn't an atomic block, it can't conflict with
   779  		// the import tx.
   780  		if atx != nil {
   781  			ancestorInputs := atx.UnsignedAtomicTx.InputUTXOs()
   782  			if inputs.Overlaps(ancestorInputs) {
   783  				return errConflictingAtomicInputs
   784  			}
   785  		}
   786  
   787  		// Move up the chain.
   788  		nextAncestorID := ancestor.Parent()
   789  		// If the ancestor is unknown, then the parent failed
   790  		// verification when it was called.
   791  		// If the ancestor is rejected, then this block shouldn't be
   792  		// inserted into the canonical chain because the parent is
   793  		// will be missing.
   794  		// If the ancestor is processing, then the block may have
   795  		// been verified.
   796  		nextAncestorIntf, err := vm.GetBlockInternal(nextAncestorID)
   797  		if err != nil {
   798  			return errRejectedParent
   799  		}
   800  
   801  		if blkStatus := nextAncestorIntf.Status(); blkStatus == choices.Unknown || blkStatus == choices.Rejected {
   802  			return errRejectedParent
   803  		}
   804  		nextAncestor, ok := nextAncestorIntf.(*Block)
   805  		if !ok {
   806  			return fmt.Errorf("ancestor block %s had unexpected type %T", nextAncestor.ID(), nextAncestorIntf)
   807  		}
   808  		ancestor = nextAncestor
   809  	}
   810  
   811  	return nil
   812  }
   813  
   814  // getAcceptedAtomicTx attempts to get [txID] from the database.
   815  func (vm *VM) getAcceptedAtomicTx(txID ids.ID) (*Tx, uint64, error) {
   816  	indexedTxBytes, err := vm.acceptedAtomicTxDB.Get(txID[:])
   817  	if err != nil {
   818  		return nil, 0, err
   819  	}
   820  
   821  	packer := wrappers.Packer{Bytes: indexedTxBytes}
   822  	height := packer.UnpackLong()
   823  	txBytes := packer.UnpackBytes()
   824  
   825  	tx := &Tx{}
   826  	if _, err := vm.codec.Unmarshal(txBytes, tx); err != nil {
   827  		return nil, 0, fmt.Errorf("problem parsing atomic transaction from db: %w", err)
   828  	}
   829  	if err := tx.Sign(vm.codec, nil); err != nil {
   830  		return nil, 0, fmt.Errorf("problem initializing atomic transaction from db: %w", err)
   831  	}
   832  
   833  	return tx, height, nil
   834  }
   835  
   836  // getAtomicTx returns the requested transaction, status, and height.
   837  // If the status is Unknown, then the returned transaction will be nil.
   838  func (vm *VM) getAtomicTx(txID ids.ID) (*Tx, Status, uint64, error) {
   839  	if tx, height, err := vm.getAcceptedAtomicTx(txID); err == nil {
   840  		return tx, Accepted, height, nil
   841  	} else if err != database.ErrNotFound {
   842  		return nil, Unknown, 0, err
   843  	}
   844  
   845  	tx, dropped, found := vm.mempool.GetTx(txID)
   846  	switch {
   847  	case found && dropped:
   848  		return tx, Dropped, 0, nil
   849  	case found:
   850  		return tx, Processing, 0, nil
   851  	default:
   852  		return nil, Unknown, 0, nil
   853  	}
   854  }
   855  
   856  // writeAtomicTx writes indexes [tx] in [blk]
   857  func (vm *VM) writeAtomicTx(blk *Block, tx *Tx) error {
   858  	// 8 bytes
   859  	height := blk.ethBlock.NumberU64()
   860  	// 4 + len(txBytes)
   861  	txBytes := tx.Bytes()
   862  	packer := wrappers.Packer{Bytes: make([]byte, 12+len(txBytes))}
   863  	packer.PackLong(height)
   864  	packer.PackBytes(txBytes)
   865  	txID := tx.ID()
   866  
   867  	return vm.acceptedAtomicTxDB.Put(txID[:], packer.Bytes)
   868  }
   869  
   870  // needToBuild returns true if there are outstanding transactions to be issued
   871  // into a block.
   872  func (vm *VM) needToBuild() bool {
   873  	size, err := vm.chain.PendingSize()
   874  	if err != nil {
   875  		log.Error("Failed to get chain pending size", "error", err)
   876  		return false
   877  	}
   878  	return size > 0 || vm.mempool.Len() > 0
   879  }
   880  
   881  // buildEarly returns true if there are sufficient outstanding transactions to
   882  // be issued into a block to build a block early.
   883  func (vm *VM) buildEarly() bool {
   884  	size, err := vm.chain.PendingSize()
   885  	if err != nil {
   886  		log.Error("Failed to get chain pending size", "error", err)
   887  		return false
   888  	}
   889  	return size > batchSize || vm.mempool.Len() > 1
   890  }
   891  
   892  // buildBlockTwoStageTimer is a two stage timer that sends a notification
   893  // to the engine when the VM is ready to build a block.
   894  // If it should be called back again, it returns the timeout duration at
   895  // which it should be called again.
   896  func (vm *VM) buildBlockTwoStageTimer() (time.Duration, bool) {
   897  	vm.buildBlockLock.Lock()
   898  	defer vm.buildBlockLock.Unlock()
   899  
   900  	switch vm.buildStatus {
   901  	case dontBuild:
   902  		return 0, false
   903  	case conditionalBuild:
   904  		if !vm.buildEarly() {
   905  			vm.buildStatus = mayBuild
   906  			return (maxBlockTime - minBlockTime), true
   907  		}
   908  	case mayBuild:
   909  	case building:
   910  		// If the status has already been set to building, there is no need
   911  		// to send an additional request to the consensus engine until the call
   912  		// to BuildBlock resets the block status.
   913  		return 0, false
   914  	default:
   915  		// Log an error if an invalid status is found.
   916  		log.Error("Found invalid build status in build block timer", "buildStatus", vm.buildStatus)
   917  	}
   918  
   919  	select {
   920  	case vm.notifyBuildBlockChan <- commonEng.PendingTxs:
   921  		vm.buildStatus = building
   922  	default:
   923  		log.Error("Failed to push PendingTxs notification to the consensus engine.")
   924  	}
   925  
   926  	// No need for the timeout to fire again until BuildBlock is called.
   927  	return 0, false
   928  }
   929  
   930  // signalTxsReady sets the initial timeout on the two stage timer if the process
   931  // has not already begun from an earlier notification. If [buildStatus] is anything
   932  // other than [dontBuild], then the attempt has already begun and this notification
   933  // can be safely skipped.
   934  func (vm *VM) signalTxsReady() {
   935  	vm.buildBlockLock.Lock()
   936  	defer vm.buildBlockLock.Unlock()
   937  
   938  	// Set the build block timer in motion if it has not been started.
   939  	if vm.buildStatus == dontBuild {
   940  		vm.buildStatus = conditionalBuild
   941  		vm.buildBlockTimer.SetTimeoutIn(minBlockTime)
   942  	}
   943  }
   944  
   945  // awaitSubmittedTxs waits for new transactions to be submitted
   946  // and notifies the VM when the tx pool has transactions to be
   947  // put into a new block.
   948  func (vm *VM) awaitSubmittedTxs() {
   949  	defer vm.shutdownWg.Done()
   950  	txSubmitChan := vm.chain.GetTxSubmitCh()
   951  	for {
   952  		select {
   953  		case <-txSubmitChan:
   954  			log.Trace("New tx detected, trying to generate a block")
   955  			vm.signalTxsReady()
   956  		case <-vm.mempool.Pending:
   957  			log.Trace("New atomic Tx detected, trying to generate a block")
   958  			vm.signalTxsReady()
   959  		case <-vm.shutdownChan:
   960  			return
   961  		}
   962  	}
   963  }
   964  
   965  // ParseAddress takes in an address and produces the ID of the chain it's for
   966  // the ID of the address
   967  func (vm *VM) ParseAddress(addrStr string) (ids.ID, ids.ShortID, error) {
   968  	chainIDAlias, hrp, addrBytes, err := formatting.ParseAddress(addrStr)
   969  	if err != nil {
   970  		return ids.ID{}, ids.ShortID{}, err
   971  	}
   972  
   973  	chainID, err := vm.ctx.BCLookup.Lookup(chainIDAlias)
   974  	if err != nil {
   975  		return ids.ID{}, ids.ShortID{}, err
   976  	}
   977  
   978  	expectedHRP := constants.GetHRP(vm.ctx.NetworkID)
   979  	if hrp != expectedHRP {
   980  		return ids.ID{}, ids.ShortID{}, fmt.Errorf("expected hrp %q but got %q",
   981  			expectedHRP, hrp)
   982  	}
   983  
   984  	addr, err := ids.ToShortID(addrBytes)
   985  	if err != nil {
   986  		return ids.ID{}, ids.ShortID{}, err
   987  	}
   988  	return chainID, addr, nil
   989  }
   990  
   991  // issueTx verifies [tx] as valid to be issued on top of the currently preferred block
   992  // and then issues [tx] into the mempool if valid.
   993  func (vm *VM) issueTx(tx *Tx) error {
   994  	if err := vm.verifyTxAtTip(tx); err != nil {
   995  		return err
   996  	}
   997  	return vm.mempool.AddTx(tx)
   998  }
   999  
  1000  // verifyTxAtTip verifies that [tx] is valid to be issued on top of the currently preferred block
  1001  func (vm *VM) verifyTxAtTip(tx *Tx) error {
  1002  	preferredBlock := vm.chain.CurrentBlock()
  1003  	preferredState, err := vm.chain.BlockState(preferredBlock)
  1004  	if err != nil {
  1005  		return fmt.Errorf("failed to retrieve block state at tip while verifying atomic tx: %w", err)
  1006  	}
  1007  	rules := vm.currentRules()
  1008  	parentHeader := preferredBlock.Header()
  1009  	var nextBaseFee *big.Int
  1010  	timestamp := time.Now().Unix()
  1011  	bigTimestamp := big.NewInt(timestamp)
  1012  	if vm.chainConfig.IsApricotPhase3(bigTimestamp) {
  1013  		_, nextBaseFee, err = dummy.CalcBaseFee(vm.chainConfig, parentHeader, uint64(timestamp))
  1014  		if err != nil {
  1015  			// Return extremely detailed error since CalcBaseFee should never encounter an issue here
  1016  			return fmt.Errorf("failed to calculate base fee with parent timestamp (%d), parent ExtraData: (0x%x), and current timestamp (%d): %w", parentHeader.Time, parentHeader.Extra, timestamp, err)
  1017  		}
  1018  	}
  1019  
  1020  	return vm.verifyTx(tx, parentHeader.Hash(), nextBaseFee, preferredState, rules)
  1021  }
  1022  
  1023  // verifyTx verifies that [tx] is valid to be issued into a block with parent block [parentHash]
  1024  // and validated at [state] using [rules] as the current rule set.
  1025  // Note: verifyTx may modify [state]. If [state] needs to be properly maintained, the caller is responsible
  1026  // for reverting to the correct snapshot after calling this function. If this function is called with a
  1027  // throwaway state, then this is not necessary.
  1028  func (vm *VM) verifyTx(tx *Tx, parentHash common.Hash, baseFee *big.Int, state *state.StateDB, rules params.Rules) error {
  1029  	parentIntf, err := vm.GetBlockInternal(ids.ID(parentHash))
  1030  	if err != nil {
  1031  		return fmt.Errorf("failed to get parent block: %w", err)
  1032  	}
  1033  	parent, ok := parentIntf.(*Block)
  1034  	if !ok {
  1035  		return fmt.Errorf("parent block %s had unexpected type %T", parentIntf.ID(), parentIntf)
  1036  	}
  1037  	if err := tx.UnsignedAtomicTx.SemanticVerify(vm, tx, parent, baseFee, rules); err != nil {
  1038  		return err
  1039  	}
  1040  	return tx.UnsignedAtomicTx.EVMStateTransfer(vm.ctx, state)
  1041  }
  1042  
  1043  // GetAtomicUTXOs returns the utxos that at least one of the provided addresses is
  1044  // referenced in.
  1045  func (vm *VM) GetAtomicUTXOs(
  1046  	chainID ids.ID,
  1047  	addrs ids.ShortSet,
  1048  	startAddr ids.ShortID,
  1049  	startUTXOID ids.ID,
  1050  	limit int,
  1051  ) ([]*avax.UTXO, ids.ShortID, ids.ID, error) {
  1052  	if limit <= 0 || limit > maxUTXOsToFetch {
  1053  		limit = maxUTXOsToFetch
  1054  	}
  1055  
  1056  	addrsList := make([][]byte, addrs.Len())
  1057  	for i, addr := range addrs.List() {
  1058  		addrsList[i] = addr.Bytes()
  1059  	}
  1060  
  1061  	allUTXOBytes, lastAddr, lastUTXO, err := vm.ctx.SharedMemory.Indexed(
  1062  		chainID,
  1063  		addrsList,
  1064  		startAddr.Bytes(),
  1065  		startUTXOID[:],
  1066  		limit,
  1067  	)
  1068  	if err != nil {
  1069  		return nil, ids.ShortID{}, ids.ID{}, fmt.Errorf("error fetching atomic UTXOs: %w", err)
  1070  	}
  1071  
  1072  	lastAddrID, err := ids.ToShortID(lastAddr)
  1073  	if err != nil {
  1074  		lastAddrID = ids.ShortEmpty
  1075  	}
  1076  	lastUTXOID, err := ids.ToID(lastUTXO)
  1077  	if err != nil {
  1078  		lastUTXOID = ids.Empty
  1079  	}
  1080  
  1081  	utxos := make([]*avax.UTXO, len(allUTXOBytes))
  1082  	for i, utxoBytes := range allUTXOBytes {
  1083  		utxo := &avax.UTXO{}
  1084  		if _, err := vm.codec.Unmarshal(utxoBytes, utxo); err != nil {
  1085  			return nil, ids.ShortID{}, ids.ID{}, fmt.Errorf("error parsing UTXO: %w", err)
  1086  		}
  1087  		utxos[i] = utxo
  1088  	}
  1089  	return utxos, lastAddrID, lastUTXOID, nil
  1090  }
  1091  
  1092  // GetSpendableFunds returns a list of EVMInputs and keys (in corresponding
  1093  // order) to total [amount] of [assetID] owned by [keys].
  1094  // Note: we return [][]*crypto.PrivateKeySECP256K1R even though each input
  1095  // corresponds to a single key, so that the signers can be passed in to
  1096  // [tx.Sign] which supports multiple keys on a single input.
  1097  func (vm *VM) GetSpendableFunds(
  1098  	keys []*crypto.PrivateKeySECP256K1R,
  1099  	assetID ids.ID,
  1100  	amount uint64,
  1101  ) ([]EVMInput, [][]*crypto.PrivateKeySECP256K1R, error) {
  1102  	// Note: current state uses the state of the preferred block.
  1103  	state, err := vm.chain.CurrentState()
  1104  	if err != nil {
  1105  		return nil, nil, err
  1106  	}
  1107  	inputs := []EVMInput{}
  1108  	signers := [][]*crypto.PrivateKeySECP256K1R{}
  1109  	// Note: we assume that each key in [keys] is unique, so that iterating over
  1110  	// the keys will not produce duplicated nonces in the returned EVMInput slice.
  1111  	for _, key := range keys {
  1112  		if amount == 0 {
  1113  			break
  1114  		}
  1115  		addr := GetEthAddress(key)
  1116  		var balance uint64
  1117  		if assetID == vm.ctx.AVAXAssetID {
  1118  			// If the asset is AVAX, we divide by the x2cRate to convert back to the correct
  1119  			// denomination of AVAX that can be exported.
  1120  			balance = new(big.Int).Div(state.GetBalance(addr), x2cRate).Uint64()
  1121  		} else {
  1122  			balance = state.GetBalanceMultiCoin(addr, common.Hash(assetID)).Uint64()
  1123  		}
  1124  		if balance == 0 {
  1125  			continue
  1126  		}
  1127  		if amount < balance {
  1128  			balance = amount
  1129  		}
  1130  		nonce, err := vm.GetCurrentNonce(addr)
  1131  		if err != nil {
  1132  			return nil, nil, err
  1133  		}
  1134  		inputs = append(inputs, EVMInput{
  1135  			Address: addr,
  1136  			Amount:  balance,
  1137  			AssetID: assetID,
  1138  			Nonce:   nonce,
  1139  		})
  1140  		signers = append(signers, []*crypto.PrivateKeySECP256K1R{key})
  1141  		amount -= balance
  1142  	}
  1143  
  1144  	if amount > 0 {
  1145  		return nil, nil, errInsufficientFunds
  1146  	}
  1147  
  1148  	return inputs, signers, nil
  1149  }
  1150  
  1151  // GetSpendableAVAXWithFee returns a list of EVMInputs and keys (in corresponding
  1152  // order) to total [amount] + [fee] of [AVAX] owned by [keys].
  1153  // This function accounts for the added cost of the additional inputs needed to
  1154  // create the transaction and makes sure to skip any keys with a balance that is
  1155  // insufficient to cover the additional fee.
  1156  // Note: we return [][]*crypto.PrivateKeySECP256K1R even though each input
  1157  // corresponds to a single key, so that the signers can be passed in to
  1158  // [tx.Sign] which supports multiple keys on a single input.
  1159  func (vm *VM) GetSpendableAVAXWithFee(
  1160  	keys []*crypto.PrivateKeySECP256K1R,
  1161  	amount uint64,
  1162  	cost uint64,
  1163  	baseFee *big.Int,
  1164  ) ([]EVMInput, [][]*crypto.PrivateKeySECP256K1R, error) {
  1165  	// Note: current state uses the state of the preferred block.
  1166  	state, err := vm.chain.CurrentState()
  1167  	if err != nil {
  1168  		return nil, nil, err
  1169  	}
  1170  
  1171  	initialFee, err := calculateDynamicFee(cost, baseFee)
  1172  	if err != nil {
  1173  		return nil, nil, err
  1174  	}
  1175  
  1176  	newAmount, err := math.Add64(amount, initialFee)
  1177  	if err != nil {
  1178  		return nil, nil, err
  1179  	}
  1180  	amount = newAmount
  1181  
  1182  	inputs := []EVMInput{}
  1183  	signers := [][]*crypto.PrivateKeySECP256K1R{}
  1184  	// Note: we assume that each key in [keys] is unique, so that iterating over
  1185  	// the keys will not produce duplicated nonces in the returned EVMInput slice.
  1186  	for _, key := range keys {
  1187  		if amount == 0 {
  1188  			break
  1189  		}
  1190  
  1191  		prevFee, err := calculateDynamicFee(cost, baseFee)
  1192  		if err != nil {
  1193  			return nil, nil, err
  1194  		}
  1195  
  1196  		newCost := cost + EVMInputGas
  1197  		newFee, err := calculateDynamicFee(newCost, baseFee)
  1198  		if err != nil {
  1199  			return nil, nil, err
  1200  		}
  1201  
  1202  		additionalFee := newFee - prevFee
  1203  
  1204  		addr := GetEthAddress(key)
  1205  		// Since the asset is AVAX, we divide by the x2cRate to convert back to
  1206  		// the correct denomination of AVAX that can be exported.
  1207  		balance := new(big.Int).Div(state.GetBalance(addr), x2cRate).Uint64()
  1208  		// If the balance for [addr] is insufficient to cover the additional cost
  1209  		// of adding an input to the transaction, skip adding the input altogether
  1210  		if balance <= additionalFee {
  1211  			continue
  1212  		}
  1213  
  1214  		// Update the cost for the next iteration
  1215  		cost = newCost
  1216  
  1217  		newAmount, err := math.Add64(amount, additionalFee)
  1218  		if err != nil {
  1219  			return nil, nil, err
  1220  		}
  1221  		amount = newAmount
  1222  
  1223  		// Use the entire [balance] as an input, but if the required [amount]
  1224  		// is less than the balance, update the [inputAmount] to spend the
  1225  		// minimum amount to finish the transaction.
  1226  		inputAmount := balance
  1227  		if amount < balance {
  1228  			inputAmount = amount
  1229  		}
  1230  		nonce, err := vm.GetCurrentNonce(addr)
  1231  		if err != nil {
  1232  			return nil, nil, err
  1233  		}
  1234  		inputs = append(inputs, EVMInput{
  1235  			Address: addr,
  1236  			Amount:  inputAmount,
  1237  			AssetID: vm.ctx.AVAXAssetID,
  1238  			Nonce:   nonce,
  1239  		})
  1240  		signers = append(signers, []*crypto.PrivateKeySECP256K1R{key})
  1241  		amount -= inputAmount
  1242  	}
  1243  
  1244  	if amount > 0 {
  1245  		return nil, nil, errInsufficientFunds
  1246  	}
  1247  
  1248  	return inputs, signers, nil
  1249  }
  1250  
  1251  // GetCurrentNonce returns the nonce associated with the address at the
  1252  // preferred block
  1253  func (vm *VM) GetCurrentNonce(address common.Address) (uint64, error) {
  1254  	// Note: current state uses the state of the preferred block.
  1255  	state, err := vm.chain.CurrentState()
  1256  	if err != nil {
  1257  		return 0, err
  1258  	}
  1259  	return state.GetNonce(address), nil
  1260  }
  1261  
  1262  // currentRules returns the chain rules for the current block.
  1263  func (vm *VM) currentRules() params.Rules {
  1264  	header := vm.chain.APIBackend().CurrentHeader()
  1265  	return vm.chainConfig.AvalancheRules(header.Number, big.NewInt(int64(header.Time)))
  1266  }
  1267  
  1268  // getBlockValidator returns the block validator that should be used for a block that
  1269  // follows the ruleset defined by [rules]
  1270  func (vm *VM) getBlockValidator(rules params.Rules) BlockValidator {
  1271  	switch {
  1272  	case rules.IsApricotPhase3:
  1273  		return phase3BlockValidator
  1274  	case rules.IsApricotPhase2, rules.IsApricotPhase1:
  1275  		// Note: the phase1BlockValidator is used in both apricot phase1 and phase2
  1276  		return phase1BlockValidator
  1277  	default:
  1278  		return phase0BlockValidator
  1279  	}
  1280  }
  1281  
  1282  func (vm *VM) startContinuousProfiler() {
  1283  	// If the profiler directory is empty, return immediately
  1284  	// without creating or starting a continuous profiler.
  1285  	if vm.config.ContinuousProfilerDir == "" {
  1286  		return
  1287  	}
  1288  	vm.profiler = profiler.NewContinuous(
  1289  		filepath.Join(vm.config.ContinuousProfilerDir),
  1290  		vm.config.ContinuousProfilerFrequency.Duration,
  1291  		vm.config.ContinuousProfilerMaxFiles,
  1292  	)
  1293  	defer vm.profiler.Shutdown()
  1294  
  1295  	vm.shutdownWg.Add(1)
  1296  	go func() {
  1297  		defer vm.shutdownWg.Done()
  1298  		log.Info("Dispatching continuous profiler", "dir", vm.config.ContinuousProfilerDir, "freq", vm.config.ContinuousProfilerFrequency, "maxFiles", vm.config.ContinuousProfilerMaxFiles)
  1299  		err := vm.profiler.Dispatch()
  1300  		if err != nil {
  1301  			log.Error("continuous profiler failed", "err", err)
  1302  		}
  1303  	}()
  1304  	// Wait for shutdownChan to be closed
  1305  	<-vm.shutdownChan
  1306  }
  1307  
  1308  func (vm *VM) estimateBaseFee(ctx context.Context) (*big.Int, error) {
  1309  	// Get the base fee to use
  1310  	baseFee, err := vm.chain.APIBackend().EstimateBaseFee(ctx)
  1311  	if err != nil {
  1312  		return nil, err
  1313  	}
  1314  	if baseFee == nil {
  1315  		baseFee = initialBaseFee
  1316  	} else {
  1317  		// give some breathing room
  1318  		baseFee.Mul(baseFee, big.NewInt(11))
  1319  		baseFee.Div(baseFee, big.NewInt(10))
  1320  	}
  1321  
  1322  	return baseFee, nil
  1323  }