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(ðConfig, &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 }