github.com/dim4egster/coreth@v0.10.2/plugin/evm/vm_test.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package evm
     5  
     6  import (
     7  	"context"
     8  	"crypto/rand"
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"math/big"
    13  	"os"
    14  	"path/filepath"
    15  	"sort"
    16  	"strings"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/ethereum/go-ethereum/common"
    21  	"github.com/ethereum/go-ethereum/log"
    22  	"github.com/ethereum/go-ethereum/rlp"
    23  
    24  	"github.com/dim4egster/coreth/trie"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  
    28  	"github.com/dim4egster/qmallgo/api/keystore"
    29  	"github.com/dim4egster/qmallgo/chains/atomic"
    30  	"github.com/dim4egster/qmallgo/database/manager"
    31  	"github.com/dim4egster/qmallgo/database/prefixdb"
    32  	"github.com/dim4egster/qmallgo/ids"
    33  	"github.com/dim4egster/qmallgo/snow"
    34  	"github.com/dim4egster/qmallgo/snow/choices"
    35  	"github.com/dim4egster/qmallgo/utils/cb58"
    36  	"github.com/dim4egster/qmallgo/utils/constants"
    37  	"github.com/dim4egster/qmallgo/utils/crypto"
    38  	"github.com/dim4egster/qmallgo/utils/formatting"
    39  	"github.com/dim4egster/qmallgo/utils/hashing"
    40  	"github.com/dim4egster/qmallgo/utils/logging"
    41  	"github.com/dim4egster/qmallgo/utils/units"
    42  	"github.com/dim4egster/qmallgo/version"
    43  	"github.com/dim4egster/qmallgo/vms/components/avax"
    44  	"github.com/dim4egster/qmallgo/vms/components/chain"
    45  	"github.com/dim4egster/qmallgo/vms/secp256k1fx"
    46  
    47  	engCommon "github.com/dim4egster/qmallgo/snow/engine/common"
    48  
    49  	"github.com/dim4egster/coreth/consensus/dummy"
    50  	"github.com/dim4egster/coreth/core"
    51  	"github.com/dim4egster/coreth/core/types"
    52  	"github.com/dim4egster/coreth/eth"
    53  	"github.com/dim4egster/coreth/params"
    54  	"github.com/dim4egster/coreth/rpc"
    55  
    56  	accountKeystore "github.com/dim4egster/coreth/accounts/keystore"
    57  )
    58  
    59  var (
    60  	testNetworkID    uint32 = 10
    61  	testCChainID            = ids.ID{'c', 'c', 'h', 'a', 'i', 'n', 't', 'e', 's', 't'}
    62  	testXChainID            = ids.ID{'t', 'e', 's', 't', 'x'}
    63  	nonExistentID           = ids.ID{'F'}
    64  	testKeys         []*crypto.PrivateKeySECP256K1R
    65  	testEthAddrs     []common.Address // testEthAddrs[i] corresponds to testKeys[i]
    66  	testShortIDAddrs []ids.ShortID
    67  	testAvaxAssetID  = ids.ID{1, 2, 3}
    68  	username         = "Johns"
    69  	password         = "CjasdjhiPeirbSenfeI13" // #nosec G101
    70  	// Use chainId: 43111, so that it does not overlap with any Avalanche ChainIDs, which may have their
    71  	// config overridden in vm.Initialize.
    72  	genesisJSONApricotPhase0 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    73  	genesisJSONApricotPhase1 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    74  	genesisJSONApricotPhase2 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    75  	genesisJSONApricotPhase3 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    76  	genesisJSONApricotPhase4 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    77  	genesisJSONApricotPhase5 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    78  
    79  	genesisJSONApricotPhasePre6  = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    80  	genesisJSONApricotPhase6     = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    81  	genesisJSONApricotPhasePost6 = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    82  
    83  	genesisJSONBanff      = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    84  	genesisJSONClementine = "{\"config\":{\"chainId\":43111,\"homesteadBlock\":0,\"daoForkBlock\":0,\"daoForkSupport\":true,\"eip150Block\":0,\"eip150Hash\":\"0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0\",\"eip155Block\":0,\"eip158Block\":0,\"byzantiumBlock\":0,\"constantinopleBlock\":0,\"petersburgBlock\":0,\"istanbulBlock\":0,\"muirGlacierBlock\":0,\"apricotPhase1BlockTimestamp\":0,\"apricotPhase2BlockTimestamp\":0,\"apricotPhase3BlockTimestamp\":0,\"apricotPhase4BlockTimestamp\":0,\"apricotPhase5BlockTimestamp\":0,\"apricotPhasePre6BlockTimestamp\":0,\"apricotPhase6BlockTimestamp\":0,\"apricotPhasePost6BlockTimestamp\":0,\"banffBlockTimestamp\":0,\"clementineBlockTimestamp\":0},\"nonce\":\"0x0\",\"timestamp\":\"0x0\",\"extraData\":\"0x00\",\"gasLimit\":\"0x5f5e100\",\"difficulty\":\"0x0\",\"mixHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\":\"0x0000000000000000000000000000000000000000\",\"alloc\":{\"0100000000000000000000000000000000000000\":{\"code\":\"0x7300000000000000000000000000000000000000003014608060405260043610603d5760003560e01c80631e010439146042578063b6510bb314606e575b600080fd5b605c60048036036020811015605657600080fd5b503560b1565b60408051918252519081900360200190f35b818015607957600080fd5b5060af60048036036080811015608e57600080fd5b506001600160a01b03813516906020810135906040810135906060013560b6565b005b30cd90565b836001600160a01b031681836108fc8690811502906040516000604051808303818888878c8acf9550505050505015801560f4573d6000803e3d6000fd5b505050505056fea26469706673582212201eebce970fe3f5cb96bf8ac6ba5f5c133fc2908ae3dcd51082cfee8f583429d064736f6c634300060a0033\",\"balance\":\"0x0\"}},\"number\":\"0x0\",\"gasUsed\":\"0x0\",\"parentHash\":\"0x0000000000000000000000000000000000000000000000000000000000000000\"}"
    85  	genesisJSONLatest     = genesisJSONBanff // TODO: update to Clementine
    86  
    87  	apricotRulesPhase0 = params.Rules{}
    88  	apricotRulesPhase1 = params.Rules{IsApricotPhase1: true}
    89  	apricotRulesPhase2 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true}
    90  	apricotRulesPhase3 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true}
    91  	apricotRulesPhase4 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true}
    92  	apricotRulesPhase5 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true}
    93  	apricotRulesPhase6 = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true}
    94  	banffRules         = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true, IsBanff: true}
    95  	// clementineRules    = params.Rules{IsApricotPhase1: true, IsApricotPhase2: true, IsApricotPhase3: true, IsApricotPhase4: true, IsApricotPhase5: true, IsApricotPhasePre6: true, IsApricotPhase6: true, IsApricotPhasePost6: true, IsBanff: true, IsClementine: true}
    96  )
    97  
    98  func init() {
    99  	var b []byte
   100  	factory := crypto.FactorySECP256K1R{}
   101  
   102  	for _, key := range []string{
   103  		"24jUJ9vZexUM6expyMcT48LBx27k1m7xpraoV62oSQAHdziao5",
   104  		"2MMvUMsxx6zsHSNXJdFD8yc5XkancvwyKPwpw4xUK3TCGDuNBY",
   105  		"cxb7KpGWhDMALTjNNSJ7UQkkomPesyWAPUaWRGdyeBNzR6f35",
   106  	} {
   107  		b, _ = cb58.Decode(key)
   108  		pk, _ := factory.ToPrivateKey(b)
   109  		secpKey := pk.(*crypto.PrivateKeySECP256K1R)
   110  		testKeys = append(testKeys, secpKey)
   111  		testEthAddrs = append(testEthAddrs, GetEthAddress(secpKey))
   112  		testShortIDAddrs = append(testShortIDAddrs, pk.PublicKey().Address())
   113  	}
   114  
   115  	minBlockTimeAP4 = time.Millisecond
   116  }
   117  
   118  // BuildGenesisTest returns the genesis bytes for Coreth VM to be used in testing
   119  func BuildGenesisTest(t *testing.T, genesisJSON string) []byte {
   120  	ss := StaticService{}
   121  
   122  	genesis := &core.Genesis{}
   123  	if err := json.Unmarshal([]byte(genesisJSON), genesis); err != nil {
   124  		t.Fatalf("Problem unmarshaling genesis JSON: %s", err)
   125  	}
   126  	genesisReply, err := ss.BuildGenesis(nil, genesis)
   127  	if err != nil {
   128  		t.Fatalf("Failed to create test genesis")
   129  	}
   130  	genesisBytes, err := formatting.Decode(genesisReply.Encoding, genesisReply.Bytes)
   131  	if err != nil {
   132  		t.Fatalf("Failed to decode genesis bytes: %s", err)
   133  	}
   134  	return genesisBytes
   135  }
   136  
   137  func NewContext() *snow.Context {
   138  	ctx := snow.DefaultContextTest()
   139  	ctx.NodeID = ids.GenerateTestNodeID()
   140  	ctx.NetworkID = testNetworkID
   141  	ctx.ChainID = testCChainID
   142  	ctx.AVAXAssetID = testAvaxAssetID
   143  	ctx.XChainID = testXChainID
   144  	ctx.SharedMemory = testSharedMemory()
   145  	aliaser := ctx.BCLookup.(ids.Aliaser)
   146  	_ = aliaser.Alias(testCChainID, "C")
   147  	_ = aliaser.Alias(testCChainID, testCChainID.String())
   148  	_ = aliaser.Alias(testXChainID, "X")
   149  	_ = aliaser.Alias(testXChainID, testXChainID.String())
   150  	ctx.SNLookup = &snLookup{
   151  		chainsToSubnet: map[ids.ID]ids.ID{
   152  			constants.PlatformChainID: constants.PrimaryNetworkID,
   153  			testXChainID:              constants.PrimaryNetworkID,
   154  			testCChainID:              constants.PrimaryNetworkID,
   155  		},
   156  	}
   157  	return ctx
   158  }
   159  
   160  type snLookup struct {
   161  	chainsToSubnet map[ids.ID]ids.ID
   162  }
   163  
   164  func (sn *snLookup) SubnetID(chainID ids.ID) (ids.ID, error) {
   165  	subnetID, ok := sn.chainsToSubnet[chainID]
   166  	if !ok {
   167  		return ids.ID{}, errors.New("unknown chain")
   168  	}
   169  	return subnetID, nil
   170  }
   171  
   172  // setupGenesis sets up the genesis
   173  // If [genesisJSON] is empty, defaults to using [genesisJSONLatest]
   174  func setupGenesis(t *testing.T,
   175  	genesisJSON string,
   176  ) (*snow.Context,
   177  	manager.Manager,
   178  	[]byte,
   179  	chan engCommon.Message,
   180  	*atomic.Memory) {
   181  	if len(genesisJSON) == 0 {
   182  		genesisJSON = genesisJSONLatest
   183  	}
   184  	genesisBytes := BuildGenesisTest(t, genesisJSON)
   185  	ctx := NewContext()
   186  
   187  	baseDBManager := manager.NewMemDB(&version.Semantic{
   188  		Major: 1,
   189  		Minor: 4,
   190  		Patch: 5,
   191  	})
   192  
   193  	m := atomic.NewMemory(prefixdb.New([]byte{0}, baseDBManager.Current().Database))
   194  	ctx.SharedMemory = m.NewSharedMemory(ctx.ChainID)
   195  
   196  	// NB: this lock is intentionally left locked when this function returns.
   197  	// The caller of this function is responsible for unlocking.
   198  	ctx.Lock.Lock()
   199  
   200  	userKeystore := keystore.New(
   201  		logging.NoLog{},
   202  		manager.NewMemDB(&version.Semantic{
   203  			Major: 1,
   204  			Minor: 4,
   205  			Patch: 5,
   206  		}),
   207  	)
   208  	if err := userKeystore.CreateUser(username, password); err != nil {
   209  		t.Fatal(err)
   210  	}
   211  	ctx.Keystore = userKeystore.NewBlockchainKeyStore(ctx.ChainID)
   212  
   213  	issuer := make(chan engCommon.Message, 1)
   214  	prefixedDBManager := baseDBManager.NewPrefixDBManager([]byte{1})
   215  	return ctx, prefixedDBManager, genesisBytes, issuer, m
   216  }
   217  
   218  // GenesisVM creates a VM instance with the genesis test bytes and returns
   219  // the channel use to send messages to the engine, the vm, and atomic memory
   220  // If [genesisJSON] is empty, defaults to using [genesisJSONLatest]
   221  func GenesisVM(t *testing.T,
   222  	finishBootstrapping bool,
   223  	genesisJSON string,
   224  	configJSON string,
   225  	upgradeJSON string,
   226  ) (chan engCommon.Message,
   227  	*VM, manager.Manager,
   228  	*atomic.Memory,
   229  	*engCommon.SenderTest) {
   230  	vm := &VM{}
   231  	ctx, dbManager, genesisBytes, issuer, m := setupGenesis(t, genesisJSON)
   232  	appSender := &engCommon.SenderTest{T: t}
   233  	appSender.CantSendAppGossip = true
   234  	appSender.SendAppGossipF = func([]byte) error { return nil }
   235  	if err := vm.Initialize(
   236  		ctx,
   237  		dbManager,
   238  		genesisBytes,
   239  		[]byte(upgradeJSON),
   240  		[]byte(configJSON),
   241  		issuer,
   242  		[]*engCommon.Fx{},
   243  		appSender,
   244  	); err != nil {
   245  		t.Fatal(err)
   246  	}
   247  
   248  	if finishBootstrapping {
   249  		assert.NoError(t, vm.SetState(snow.Bootstrapping))
   250  		assert.NoError(t, vm.SetState(snow.NormalOp))
   251  	}
   252  
   253  	return issuer, vm, dbManager, m, appSender
   254  }
   255  
   256  func addUTXO(sharedMemory *atomic.Memory, ctx *snow.Context, txID ids.ID, index uint32, assetID ids.ID, amount uint64, addr ids.ShortID) (*avax.UTXO, error) {
   257  	utxo := &avax.UTXO{
   258  		UTXOID: avax.UTXOID{
   259  			TxID:        txID,
   260  			OutputIndex: index,
   261  		},
   262  		Asset: avax.Asset{ID: assetID},
   263  		Out: &secp256k1fx.TransferOutput{
   264  			Amt: amount,
   265  			OutputOwners: secp256k1fx.OutputOwners{
   266  				Threshold: 1,
   267  				Addrs:     []ids.ShortID{addr},
   268  			},
   269  		},
   270  	}
   271  	utxoBytes, err := Codec.Marshal(codecVersion, utxo)
   272  	if err != nil {
   273  		return nil, err
   274  	}
   275  
   276  	xChainSharedMemory := sharedMemory.NewSharedMemory(ctx.XChainID)
   277  	inputID := utxo.InputID()
   278  	if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{ctx.ChainID: {PutRequests: []*atomic.Element{{
   279  		Key:   inputID[:],
   280  		Value: utxoBytes,
   281  		Traits: [][]byte{
   282  			addr.Bytes(),
   283  		},
   284  	}}}}); err != nil {
   285  		return nil, err
   286  	}
   287  
   288  	return utxo, nil
   289  }
   290  
   291  // GenesisVMWithUTXOs creates a GenesisVM and generates UTXOs in the X-Chain Shared Memory containing AVAX based on the [utxos] map
   292  // Generates UTXOIDs by using a hash of the address in the [utxos] map such that the UTXOs will be generated deterministically.
   293  // If [genesisJSON] is empty, defaults to using [genesisJSONLatest]
   294  func GenesisVMWithUTXOs(t *testing.T, finishBootstrapping bool, genesisJSON string, configJSON string, upgradeJSON string, utxos map[ids.ShortID]uint64) (chan engCommon.Message, *VM, manager.Manager, *atomic.Memory, *engCommon.SenderTest) {
   295  	issuer, vm, dbManager, sharedMemory, sender := GenesisVM(t, finishBootstrapping, genesisJSON, configJSON, upgradeJSON)
   296  	for addr, avaxAmount := range utxos {
   297  		txID, err := ids.ToID(hashing.ComputeHash256(addr.Bytes()))
   298  		if err != nil {
   299  			t.Fatalf("Failed to generate txID from addr: %s", err)
   300  		}
   301  		if _, err := addUTXO(sharedMemory, vm.ctx, txID, 0, vm.ctx.AVAXAssetID, avaxAmount, addr); err != nil {
   302  			t.Fatalf("Failed to add UTXO to shared memory: %s", err)
   303  		}
   304  	}
   305  
   306  	return issuer, vm, dbManager, sharedMemory, sender
   307  }
   308  
   309  func TestVMConfig(t *testing.T) {
   310  	txFeeCap := float64(11)
   311  	enabledEthAPIs := []string{"debug"}
   312  	configJSON := fmt.Sprintf("{\"rpc-tx-fee-cap\": %g,\"eth-apis\": %s}", txFeeCap, fmt.Sprintf("[%q]", enabledEthAPIs[0]))
   313  	_, vm, _, _, _ := GenesisVM(t, false, "", configJSON, "")
   314  	assert.Equal(t, vm.config.RPCTxFeeCap, txFeeCap, "Tx Fee Cap should be set")
   315  	assert.Equal(t, vm.config.EthAPIs(), enabledEthAPIs, "EnabledEthAPIs should be set")
   316  	assert.NoError(t, vm.Shutdown())
   317  }
   318  
   319  func TestVMConfigDefaults(t *testing.T) {
   320  	txFeeCap := float64(11)
   321  	enabledEthAPIs := []string{"debug"}
   322  	configJSON := fmt.Sprintf("{\"rpc-tx-fee-cap\": %g,\"eth-apis\": %s}", txFeeCap, fmt.Sprintf("[%q]", enabledEthAPIs[0]))
   323  	_, vm, _, _, _ := GenesisVM(t, false, "", configJSON, "")
   324  
   325  	var vmConfig Config
   326  	vmConfig.SetDefaults()
   327  	vmConfig.RPCTxFeeCap = txFeeCap
   328  	vmConfig.EnabledEthAPIs = enabledEthAPIs
   329  	assert.Equal(t, vmConfig, vm.config, "VM Config should match default with overrides")
   330  	assert.NoError(t, vm.Shutdown())
   331  }
   332  
   333  func TestVMNilConfig(t *testing.T) {
   334  	_, vm, _, _, _ := GenesisVM(t, false, "", "", "")
   335  
   336  	// VM Config should match defaults if no config is passed in
   337  	var vmConfig Config
   338  	vmConfig.SetDefaults()
   339  	assert.Equal(t, vmConfig, vm.config, "VM Config should match default config")
   340  	assert.NoError(t, vm.Shutdown())
   341  }
   342  
   343  func TestVMContinuosProfiler(t *testing.T) {
   344  	profilerDir := t.TempDir()
   345  	profilerFrequency := 500 * time.Millisecond
   346  	configJSON := fmt.Sprintf("{\"continuous-profiler-dir\": %q,\"continuous-profiler-frequency\": \"500ms\"}", profilerDir)
   347  	_, vm, _, _, _ := GenesisVM(t, false, "", configJSON, "")
   348  	assert.Equal(t, vm.config.ContinuousProfilerDir, profilerDir, "profiler dir should be set")
   349  	assert.Equal(t, vm.config.ContinuousProfilerFrequency.Duration, profilerFrequency, "profiler frequency should be set")
   350  
   351  	// Sleep for twice the frequency of the profiler to give it time
   352  	// to generate the first profile.
   353  	time.Sleep(2 * time.Second)
   354  	assert.NoError(t, vm.Shutdown())
   355  
   356  	// Check that the first profile was generated
   357  	expectedFileName := filepath.Join(profilerDir, "cpu.profile.1")
   358  	_, err := os.Stat(expectedFileName)
   359  	assert.NoError(t, err, "Expected continuous profiler to generate the first CPU profile at %s", expectedFileName)
   360  }
   361  
   362  func TestVMUpgrades(t *testing.T) {
   363  	genesisTests := []struct {
   364  		name             string
   365  		genesis          string
   366  		expectedGasPrice *big.Int
   367  	}{
   368  		{
   369  			name:             "Apricot Phase 0",
   370  			genesis:          genesisJSONApricotPhase0,
   371  			expectedGasPrice: big.NewInt(params.LaunchMinGasPrice),
   372  		},
   373  		{
   374  			name:             "Apricot Phase 1",
   375  			genesis:          genesisJSONApricotPhase1,
   376  			expectedGasPrice: big.NewInt(params.ApricotPhase1MinGasPrice),
   377  		},
   378  		{
   379  			name:             "Apricot Phase 2",
   380  			genesis:          genesisJSONApricotPhase2,
   381  			expectedGasPrice: big.NewInt(params.ApricotPhase1MinGasPrice),
   382  		},
   383  		{
   384  			name:             "Apricot Phase 3",
   385  			genesis:          genesisJSONApricotPhase3,
   386  			expectedGasPrice: big.NewInt(0),
   387  		},
   388  		{
   389  			name:             "Apricot Phase 4",
   390  			genesis:          genesisJSONApricotPhase4,
   391  			expectedGasPrice: big.NewInt(0),
   392  		},
   393  		{
   394  			name:             "Apricot Phase 5",
   395  			genesis:          genesisJSONApricotPhase5,
   396  			expectedGasPrice: big.NewInt(0),
   397  		},
   398  		{
   399  			name:             "Apricot Phase Pre 6",
   400  			genesis:          genesisJSONApricotPhasePre6,
   401  			expectedGasPrice: big.NewInt(0),
   402  		},
   403  		{
   404  			name:             "Apricot Phase 6",
   405  			genesis:          genesisJSONApricotPhase6,
   406  			expectedGasPrice: big.NewInt(0),
   407  		},
   408  		{
   409  			name:             "Apricot Phase Post 6",
   410  			genesis:          genesisJSONApricotPhasePost6,
   411  			expectedGasPrice: big.NewInt(0),
   412  		},
   413  		{
   414  			name:             "Banff",
   415  			genesis:          genesisJSONBanff,
   416  			expectedGasPrice: big.NewInt(0),
   417  		},
   418  		{
   419  			name:             "Clementine",
   420  			genesis:          genesisJSONClementine,
   421  			expectedGasPrice: big.NewInt(0),
   422  		},
   423  	}
   424  	for _, test := range genesisTests {
   425  		t.Run(test.name, func(t *testing.T) {
   426  			_, vm, _, _, _ := GenesisVM(t, true, test.genesis, "", "")
   427  
   428  			if gasPrice := vm.txPool.GasPrice(); gasPrice.Cmp(test.expectedGasPrice) != 0 {
   429  				t.Fatalf("Expected pool gas price to be %d but found %d", test.expectedGasPrice, gasPrice)
   430  			}
   431  			defer func() {
   432  				shutdownChan := make(chan error, 1)
   433  				shutdownFunc := func() {
   434  					err := vm.Shutdown()
   435  					shutdownChan <- err
   436  				}
   437  
   438  				go shutdownFunc()
   439  				shutdownTimeout := 50 * time.Millisecond
   440  				ticker := time.NewTicker(shutdownTimeout)
   441  				select {
   442  				case <-ticker.C:
   443  					t.Fatalf("VM shutdown took longer than timeout: %v", shutdownTimeout)
   444  				case err := <-shutdownChan:
   445  					if err != nil {
   446  						t.Fatalf("Shutdown errored: %s", err)
   447  					}
   448  				}
   449  			}()
   450  
   451  			lastAcceptedID, err := vm.LastAccepted()
   452  			if err != nil {
   453  				t.Fatal(err)
   454  			}
   455  
   456  			if lastAcceptedID != ids.ID(vm.genesisHash) {
   457  				t.Fatal("Expected last accepted block to match the genesis block hash")
   458  			}
   459  
   460  			genesisBlk, err := vm.GetBlock(lastAcceptedID)
   461  			if err != nil {
   462  				t.Fatalf("Failed to get genesis block due to %s", err)
   463  			}
   464  
   465  			if height := genesisBlk.Height(); height != 0 {
   466  				t.Fatalf("Expected height of geneiss block to be 0, found: %d", height)
   467  			}
   468  
   469  			if _, err := vm.ParseBlock(genesisBlk.Bytes()); err != nil {
   470  				t.Fatalf("Failed to parse genesis block due to %s", err)
   471  			}
   472  
   473  			genesisStatus := genesisBlk.Status()
   474  			if genesisStatus != choices.Accepted {
   475  				t.Fatalf("expected genesis status to be %s but was %s", choices.Accepted, genesisStatus)
   476  			}
   477  		})
   478  	}
   479  }
   480  
   481  // Simple test to ensure we can issue an import transaction followed by an export transaction
   482  // and they will be indexed correctly when accepted.
   483  func TestIssueAtomicTxs(t *testing.T) {
   484  	importAmount := uint64(50000000)
   485  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "", "", map[ids.ShortID]uint64{
   486  		testShortIDAddrs[0]: importAmount,
   487  	})
   488  
   489  	defer func() {
   490  		if err := vm.Shutdown(); err != nil {
   491  			t.Fatal(err)
   492  		}
   493  	}()
   494  
   495  	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
   496  	if err != nil {
   497  		t.Fatal(err)
   498  	}
   499  
   500  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
   501  		t.Fatal(err)
   502  	}
   503  
   504  	<-issuer
   505  
   506  	blk, err := vm.BuildBlock()
   507  	if err != nil {
   508  		t.Fatal(err)
   509  	}
   510  
   511  	if err := blk.Verify(); err != nil {
   512  		t.Fatal(err)
   513  	}
   514  
   515  	if status := blk.Status(); status != choices.Processing {
   516  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   517  	}
   518  
   519  	if err := vm.SetPreference(blk.ID()); err != nil {
   520  		t.Fatal(err)
   521  	}
   522  
   523  	if err := blk.Accept(); err != nil {
   524  		t.Fatal(err)
   525  	}
   526  
   527  	if status := blk.Status(); status != choices.Accepted {
   528  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
   529  	}
   530  
   531  	if lastAcceptedID, err := vm.LastAccepted(); err != nil {
   532  		t.Fatal(err)
   533  	} else if lastAcceptedID != blk.ID() {
   534  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID)
   535  	}
   536  
   537  	exportTx, err := vm.newExportTx(vm.ctx.AVAXAssetID, importAmount-(2*params.AvalancheAtomicTxFee), vm.ctx.XChainID, testShortIDAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
   538  	if err != nil {
   539  		t.Fatal(err)
   540  	}
   541  
   542  	if err := vm.issueTx(exportTx, true /*=local*/); err != nil {
   543  		t.Fatal(err)
   544  	}
   545  
   546  	<-issuer
   547  
   548  	blk2, err := vm.BuildBlock()
   549  	if err != nil {
   550  		t.Fatal(err)
   551  	}
   552  
   553  	if err := blk2.Verify(); err != nil {
   554  		t.Fatal(err)
   555  	}
   556  
   557  	if status := blk2.Status(); status != choices.Processing {
   558  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   559  	}
   560  
   561  	if err := blk2.Accept(); err != nil {
   562  		t.Fatal(err)
   563  	}
   564  
   565  	if status := blk2.Status(); status != choices.Accepted {
   566  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
   567  	}
   568  
   569  	if lastAcceptedID, err := vm.LastAccepted(); err != nil {
   570  		t.Fatal(err)
   571  	} else if lastAcceptedID != blk2.ID() {
   572  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk2.ID(), lastAcceptedID)
   573  	}
   574  
   575  	// Check that both atomic transactions were indexed as expected.
   576  	indexedImportTx, status, height, err := vm.getAtomicTx(importTx.ID())
   577  	assert.NoError(t, err)
   578  	assert.Equal(t, Accepted, status)
   579  	assert.Equal(t, uint64(1), height, "expected height of indexed import tx to be 1")
   580  	assert.Equal(t, indexedImportTx.ID(), importTx.ID(), "expected ID of indexed import tx to match original txID")
   581  
   582  	indexedExportTx, status, height, err := vm.getAtomicTx(exportTx.ID())
   583  	assert.NoError(t, err)
   584  	assert.Equal(t, Accepted, status)
   585  	assert.Equal(t, uint64(2), height, "expected height of indexed export tx to be 2")
   586  	assert.Equal(t, indexedExportTx.ID(), exportTx.ID(), "expected ID of indexed import tx to match original txID")
   587  }
   588  
   589  func TestBuildEthTxBlock(t *testing.T) {
   590  	importAmount := uint64(20000000)
   591  	issuer, vm, dbManager, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase2, "{\"pruning-enabled\":true}", "", map[ids.ShortID]uint64{
   592  		testShortIDAddrs[0]: importAmount,
   593  	})
   594  
   595  	defer func() {
   596  		if err := vm.Shutdown(); err != nil {
   597  			t.Fatal(err)
   598  		}
   599  	}()
   600  
   601  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
   602  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
   603  
   604  	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
   605  	if err != nil {
   606  		t.Fatal(err)
   607  	}
   608  
   609  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
   610  		t.Fatal(err)
   611  	}
   612  
   613  	<-issuer
   614  
   615  	blk1, err := vm.BuildBlock()
   616  	if err != nil {
   617  		t.Fatal(err)
   618  	}
   619  
   620  	if err := blk1.Verify(); err != nil {
   621  		t.Fatal(err)
   622  	}
   623  
   624  	if status := blk1.Status(); status != choices.Processing {
   625  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   626  	}
   627  
   628  	if err := vm.SetPreference(blk1.ID()); err != nil {
   629  		t.Fatal(err)
   630  	}
   631  
   632  	if err := blk1.Accept(); err != nil {
   633  		t.Fatal(err)
   634  	}
   635  
   636  	newHead := <-newTxPoolHeadChan
   637  	if newHead.Head.Hash() != common.Hash(blk1.ID()) {
   638  		t.Fatalf("Expected new block to match")
   639  	}
   640  
   641  	txs := make([]*types.Transaction, 10)
   642  	for i := 0; i < 10; i++ {
   643  		tx := types.NewTransaction(uint64(i), testEthAddrs[0], big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
   644  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), testKeys[0].ToECDSA())
   645  		if err != nil {
   646  			t.Fatal(err)
   647  		}
   648  		txs[i] = signedTx
   649  	}
   650  	errs := vm.txPool.AddRemotesSync(txs)
   651  	for i, err := range errs {
   652  		if err != nil {
   653  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
   654  		}
   655  	}
   656  
   657  	<-issuer
   658  
   659  	blk2, err := vm.BuildBlock()
   660  	if err != nil {
   661  		t.Fatal(err)
   662  	}
   663  
   664  	if err := blk2.Verify(); err != nil {
   665  		t.Fatal(err)
   666  	}
   667  
   668  	if status := blk2.Status(); status != choices.Processing {
   669  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
   670  	}
   671  
   672  	if err := blk2.Accept(); err != nil {
   673  		t.Fatal(err)
   674  	}
   675  
   676  	newHead = <-newTxPoolHeadChan
   677  	if newHead.Head.Hash() != common.Hash(blk2.ID()) {
   678  		t.Fatalf("Expected new block to match")
   679  	}
   680  
   681  	if status := blk2.Status(); status != choices.Accepted {
   682  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
   683  	}
   684  
   685  	lastAcceptedID, err := vm.LastAccepted()
   686  	if err != nil {
   687  		t.Fatal(err)
   688  	}
   689  	if lastAcceptedID != blk2.ID() {
   690  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk2.ID(), lastAcceptedID)
   691  	}
   692  
   693  	ethBlk1 := blk1.(*chain.BlockWrapper).Block.(*Block).ethBlock
   694  	if ethBlk1Root := ethBlk1.Root(); !vm.blockChain.HasState(ethBlk1Root) {
   695  		t.Fatalf("Expected blk1 state root to not yet be pruned after blk2 was accepted because of tip buffer")
   696  	}
   697  
   698  	// Clear the cache and ensure that GetBlock returns internal blocks with the correct status
   699  	vm.State.Flush()
   700  	blk2Refreshed, err := vm.GetBlockInternal(blk2.ID())
   701  	if err != nil {
   702  		t.Fatal(err)
   703  	}
   704  	if status := blk2Refreshed.Status(); status != choices.Accepted {
   705  		t.Fatalf("Expected refreshed blk2 to be Accepted, but found status: %s", status)
   706  	}
   707  
   708  	blk1RefreshedID := blk2Refreshed.Parent()
   709  	blk1Refreshed, err := vm.GetBlockInternal(blk1RefreshedID)
   710  	if err != nil {
   711  		t.Fatal(err)
   712  	}
   713  	if status := blk1Refreshed.Status(); status != choices.Accepted {
   714  		t.Fatalf("Expected refreshed blk1 to be Accepted, but found status: %s", status)
   715  	}
   716  
   717  	if blk1Refreshed.ID() != blk1.ID() {
   718  		t.Fatalf("Found unexpected blkID for parent of blk2")
   719  	}
   720  
   721  	restartedVM := &VM{}
   722  	if err := restartedVM.Initialize(
   723  		NewContext(),
   724  		dbManager,
   725  		[]byte(genesisJSONApricotPhase2),
   726  		[]byte(""),
   727  		[]byte("{\"pruning-enabled\":true}"),
   728  		issuer,
   729  		[]*engCommon.Fx{},
   730  		nil,
   731  	); err != nil {
   732  		t.Fatal(err)
   733  	}
   734  
   735  	// State root should not have been committed and discarded on restart
   736  	if ethBlk1Root := ethBlk1.Root(); restartedVM.blockChain.HasState(ethBlk1Root) {
   737  		t.Fatalf("Expected blk1 state root to be pruned after blk2 was accepted on top of it in pruning mode")
   738  	}
   739  
   740  	// State root should be committed when accepted tip on shutdown
   741  	ethBlk2 := blk2.(*chain.BlockWrapper).Block.(*Block).ethBlock
   742  	if ethBlk2Root := ethBlk2.Root(); !restartedVM.blockChain.HasState(ethBlk2Root) {
   743  		t.Fatalf("Expected blk2 state root to not be pruned after shutdown (last accepted tip should be committed)")
   744  	}
   745  }
   746  
   747  func testConflictingImportTxs(t *testing.T, genesis string) {
   748  	importAmount := uint64(10000000)
   749  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesis, "", "", map[ids.ShortID]uint64{
   750  		testShortIDAddrs[0]: importAmount,
   751  		testShortIDAddrs[1]: importAmount,
   752  		testShortIDAddrs[2]: importAmount,
   753  	})
   754  
   755  	defer func() {
   756  		if err := vm.Shutdown(); err != nil {
   757  			t.Fatal(err)
   758  		}
   759  	}()
   760  
   761  	importTxs := make([]*Tx, 0, 3)
   762  	conflictTxs := make([]*Tx, 0, 3)
   763  	for i, key := range testKeys {
   764  		importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[i], initialBaseFee, []*crypto.PrivateKeySECP256K1R{key})
   765  		if err != nil {
   766  			t.Fatal(err)
   767  		}
   768  		importTxs = append(importTxs, importTx)
   769  
   770  		conflictAddr := testEthAddrs[(i+1)%len(testEthAddrs)]
   771  		conflictTx, err := vm.newImportTx(vm.ctx.XChainID, conflictAddr, initialBaseFee, []*crypto.PrivateKeySECP256K1R{key})
   772  		if err != nil {
   773  			t.Fatal(err)
   774  		}
   775  		conflictTxs = append(conflictTxs, conflictTx)
   776  	}
   777  
   778  	expectedParentBlkID, err := vm.LastAccepted()
   779  	if err != nil {
   780  		t.Fatal(err)
   781  	}
   782  	for i, tx := range importTxs[:2] {
   783  		if err := vm.issueTx(tx, true /*=local*/); err != nil {
   784  			t.Fatal(err)
   785  		}
   786  
   787  		<-issuer
   788  
   789  		vm.clock.Set(vm.clock.Time().Add(2 * time.Second))
   790  		blk, err := vm.BuildBlock()
   791  		if err != nil {
   792  			t.Fatal(err)
   793  		}
   794  
   795  		if err := blk.Verify(); err != nil {
   796  			t.Fatal(err)
   797  		}
   798  
   799  		if status := blk.Status(); status != choices.Processing {
   800  			t.Fatalf("Expected status of built block %d to be %s, but found %s", i, choices.Processing, status)
   801  		}
   802  
   803  		if parentID := blk.Parent(); parentID != expectedParentBlkID {
   804  			t.Fatalf("Expected parent to have blockID %s, but found %s", expectedParentBlkID, parentID)
   805  		}
   806  
   807  		expectedParentBlkID = blk.ID()
   808  		if err := vm.SetPreference(blk.ID()); err != nil {
   809  			t.Fatal(err)
   810  		}
   811  	}
   812  
   813  	// Check that for each conflict tx (whose conflict is in the chain ancestry)
   814  	// the VM returns an error when it attempts to issue the conflict into the mempool
   815  	// and when it attempts to build a block with the conflict force added to the mempool.
   816  	for i, tx := range conflictTxs[:2] {
   817  		if err := vm.issueTx(tx, true /*=local*/); err == nil {
   818  			t.Fatal("Expected issueTx to fail due to conflicting transaction")
   819  		}
   820  		// Force issue transaction directly to the mempool
   821  		if err := vm.mempool.ForceAddTx(tx); err != nil {
   822  			t.Fatal(err)
   823  		}
   824  		<-issuer
   825  
   826  		vm.clock.Set(vm.clock.Time().Add(2 * time.Second))
   827  		_, err = vm.BuildBlock()
   828  		// The new block is verified in BuildBlock, so
   829  		// BuildBlock should fail due to an attempt to
   830  		// double spend an atomic UTXO.
   831  		if err == nil {
   832  			t.Fatalf("Block verification should have failed in BuildBlock %d due to double spending atomic UTXO", i)
   833  		}
   834  	}
   835  
   836  	// Generate one more valid block so that we can copy the header to create an invalid block
   837  	// with modified extra data. This new block will be invalid for more than one reason (invalid merkle root)
   838  	// so we check to make sure that the expected error is returned from block verification.
   839  	if err := vm.issueTx(importTxs[2], true); err != nil {
   840  		t.Fatal(err)
   841  	}
   842  	<-issuer
   843  	vm.clock.Set(vm.clock.Time().Add(2 * time.Second))
   844  
   845  	validBlock, err := vm.BuildBlock()
   846  	if err != nil {
   847  		t.Fatal(err)
   848  	}
   849  
   850  	if err := validBlock.Verify(); err != nil {
   851  		t.Fatal(err)
   852  	}
   853  
   854  	validEthBlock := validBlock.(*chain.BlockWrapper).Block.(*Block).ethBlock
   855  
   856  	rules := vm.currentRules()
   857  	var extraData []byte
   858  	switch {
   859  	case rules.IsApricotPhase5:
   860  		extraData, err = vm.codec.Marshal(codecVersion, []*Tx{conflictTxs[1]})
   861  	default:
   862  		extraData, err = vm.codec.Marshal(codecVersion, conflictTxs[1])
   863  	}
   864  	if err != nil {
   865  		t.Fatal(err)
   866  	}
   867  
   868  	conflictingAtomicTxBlock := types.NewBlock(
   869  		types.CopyHeader(validEthBlock.Header()),
   870  		nil,
   871  		nil,
   872  		nil,
   873  		new(trie.Trie),
   874  		extraData,
   875  		true,
   876  	)
   877  
   878  	blockBytes, err := rlp.EncodeToBytes(conflictingAtomicTxBlock)
   879  	if err != nil {
   880  		t.Fatal(err)
   881  	}
   882  
   883  	parsedBlock, err := vm.ParseBlock(blockBytes)
   884  	if err != nil {
   885  		t.Fatal(err)
   886  	}
   887  
   888  	if err := parsedBlock.Verify(); !errors.Is(err, errConflictingAtomicInputs) {
   889  		t.Fatalf("Expected to fail with err: %s, but found err: %s", errConflictingAtomicInputs, err)
   890  	}
   891  
   892  	if !rules.IsApricotPhase5 {
   893  		return
   894  	}
   895  
   896  	extraData, err = vm.codec.Marshal(codecVersion, []*Tx{importTxs[2], conflictTxs[2]})
   897  	if err != nil {
   898  		t.Fatal(err)
   899  	}
   900  
   901  	header := types.CopyHeader(validEthBlock.Header())
   902  	header.ExtDataGasUsed.Mul(common.Big2, header.ExtDataGasUsed)
   903  
   904  	internalConflictBlock := types.NewBlock(
   905  		header,
   906  		nil,
   907  		nil,
   908  		nil,
   909  		new(trie.Trie),
   910  		extraData,
   911  		true,
   912  	)
   913  
   914  	blockBytes, err = rlp.EncodeToBytes(internalConflictBlock)
   915  	if err != nil {
   916  		t.Fatal(err)
   917  	}
   918  
   919  	parsedBlock, err = vm.ParseBlock(blockBytes)
   920  	if err != nil {
   921  		t.Fatal(err)
   922  	}
   923  
   924  	if err := parsedBlock.Verify(); !errors.Is(err, errConflictingAtomicInputs) {
   925  		t.Fatalf("Expected to fail with err: %s, but found err: %s", errConflictingAtomicInputs, err)
   926  	}
   927  }
   928  
   929  func TestReissueAtomicTxHigherGasPrice(t *testing.T) {
   930  	kc := secp256k1fx.NewKeychain(testKeys...)
   931  
   932  	for name, issueTxs := range map[string]func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) (issued []*Tx, discarded []*Tx){
   933  		"single UTXO override": func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) (issued []*Tx, evicted []*Tx) {
   934  			utxo, err := addUTXO(sharedMemory, vm.ctx, ids.GenerateTestID(), 0, vm.ctx.AVAXAssetID, units.Avax, testShortIDAddrs[0])
   935  			if err != nil {
   936  				t.Fatal(err)
   937  			}
   938  			tx1, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, kc, []*avax.UTXO{utxo})
   939  			if err != nil {
   940  				t.Fatal(err)
   941  			}
   942  			tx2, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], new(big.Int).Mul(common.Big2, initialBaseFee), kc, []*avax.UTXO{utxo})
   943  			if err != nil {
   944  				t.Fatal(err)
   945  			}
   946  
   947  			if err := vm.issueTx(tx1, true); err != nil {
   948  				t.Fatal(err)
   949  			}
   950  			if err := vm.issueTx(tx2, true); err != nil {
   951  				t.Fatal(err)
   952  			}
   953  
   954  			return []*Tx{tx2}, []*Tx{tx1}
   955  		},
   956  		"one of two UTXOs overrides": func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) (issued []*Tx, evicted []*Tx) {
   957  			utxo1, err := addUTXO(sharedMemory, vm.ctx, ids.GenerateTestID(), 0, vm.ctx.AVAXAssetID, units.Avax, testShortIDAddrs[0])
   958  			if err != nil {
   959  				t.Fatal(err)
   960  			}
   961  			utxo2, err := addUTXO(sharedMemory, vm.ctx, ids.GenerateTestID(), 0, vm.ctx.AVAXAssetID, units.Avax, testShortIDAddrs[0])
   962  			if err != nil {
   963  				t.Fatal(err)
   964  			}
   965  			tx1, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, kc, []*avax.UTXO{utxo1, utxo2})
   966  			if err != nil {
   967  				t.Fatal(err)
   968  			}
   969  			tx2, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], new(big.Int).Mul(common.Big2, initialBaseFee), kc, []*avax.UTXO{utxo1})
   970  			if err != nil {
   971  				t.Fatal(err)
   972  			}
   973  
   974  			if err := vm.issueTx(tx1, true); err != nil {
   975  				t.Fatal(err)
   976  			}
   977  			if err := vm.issueTx(tx2, true); err != nil {
   978  				t.Fatal(err)
   979  			}
   980  
   981  			return []*Tx{tx2}, []*Tx{tx1}
   982  		},
   983  		"hola": func(t *testing.T, vm *VM, sharedMemory *atomic.Memory) (issued []*Tx, evicted []*Tx) {
   984  			utxo1, err := addUTXO(sharedMemory, vm.ctx, ids.GenerateTestID(), 0, vm.ctx.AVAXAssetID, units.Avax, testShortIDAddrs[0])
   985  			if err != nil {
   986  				t.Fatal(err)
   987  			}
   988  			utxo2, err := addUTXO(sharedMemory, vm.ctx, ids.GenerateTestID(), 0, vm.ctx.AVAXAssetID, units.Avax, testShortIDAddrs[0])
   989  			if err != nil {
   990  				t.Fatal(err)
   991  			}
   992  
   993  			importTx1, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, kc, []*avax.UTXO{utxo1})
   994  			if err != nil {
   995  				t.Fatal(err)
   996  			}
   997  
   998  			importTx2, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], new(big.Int).Mul(big.NewInt(3), initialBaseFee), kc, []*avax.UTXO{utxo2})
   999  			if err != nil {
  1000  				t.Fatal(err)
  1001  			}
  1002  
  1003  			reissuanceTx1, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], new(big.Int).Mul(big.NewInt(2), initialBaseFee), kc, []*avax.UTXO{utxo1, utxo2})
  1004  			if err != nil {
  1005  				t.Fatal(err)
  1006  			}
  1007  			if err := vm.issueTx(importTx1, true /*=local*/); err != nil {
  1008  				t.Fatal(err)
  1009  			}
  1010  
  1011  			if err := vm.issueTx(importTx2, true /*=local*/); err != nil {
  1012  				t.Fatal(err)
  1013  			}
  1014  
  1015  			if err := vm.issueTx(reissuanceTx1, true /*=local*/); !errors.Is(err, errConflictingAtomicTx) {
  1016  				t.Fatalf("Expected to fail with err: %s, but found err: %s", errConflictingAtomicTx, err)
  1017  			}
  1018  
  1019  			assert.True(t, vm.mempool.has(importTx1.ID()))
  1020  			assert.True(t, vm.mempool.has(importTx2.ID()))
  1021  			assert.False(t, vm.mempool.has(reissuanceTx1.ID()))
  1022  
  1023  			reissuanceTx2, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], new(big.Int).Mul(big.NewInt(4), initialBaseFee), kc, []*avax.UTXO{utxo1, utxo2})
  1024  			if err != nil {
  1025  				t.Fatal(err)
  1026  			}
  1027  			if err := vm.issueTx(reissuanceTx2, true /*=local*/); err != nil {
  1028  				t.Fatal(err)
  1029  			}
  1030  
  1031  			return []*Tx{reissuanceTx2}, []*Tx{importTx1, importTx2}
  1032  		},
  1033  	} {
  1034  		t.Run(name, func(t *testing.T) {
  1035  			_, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase5, "", "")
  1036  			issuedTxs, evictedTxs := issueTxs(t, vm, sharedMemory)
  1037  
  1038  			for i, tx := range issuedTxs {
  1039  				_, issued := vm.mempool.txHeap.Get(tx.ID())
  1040  				assert.True(t, issued, "expected issued tx at index %d to be issued", i)
  1041  			}
  1042  
  1043  			for i, tx := range evictedTxs {
  1044  				_, discarded := vm.mempool.discardedTxs.Get(tx.ID())
  1045  				assert.True(t, discarded, "expected discarded tx at index %d to be discarded", i)
  1046  			}
  1047  		})
  1048  	}
  1049  }
  1050  
  1051  func TestConflictingImportTxsAcrossBlocks(t *testing.T) {
  1052  	for name, genesis := range map[string]string{
  1053  		"apricotPhase1": genesisJSONApricotPhase1,
  1054  		"apricotPhase2": genesisJSONApricotPhase2,
  1055  		"apricotPhase3": genesisJSONApricotPhase3,
  1056  		"apricotPhase4": genesisJSONApricotPhase4,
  1057  		"apricotPhase5": genesisJSONApricotPhase5,
  1058  	} {
  1059  		t.Run(name, func(t *testing.T) {
  1060  			testConflictingImportTxs(t, genesis)
  1061  		})
  1062  	}
  1063  }
  1064  
  1065  // Regression test to ensure that after accepting block A
  1066  // then calling SetPreference on block B (when it becomes preferred)
  1067  // and the head of a longer chain (block D) does not corrupt the
  1068  // canonical chain.
  1069  //  A
  1070  // / \
  1071  // B  C
  1072  //    |
  1073  //    D
  1074  func TestSetPreferenceRace(t *testing.T) {
  1075  	// Create two VMs which will agree on block A and then
  1076  	// build the two distinct preferred chains above
  1077  	importAmount := uint64(1000000000)
  1078  	issuer1, vm1, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "{\"pruning-enabled\":true}", "", map[ids.ShortID]uint64{
  1079  		testShortIDAddrs[0]: importAmount,
  1080  	})
  1081  	issuer2, vm2, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "{\"pruning-enabled\":true}", "", map[ids.ShortID]uint64{
  1082  		testShortIDAddrs[0]: importAmount,
  1083  	})
  1084  
  1085  	defer func() {
  1086  		if err := vm1.Shutdown(); err != nil {
  1087  			t.Fatal(err)
  1088  		}
  1089  
  1090  		if err := vm2.Shutdown(); err != nil {
  1091  			t.Fatal(err)
  1092  		}
  1093  	}()
  1094  
  1095  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  1096  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  1097  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  1098  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  1099  
  1100  	importTx, err := vm1.newImportTx(vm1.ctx.XChainID, testEthAddrs[1], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1101  	if err != nil {
  1102  		t.Fatal(err)
  1103  	}
  1104  
  1105  	if err := vm1.issueTx(importTx, true /*=local*/); err != nil {
  1106  		t.Fatal(err)
  1107  	}
  1108  
  1109  	<-issuer1
  1110  
  1111  	vm1BlkA, err := vm1.BuildBlock()
  1112  	if err != nil {
  1113  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1114  	}
  1115  
  1116  	if err := vm1BlkA.Verify(); err != nil {
  1117  		t.Fatalf("Block failed verification on VM1: %s", err)
  1118  	}
  1119  
  1120  	if status := vm1BlkA.Status(); status != choices.Processing {
  1121  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1122  	}
  1123  
  1124  	if err := vm1.SetPreference(vm1BlkA.ID()); err != nil {
  1125  		t.Fatal(err)
  1126  	}
  1127  
  1128  	vm2BlkA, err := vm2.ParseBlock(vm1BlkA.Bytes())
  1129  	if err != nil {
  1130  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1131  	}
  1132  	if err := vm2BlkA.Verify(); err != nil {
  1133  		t.Fatalf("Block failed verification on VM2: %s", err)
  1134  	}
  1135  	if status := vm2BlkA.Status(); status != choices.Processing {
  1136  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1137  	}
  1138  	if err := vm2.SetPreference(vm2BlkA.ID()); err != nil {
  1139  		t.Fatal(err)
  1140  	}
  1141  
  1142  	if err := vm1BlkA.Accept(); err != nil {
  1143  		t.Fatalf("VM1 failed to accept block: %s", err)
  1144  	}
  1145  	if err := vm2BlkA.Accept(); err != nil {
  1146  		t.Fatalf("VM2 failed to accept block: %s", err)
  1147  	}
  1148  
  1149  	newHead := <-newTxPoolHeadChan1
  1150  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  1151  		t.Fatalf("Expected new block to match")
  1152  	}
  1153  	newHead = <-newTxPoolHeadChan2
  1154  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  1155  		t.Fatalf("Expected new block to match")
  1156  	}
  1157  
  1158  	// Create list of 10 successive transactions to build block A on vm1
  1159  	// and to be split into two separate blocks on VM2
  1160  	txs := make([]*types.Transaction, 10)
  1161  	for i := 0; i < 10; i++ {
  1162  		tx := types.NewTransaction(uint64(i), testEthAddrs[1], big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  1163  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainID), testKeys[1].ToECDSA())
  1164  		if err != nil {
  1165  			t.Fatal(err)
  1166  		}
  1167  		txs[i] = signedTx
  1168  	}
  1169  
  1170  	var errs []error
  1171  
  1172  	// Add the remote transactions, build the block, and set VM1's preference for block A
  1173  	errs = vm1.txPool.AddRemotesSync(txs)
  1174  	for i, err := range errs {
  1175  		if err != nil {
  1176  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  1177  		}
  1178  	}
  1179  
  1180  	<-issuer1
  1181  
  1182  	vm1BlkB, err := vm1.BuildBlock()
  1183  	if err != nil {
  1184  		t.Fatal(err)
  1185  	}
  1186  
  1187  	if err := vm1BlkB.Verify(); err != nil {
  1188  		t.Fatal(err)
  1189  	}
  1190  
  1191  	if status := vm1BlkB.Status(); status != choices.Processing {
  1192  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1193  	}
  1194  
  1195  	if err := vm1.SetPreference(vm1BlkB.ID()); err != nil {
  1196  		t.Fatal(err)
  1197  	}
  1198  
  1199  	// Split the transactions over two blocks, and set VM2's preference to them in sequence
  1200  	// after building each block
  1201  	// Block C
  1202  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  1203  	for i, err := range errs {
  1204  		if err != nil {
  1205  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1206  		}
  1207  	}
  1208  
  1209  	<-issuer2
  1210  	vm2BlkC, err := vm2.BuildBlock()
  1211  	if err != nil {
  1212  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  1213  	}
  1214  
  1215  	if err := vm2BlkC.Verify(); err != nil {
  1216  		t.Fatalf("BlkC failed verification on VM2: %s", err)
  1217  	}
  1218  
  1219  	if status := vm2BlkC.Status(); status != choices.Processing {
  1220  		t.Fatalf("Expected status of built block C to be %s, but found %s", choices.Processing, status)
  1221  	}
  1222  
  1223  	if err := vm2.SetPreference(vm2BlkC.ID()); err != nil {
  1224  		t.Fatal(err)
  1225  	}
  1226  
  1227  	newHead = <-newTxPoolHeadChan2
  1228  	if newHead.Head.Hash() != common.Hash(vm2BlkC.ID()) {
  1229  		t.Fatalf("Expected new block to match")
  1230  	}
  1231  
  1232  	// Block D
  1233  	errs = vm2.txPool.AddRemotesSync(txs[5:10])
  1234  	for i, err := range errs {
  1235  		if err != nil {
  1236  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1237  		}
  1238  	}
  1239  
  1240  	<-issuer2
  1241  	vm2BlkD, err := vm2.BuildBlock()
  1242  	if err != nil {
  1243  		t.Fatalf("Failed to build BlkD on VM2: %s", err)
  1244  	}
  1245  
  1246  	if err := vm2BlkD.Verify(); err != nil {
  1247  		t.Fatalf("BlkD failed verification on VM2: %s", err)
  1248  	}
  1249  
  1250  	if status := vm2BlkD.Status(); status != choices.Processing {
  1251  		t.Fatalf("Expected status of built block D to be %s, but found %s", choices.Processing, status)
  1252  	}
  1253  
  1254  	if err := vm2.SetPreference(vm2BlkD.ID()); err != nil {
  1255  		t.Fatal(err)
  1256  	}
  1257  
  1258  	// VM1 receives blkC and blkD from VM1
  1259  	// and happens to call SetPreference on blkD without ever calling SetPreference
  1260  	// on blkC
  1261  	// Here we parse them in reverse order to simulate receiving a chain from the tip
  1262  	// back to the last accepted block as would typically be the case in the consensus
  1263  	// engine
  1264  	vm1BlkD, err := vm1.ParseBlock(vm2BlkD.Bytes())
  1265  	if err != nil {
  1266  		t.Fatalf("VM1 errored parsing blkD: %s", err)
  1267  	}
  1268  	vm1BlkC, err := vm1.ParseBlock(vm2BlkC.Bytes())
  1269  	if err != nil {
  1270  		t.Fatalf("VM1 errored parsing blkC: %s", err)
  1271  	}
  1272  
  1273  	// The blocks must be verified in order. This invariant is maintained
  1274  	// in the consensus engine.
  1275  	if err := vm1BlkC.Verify(); err != nil {
  1276  		t.Fatalf("VM1 BlkC failed verification: %s", err)
  1277  	}
  1278  	if err := vm1BlkD.Verify(); err != nil {
  1279  		t.Fatalf("VM1 BlkD failed verification: %s", err)
  1280  	}
  1281  
  1282  	// Set VM1's preference to blockD, skipping blockC
  1283  	if err := vm1.SetPreference(vm1BlkD.ID()); err != nil {
  1284  		t.Fatal(err)
  1285  	}
  1286  
  1287  	// Accept the longer chain on both VMs and ensure there are no errors
  1288  	// VM1 Accepts the blocks in order
  1289  	if err := vm1BlkC.Accept(); err != nil {
  1290  		t.Fatalf("VM1 BlkC failed on accept: %s", err)
  1291  	}
  1292  	if err := vm1BlkD.Accept(); err != nil {
  1293  		t.Fatalf("VM1 BlkC failed on accept: %s", err)
  1294  	}
  1295  
  1296  	// VM2 Accepts the blocks in order
  1297  	if err := vm2BlkC.Accept(); err != nil {
  1298  		t.Fatalf("VM2 BlkC failed on accept: %s", err)
  1299  	}
  1300  	if err := vm2BlkD.Accept(); err != nil {
  1301  		t.Fatalf("VM2 BlkC failed on accept: %s", err)
  1302  	}
  1303  
  1304  	log.Info("Validating canonical chain")
  1305  	// Verify the Canonical Chain for Both VMs
  1306  	if err := vm2.blockChain.ValidateCanonicalChain(); err != nil {
  1307  		t.Fatalf("VM2 failed canonical chain verification due to: %s", err)
  1308  	}
  1309  
  1310  	if err := vm1.blockChain.ValidateCanonicalChain(); err != nil {
  1311  		t.Fatalf("VM1 failed canonical chain verification due to: %s", err)
  1312  	}
  1313  }
  1314  
  1315  func TestConflictingTransitiveAncestryWithGap(t *testing.T) {
  1316  	key, err := accountKeystore.NewKey(rand.Reader)
  1317  	if err != nil {
  1318  		t.Fatal(err)
  1319  	}
  1320  
  1321  	key0 := testKeys[0]
  1322  	addr0 := key0.PublicKey().Address()
  1323  
  1324  	key1 := testKeys[1]
  1325  	addr1 := key1.PublicKey().Address()
  1326  
  1327  	importAmount := uint64(1000000000)
  1328  
  1329  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "",
  1330  		map[ids.ShortID]uint64{
  1331  			addr0: importAmount,
  1332  			addr1: importAmount,
  1333  		})
  1334  
  1335  	defer func() {
  1336  		if err := vm.Shutdown(); err != nil {
  1337  			t.Fatal(err)
  1338  		}
  1339  	}()
  1340  
  1341  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  1342  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  1343  
  1344  	importTx0A, err := vm.newImportTx(vm.ctx.XChainID, key.Address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{key0})
  1345  	if err != nil {
  1346  		t.Fatal(err)
  1347  	}
  1348  	// Create a conflicting transaction
  1349  	importTx0B, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[2], initialBaseFee, []*crypto.PrivateKeySECP256K1R{key0})
  1350  	if err != nil {
  1351  		t.Fatal(err)
  1352  	}
  1353  
  1354  	if err := vm.issueTx(importTx0A, true /*=local*/); err != nil {
  1355  		t.Fatalf("Failed to issue importTx0A: %s", err)
  1356  	}
  1357  
  1358  	<-issuer
  1359  
  1360  	blk0, err := vm.BuildBlock()
  1361  	if err != nil {
  1362  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1363  	}
  1364  
  1365  	if err := blk0.Verify(); err != nil {
  1366  		t.Fatalf("Block failed verification: %s", err)
  1367  	}
  1368  
  1369  	if err := vm.SetPreference(blk0.ID()); err != nil {
  1370  		t.Fatal(err)
  1371  	}
  1372  
  1373  	newHead := <-newTxPoolHeadChan
  1374  	if newHead.Head.Hash() != common.Hash(blk0.ID()) {
  1375  		t.Fatalf("Expected new block to match")
  1376  	}
  1377  
  1378  	tx := types.NewTransaction(0, key.Address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  1379  	signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), key.PrivateKey)
  1380  	if err != nil {
  1381  		t.Fatal(err)
  1382  	}
  1383  
  1384  	// Add the remote transactions, build the block, and set VM1's preference for block A
  1385  	errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx})
  1386  	for i, err := range errs {
  1387  		if err != nil {
  1388  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  1389  		}
  1390  	}
  1391  
  1392  	<-issuer
  1393  
  1394  	blk1, err := vm.BuildBlock()
  1395  	if err != nil {
  1396  		t.Fatalf("Failed to build blk1: %s", err)
  1397  	}
  1398  
  1399  	if err := blk1.Verify(); err != nil {
  1400  		t.Fatalf("blk1 failed verification due to %s", err)
  1401  	}
  1402  
  1403  	if err := vm.SetPreference(blk1.ID()); err != nil {
  1404  		t.Fatal(err)
  1405  	}
  1406  
  1407  	importTx1, err := vm.newImportTx(vm.ctx.XChainID, key.Address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{key1})
  1408  	if err != nil {
  1409  		t.Fatalf("Failed to issue importTx1 due to: %s", err)
  1410  	}
  1411  
  1412  	if err := vm.issueTx(importTx1, true /*=local*/); err != nil {
  1413  		t.Fatal(err)
  1414  	}
  1415  
  1416  	<-issuer
  1417  
  1418  	blk2, err := vm.BuildBlock()
  1419  	if err != nil {
  1420  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1421  	}
  1422  
  1423  	if err := blk2.Verify(); err != nil {
  1424  		t.Fatalf("Block failed verification: %s", err)
  1425  	}
  1426  
  1427  	if err := vm.SetPreference(blk2.ID()); err != nil {
  1428  		t.Fatal(err)
  1429  	}
  1430  
  1431  	if err := vm.issueTx(importTx0B, true /*=local*/); err == nil {
  1432  		t.Fatalf("Should not have been able to issue import tx with conflict")
  1433  	}
  1434  	// Force issue transaction directly into the mempool
  1435  	if err := vm.mempool.ForceAddTx(importTx0B); err != nil {
  1436  		t.Fatal(err)
  1437  	}
  1438  	<-issuer
  1439  
  1440  	_, err = vm.BuildBlock()
  1441  	if err == nil {
  1442  		t.Fatal("Shouldn't have been able to build an invalid block")
  1443  	}
  1444  }
  1445  
  1446  func TestBonusBlocksTxs(t *testing.T) {
  1447  	issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase0, "", "")
  1448  
  1449  	defer func() {
  1450  		if err := vm.Shutdown(); err != nil {
  1451  			t.Fatal(err)
  1452  		}
  1453  	}()
  1454  
  1455  	importAmount := uint64(10000000)
  1456  	utxoID := avax.UTXOID{TxID: ids.GenerateTestID()}
  1457  
  1458  	utxo := &avax.UTXO{
  1459  		UTXOID: utxoID,
  1460  		Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
  1461  		Out: &secp256k1fx.TransferOutput{
  1462  			Amt: importAmount,
  1463  			OutputOwners: secp256k1fx.OutputOwners{
  1464  				Threshold: 1,
  1465  				Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
  1466  			},
  1467  		},
  1468  	}
  1469  	utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
  1470  	if err != nil {
  1471  		t.Fatal(err)
  1472  	}
  1473  
  1474  	xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
  1475  	inputID := utxo.InputID()
  1476  	if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{
  1477  		Key:   inputID[:],
  1478  		Value: utxoBytes,
  1479  		Traits: [][]byte{
  1480  			testKeys[0].PublicKey().Address().Bytes(),
  1481  		},
  1482  	}}}}); err != nil {
  1483  		t.Fatal(err)
  1484  	}
  1485  
  1486  	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1487  	if err != nil {
  1488  		t.Fatal(err)
  1489  	}
  1490  
  1491  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  1492  		t.Fatal(err)
  1493  	}
  1494  
  1495  	<-issuer
  1496  
  1497  	blk, err := vm.BuildBlock()
  1498  	if err != nil {
  1499  		t.Fatal(err)
  1500  	}
  1501  
  1502  	// Make [blk] a bonus block.
  1503  	vm.atomicBackend.(*atomicBackend).bonusBlocks = map[uint64]ids.ID{blk.Height(): blk.ID()}
  1504  
  1505  	// Remove the UTXOs from shared memory, so that non-bonus blocks will fail verification
  1506  	if err := vm.ctx.SharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.XChainID: {RemoveRequests: [][]byte{inputID[:]}}}); err != nil {
  1507  		t.Fatal(err)
  1508  	}
  1509  
  1510  	if err := blk.Verify(); err != nil {
  1511  		t.Fatal(err)
  1512  	}
  1513  
  1514  	if status := blk.Status(); status != choices.Processing {
  1515  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1516  	}
  1517  
  1518  	if err := vm.SetPreference(blk.ID()); err != nil {
  1519  		t.Fatal(err)
  1520  	}
  1521  
  1522  	if err := blk.Accept(); err != nil {
  1523  		t.Fatal(err)
  1524  	}
  1525  
  1526  	if status := blk.Status(); status != choices.Accepted {
  1527  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
  1528  	}
  1529  
  1530  	lastAcceptedID, err := vm.LastAccepted()
  1531  	if err != nil {
  1532  		t.Fatal(err)
  1533  	}
  1534  	if lastAcceptedID != blk.ID() {
  1535  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID)
  1536  	}
  1537  }
  1538  
  1539  // Regression test to ensure that a VM that accepts block A and B
  1540  // will not attempt to orphan either when verifying blocks C and D
  1541  // from another VM (which have a common ancestor under the finalized
  1542  // frontier).
  1543  //   A
  1544  //  / \
  1545  // B   C
  1546  //
  1547  // verifies block B and C, then Accepts block B. Then we test to ensure
  1548  // that the VM defends against any attempt to set the preference or to
  1549  // accept block C, which should be an orphaned block at this point and
  1550  // get rejected.
  1551  func TestReorgProtection(t *testing.T) {
  1552  	importAmount := uint64(1000000000)
  1553  	issuer1, vm1, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "{\"pruning-enabled\":false}", "", map[ids.ShortID]uint64{
  1554  		testShortIDAddrs[0]: importAmount,
  1555  	})
  1556  	issuer2, vm2, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "{\"pruning-enabled\":false}", "", map[ids.ShortID]uint64{
  1557  		testShortIDAddrs[0]: importAmount,
  1558  	})
  1559  
  1560  	defer func() {
  1561  		if err := vm1.Shutdown(); err != nil {
  1562  			t.Fatal(err)
  1563  		}
  1564  
  1565  		if err := vm2.Shutdown(); err != nil {
  1566  			t.Fatal(err)
  1567  		}
  1568  	}()
  1569  
  1570  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  1571  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  1572  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  1573  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  1574  
  1575  	key := testKeys[0].ToECDSA()
  1576  	address := testEthAddrs[0]
  1577  
  1578  	importTx, err := vm1.newImportTx(vm1.ctx.XChainID, address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1579  	if err != nil {
  1580  		t.Fatal(err)
  1581  	}
  1582  
  1583  	if err := vm1.issueTx(importTx, true /*=local*/); err != nil {
  1584  		t.Fatal(err)
  1585  	}
  1586  
  1587  	<-issuer1
  1588  
  1589  	vm1BlkA, err := vm1.BuildBlock()
  1590  	if err != nil {
  1591  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1592  	}
  1593  
  1594  	if err := vm1BlkA.Verify(); err != nil {
  1595  		t.Fatalf("Block failed verification on VM1: %s", err)
  1596  	}
  1597  
  1598  	if status := vm1BlkA.Status(); status != choices.Processing {
  1599  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1600  	}
  1601  
  1602  	if err := vm1.SetPreference(vm1BlkA.ID()); err != nil {
  1603  		t.Fatal(err)
  1604  	}
  1605  
  1606  	vm2BlkA, err := vm2.ParseBlock(vm1BlkA.Bytes())
  1607  	if err != nil {
  1608  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1609  	}
  1610  	if err := vm2BlkA.Verify(); err != nil {
  1611  		t.Fatalf("Block failed verification on VM2: %s", err)
  1612  	}
  1613  	if status := vm2BlkA.Status(); status != choices.Processing {
  1614  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1615  	}
  1616  	if err := vm2.SetPreference(vm2BlkA.ID()); err != nil {
  1617  		t.Fatal(err)
  1618  	}
  1619  
  1620  	if err := vm1BlkA.Accept(); err != nil {
  1621  		t.Fatalf("VM1 failed to accept block: %s", err)
  1622  	}
  1623  	if err := vm2BlkA.Accept(); err != nil {
  1624  		t.Fatalf("VM2 failed to accept block: %s", err)
  1625  	}
  1626  
  1627  	newHead := <-newTxPoolHeadChan1
  1628  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  1629  		t.Fatalf("Expected new block to match")
  1630  	}
  1631  	newHead = <-newTxPoolHeadChan2
  1632  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  1633  		t.Fatalf("Expected new block to match")
  1634  	}
  1635  
  1636  	// Create list of 10 successive transactions to build block A on vm1
  1637  	// and to be split into two separate blocks on VM2
  1638  	txs := make([]*types.Transaction, 10)
  1639  	for i := 0; i < 10; i++ {
  1640  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  1641  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainID), key)
  1642  		if err != nil {
  1643  			t.Fatal(err)
  1644  		}
  1645  		txs[i] = signedTx
  1646  	}
  1647  
  1648  	var errs []error
  1649  
  1650  	// Add the remote transactions, build the block, and set VM1's preference for block A
  1651  	errs = vm1.txPool.AddRemotesSync(txs)
  1652  	for i, err := range errs {
  1653  		if err != nil {
  1654  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  1655  		}
  1656  	}
  1657  
  1658  	<-issuer1
  1659  
  1660  	vm1BlkB, err := vm1.BuildBlock()
  1661  	if err != nil {
  1662  		t.Fatal(err)
  1663  	}
  1664  
  1665  	if err := vm1BlkB.Verify(); err != nil {
  1666  		t.Fatal(err)
  1667  	}
  1668  
  1669  	if status := vm1BlkB.Status(); status != choices.Processing {
  1670  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1671  	}
  1672  
  1673  	if err := vm1.SetPreference(vm1BlkB.ID()); err != nil {
  1674  		t.Fatal(err)
  1675  	}
  1676  
  1677  	// Split the transactions over two blocks, and set VM2's preference to them in sequence
  1678  	// after building each block
  1679  	// Block C
  1680  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  1681  	for i, err := range errs {
  1682  		if err != nil {
  1683  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1684  		}
  1685  	}
  1686  
  1687  	<-issuer2
  1688  	vm2BlkC, err := vm2.BuildBlock()
  1689  	if err != nil {
  1690  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  1691  	}
  1692  
  1693  	if err := vm2BlkC.Verify(); err != nil {
  1694  		t.Fatalf("Block failed verification on VM2: %s", err)
  1695  	}
  1696  	if status := vm2BlkC.Status(); status != choices.Processing {
  1697  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1698  	}
  1699  
  1700  	vm1BlkC, err := vm1.ParseBlock(vm2BlkC.Bytes())
  1701  	if err != nil {
  1702  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1703  	}
  1704  
  1705  	if err := vm1BlkC.Verify(); err != nil {
  1706  		t.Fatalf("Block failed verification on VM1: %s", err)
  1707  	}
  1708  
  1709  	// Accept B, such that block C should get Rejected.
  1710  	if err := vm1BlkB.Accept(); err != nil {
  1711  		t.Fatalf("VM1 failed to accept block: %s", err)
  1712  	}
  1713  
  1714  	// The below (setting preference blocks that have a common ancestor
  1715  	// with the preferred chain lower than the last finalized block)
  1716  	// should NEVER happen. However, the VM defends against this
  1717  	// just in case.
  1718  	if err := vm1.SetPreference(vm1BlkC.ID()); !strings.Contains(err.Error(), "cannot orphan finalized block") {
  1719  		t.Fatalf("Unexpected error when setting preference that would trigger reorg: %s", err)
  1720  	}
  1721  
  1722  	if err := vm1BlkC.Accept(); !strings.Contains(err.Error(), "expected accepted block to have parent") {
  1723  		t.Fatalf("Unexpected error when setting block at finalized height: %s", err)
  1724  	}
  1725  }
  1726  
  1727  // Regression test to ensure that a VM that accepts block C while preferring
  1728  // block B will trigger a reorg.
  1729  //   A
  1730  //  / \
  1731  // B   C
  1732  func TestNonCanonicalAccept(t *testing.T) {
  1733  	importAmount := uint64(1000000000)
  1734  	issuer1, vm1, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  1735  		testShortIDAddrs[0]: importAmount,
  1736  	})
  1737  	issuer2, vm2, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  1738  		testShortIDAddrs[0]: importAmount,
  1739  	})
  1740  
  1741  	defer func() {
  1742  		if err := vm1.Shutdown(); err != nil {
  1743  			t.Fatal(err)
  1744  		}
  1745  
  1746  		if err := vm2.Shutdown(); err != nil {
  1747  			t.Fatal(err)
  1748  		}
  1749  	}()
  1750  
  1751  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  1752  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  1753  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  1754  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  1755  
  1756  	key := testKeys[0].ToECDSA()
  1757  	address := testEthAddrs[0]
  1758  
  1759  	importTx, err := vm1.newImportTx(vm1.ctx.XChainID, address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1760  	if err != nil {
  1761  		t.Fatal(err)
  1762  	}
  1763  
  1764  	if err := vm1.issueTx(importTx, true /*=local*/); err != nil {
  1765  		t.Fatal(err)
  1766  	}
  1767  
  1768  	<-issuer1
  1769  
  1770  	vm1BlkA, err := vm1.BuildBlock()
  1771  	if err != nil {
  1772  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1773  	}
  1774  
  1775  	if err := vm1BlkA.Verify(); err != nil {
  1776  		t.Fatalf("Block failed verification on VM1: %s", err)
  1777  	}
  1778  
  1779  	if status := vm1BlkA.Status(); status != choices.Processing {
  1780  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1781  	}
  1782  
  1783  	if err := vm1.SetPreference(vm1BlkA.ID()); err != nil {
  1784  		t.Fatal(err)
  1785  	}
  1786  
  1787  	vm2BlkA, err := vm2.ParseBlock(vm1BlkA.Bytes())
  1788  	if err != nil {
  1789  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1790  	}
  1791  	if err := vm2BlkA.Verify(); err != nil {
  1792  		t.Fatalf("Block failed verification on VM2: %s", err)
  1793  	}
  1794  	if status := vm2BlkA.Status(); status != choices.Processing {
  1795  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1796  	}
  1797  	if err := vm2.SetPreference(vm2BlkA.ID()); err != nil {
  1798  		t.Fatal(err)
  1799  	}
  1800  
  1801  	if err := vm1BlkA.Accept(); err != nil {
  1802  		t.Fatalf("VM1 failed to accept block: %s", err)
  1803  	}
  1804  	if err := vm2BlkA.Accept(); err != nil {
  1805  		t.Fatalf("VM2 failed to accept block: %s", err)
  1806  	}
  1807  
  1808  	newHead := <-newTxPoolHeadChan1
  1809  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  1810  		t.Fatalf("Expected new block to match")
  1811  	}
  1812  	newHead = <-newTxPoolHeadChan2
  1813  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  1814  		t.Fatalf("Expected new block to match")
  1815  	}
  1816  
  1817  	// Create list of 10 successive transactions to build block A on vm1
  1818  	// and to be split into two separate blocks on VM2
  1819  	txs := make([]*types.Transaction, 10)
  1820  	for i := 0; i < 10; i++ {
  1821  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  1822  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainID), key)
  1823  		if err != nil {
  1824  			t.Fatal(err)
  1825  		}
  1826  		txs[i] = signedTx
  1827  	}
  1828  
  1829  	var errs []error
  1830  
  1831  	// Add the remote transactions, build the block, and set VM1's preference for block A
  1832  	errs = vm1.txPool.AddRemotesSync(txs)
  1833  	for i, err := range errs {
  1834  		if err != nil {
  1835  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  1836  		}
  1837  	}
  1838  
  1839  	<-issuer1
  1840  
  1841  	vm1BlkB, err := vm1.BuildBlock()
  1842  	if err != nil {
  1843  		t.Fatal(err)
  1844  	}
  1845  
  1846  	if err := vm1BlkB.Verify(); err != nil {
  1847  		t.Fatal(err)
  1848  	}
  1849  
  1850  	if status := vm1BlkB.Status(); status != choices.Processing {
  1851  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1852  	}
  1853  
  1854  	if err := vm1.SetPreference(vm1BlkB.ID()); err != nil {
  1855  		t.Fatal(err)
  1856  	}
  1857  
  1858  	vm1.blockChain.GetVMConfig().AllowUnfinalizedQueries = true
  1859  
  1860  	blkBHeight := vm1BlkB.Height()
  1861  	blkBHash := vm1BlkB.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1862  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkBHash {
  1863  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkBHash.Hex(), b.Hash().Hex())
  1864  	}
  1865  
  1866  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  1867  	for i, err := range errs {
  1868  		if err != nil {
  1869  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  1870  		}
  1871  	}
  1872  
  1873  	<-issuer2
  1874  	vm2BlkC, err := vm2.BuildBlock()
  1875  	if err != nil {
  1876  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  1877  	}
  1878  
  1879  	vm1BlkC, err := vm1.ParseBlock(vm2BlkC.Bytes())
  1880  	if err != nil {
  1881  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1882  	}
  1883  
  1884  	if err := vm1BlkC.Verify(); err != nil {
  1885  		t.Fatalf("Block failed verification on VM1: %s", err)
  1886  	}
  1887  
  1888  	if err := vm1BlkC.Accept(); err != nil {
  1889  		t.Fatalf("VM1 failed to accept block: %s", err)
  1890  	}
  1891  
  1892  	blkCHash := vm1BlkC.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  1893  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkCHash {
  1894  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkCHash.Hex(), b.Hash().Hex())
  1895  	}
  1896  }
  1897  
  1898  // Regression test to ensure that a VM that verifies block B, C, then
  1899  // D (preferring block B) does not trigger a reorg through the re-verification
  1900  // of block C or D.
  1901  //   A
  1902  //  / \
  1903  // B   C
  1904  //     |
  1905  //     D
  1906  func TestStickyPreference(t *testing.T) {
  1907  	importAmount := uint64(1000000000)
  1908  	issuer1, vm1, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  1909  		testShortIDAddrs[0]: importAmount,
  1910  	})
  1911  	issuer2, vm2, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  1912  		testShortIDAddrs[0]: importAmount,
  1913  	})
  1914  
  1915  	defer func() {
  1916  		if err := vm1.Shutdown(); err != nil {
  1917  			t.Fatal(err)
  1918  		}
  1919  
  1920  		if err := vm2.Shutdown(); err != nil {
  1921  			t.Fatal(err)
  1922  		}
  1923  	}()
  1924  
  1925  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  1926  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  1927  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  1928  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  1929  
  1930  	key := testKeys[0].ToECDSA()
  1931  	address := testEthAddrs[0]
  1932  
  1933  	importTx, err := vm1.newImportTx(vm1.ctx.XChainID, address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  1934  	if err != nil {
  1935  		t.Fatal(err)
  1936  	}
  1937  
  1938  	if err := vm1.issueTx(importTx, true /*=local*/); err != nil {
  1939  		t.Fatal(err)
  1940  	}
  1941  
  1942  	<-issuer1
  1943  
  1944  	vm1BlkA, err := vm1.BuildBlock()
  1945  	if err != nil {
  1946  		t.Fatalf("Failed to build block with import transaction: %s", err)
  1947  	}
  1948  
  1949  	if err := vm1BlkA.Verify(); err != nil {
  1950  		t.Fatalf("Block failed verification on VM1: %s", err)
  1951  	}
  1952  
  1953  	if status := vm1BlkA.Status(); status != choices.Processing {
  1954  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  1955  	}
  1956  
  1957  	if err := vm1.SetPreference(vm1BlkA.ID()); err != nil {
  1958  		t.Fatal(err)
  1959  	}
  1960  
  1961  	vm2BlkA, err := vm2.ParseBlock(vm1BlkA.Bytes())
  1962  	if err != nil {
  1963  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  1964  	}
  1965  	if err := vm2BlkA.Verify(); err != nil {
  1966  		t.Fatalf("Block failed verification on VM2: %s", err)
  1967  	}
  1968  	if status := vm2BlkA.Status(); status != choices.Processing {
  1969  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  1970  	}
  1971  	if err := vm2.SetPreference(vm2BlkA.ID()); err != nil {
  1972  		t.Fatal(err)
  1973  	}
  1974  
  1975  	if err := vm1BlkA.Accept(); err != nil {
  1976  		t.Fatalf("VM1 failed to accept block: %s", err)
  1977  	}
  1978  	if err := vm2BlkA.Accept(); err != nil {
  1979  		t.Fatalf("VM2 failed to accept block: %s", err)
  1980  	}
  1981  
  1982  	newHead := <-newTxPoolHeadChan1
  1983  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  1984  		t.Fatalf("Expected new block to match")
  1985  	}
  1986  	newHead = <-newTxPoolHeadChan2
  1987  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  1988  		t.Fatalf("Expected new block to match")
  1989  	}
  1990  
  1991  	// Create list of 10 successive transactions to build block A on vm1
  1992  	// and to be split into two separate blocks on VM2
  1993  	txs := make([]*types.Transaction, 10)
  1994  	for i := 0; i < 10; i++ {
  1995  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  1996  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainID), key)
  1997  		if err != nil {
  1998  			t.Fatal(err)
  1999  		}
  2000  		txs[i] = signedTx
  2001  	}
  2002  
  2003  	var errs []error
  2004  
  2005  	// Add the remote transactions, build the block, and set VM1's preference for block A
  2006  	errs = vm1.txPool.AddRemotesSync(txs)
  2007  	for i, err := range errs {
  2008  		if err != nil {
  2009  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  2010  		}
  2011  	}
  2012  
  2013  	<-issuer1
  2014  
  2015  	vm1BlkB, err := vm1.BuildBlock()
  2016  	if err != nil {
  2017  		t.Fatal(err)
  2018  	}
  2019  
  2020  	if err := vm1BlkB.Verify(); err != nil {
  2021  		t.Fatal(err)
  2022  	}
  2023  
  2024  	if status := vm1BlkB.Status(); status != choices.Processing {
  2025  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2026  	}
  2027  
  2028  	if err := vm1.SetPreference(vm1BlkB.ID()); err != nil {
  2029  		t.Fatal(err)
  2030  	}
  2031  
  2032  	vm1.blockChain.GetVMConfig().AllowUnfinalizedQueries = true
  2033  
  2034  	blkBHeight := vm1BlkB.Height()
  2035  	blkBHash := vm1BlkB.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  2036  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkBHash {
  2037  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkBHash.Hex(), b.Hash().Hex())
  2038  	}
  2039  
  2040  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  2041  	for i, err := range errs {
  2042  		if err != nil {
  2043  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  2044  		}
  2045  	}
  2046  
  2047  	<-issuer2
  2048  	vm2BlkC, err := vm2.BuildBlock()
  2049  	if err != nil {
  2050  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  2051  	}
  2052  
  2053  	if err := vm2BlkC.Verify(); err != nil {
  2054  		t.Fatalf("BlkC failed verification on VM2: %s", err)
  2055  	}
  2056  
  2057  	if status := vm2BlkC.Status(); status != choices.Processing {
  2058  		t.Fatalf("Expected status of built block C to be %s, but found %s", choices.Processing, status)
  2059  	}
  2060  
  2061  	if err := vm2.SetPreference(vm2BlkC.ID()); err != nil {
  2062  		t.Fatal(err)
  2063  	}
  2064  
  2065  	newHead = <-newTxPoolHeadChan2
  2066  	if newHead.Head.Hash() != common.Hash(vm2BlkC.ID()) {
  2067  		t.Fatalf("Expected new block to match")
  2068  	}
  2069  
  2070  	errs = vm2.txPool.AddRemotesSync(txs[5:])
  2071  	for i, err := range errs {
  2072  		if err != nil {
  2073  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  2074  		}
  2075  	}
  2076  
  2077  	<-issuer2
  2078  	vm2BlkD, err := vm2.BuildBlock()
  2079  	if err != nil {
  2080  		t.Fatalf("Failed to build BlkD on VM2: %s", err)
  2081  	}
  2082  
  2083  	// Parse blocks produced in vm2
  2084  	vm1BlkC, err := vm1.ParseBlock(vm2BlkC.Bytes())
  2085  	if err != nil {
  2086  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  2087  	}
  2088  	blkCHash := vm1BlkC.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  2089  
  2090  	vm1BlkD, err := vm1.ParseBlock(vm2BlkD.Bytes())
  2091  	if err != nil {
  2092  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  2093  	}
  2094  	blkDHeight := vm1BlkD.Height()
  2095  	blkDHash := vm1BlkD.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  2096  
  2097  	// Should be no-ops
  2098  	if err := vm1BlkC.Verify(); err != nil {
  2099  		t.Fatalf("Block failed verification on VM1: %s", err)
  2100  	}
  2101  	if err := vm1BlkD.Verify(); err != nil {
  2102  		t.Fatalf("Block failed verification on VM1: %s", err)
  2103  	}
  2104  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkBHash {
  2105  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkBHash.Hex(), b.Hash().Hex())
  2106  	}
  2107  	if b := vm1.blockChain.GetBlockByNumber(blkDHeight); b != nil {
  2108  		t.Fatalf("expected block at %d to be nil but got %s", blkDHeight, b.Hash().Hex())
  2109  	}
  2110  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkBHash {
  2111  		t.Fatalf("expected current block to have hash %s but got %s", blkBHash.Hex(), b.Hash().Hex())
  2112  	}
  2113  
  2114  	// Should still be no-ops on re-verify
  2115  	if err := vm1BlkC.Verify(); err != nil {
  2116  		t.Fatalf("Block failed verification on VM1: %s", err)
  2117  	}
  2118  	if err := vm1BlkD.Verify(); err != nil {
  2119  		t.Fatalf("Block failed verification on VM1: %s", err)
  2120  	}
  2121  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkBHash {
  2122  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkBHash.Hex(), b.Hash().Hex())
  2123  	}
  2124  	if b := vm1.blockChain.GetBlockByNumber(blkDHeight); b != nil {
  2125  		t.Fatalf("expected block at %d to be nil but got %s", blkDHeight, b.Hash().Hex())
  2126  	}
  2127  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkBHash {
  2128  		t.Fatalf("expected current block to have hash %s but got %s", blkBHash.Hex(), b.Hash().Hex())
  2129  	}
  2130  
  2131  	// Should be queryable after setting preference to side chain
  2132  	if err := vm1.SetPreference(vm1BlkD.ID()); err != nil {
  2133  		t.Fatal(err)
  2134  	}
  2135  
  2136  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkCHash {
  2137  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkCHash.Hex(), b.Hash().Hex())
  2138  	}
  2139  	if b := vm1.blockChain.GetBlockByNumber(blkDHeight); b.Hash() != blkDHash {
  2140  		t.Fatalf("expected block at %d to have hash %s but got %s", blkDHeight, blkDHash.Hex(), b.Hash().Hex())
  2141  	}
  2142  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkDHash {
  2143  		t.Fatalf("expected current block to have hash %s but got %s", blkDHash.Hex(), b.Hash().Hex())
  2144  	}
  2145  
  2146  	// Attempt to accept out of order
  2147  	if err := vm1BlkD.Accept(); !strings.Contains(err.Error(), "expected accepted block to have parent") {
  2148  		t.Fatalf("unexpected error when accepting out of order block: %s", err)
  2149  	}
  2150  
  2151  	// Accept in order
  2152  	if err := vm1BlkC.Accept(); err != nil {
  2153  		t.Fatalf("Block failed verification on VM1: %s", err)
  2154  	}
  2155  	if err := vm1BlkD.Accept(); err != nil {
  2156  		t.Fatalf("Block failed acceptance on VM1: %s", err)
  2157  	}
  2158  
  2159  	// Ensure queryable after accepting
  2160  	if b := vm1.blockChain.GetBlockByNumber(blkBHeight); b.Hash() != blkCHash {
  2161  		t.Fatalf("expected block at %d to have hash %s but got %s", blkBHeight, blkCHash.Hex(), b.Hash().Hex())
  2162  	}
  2163  	if b := vm1.blockChain.GetBlockByNumber(blkDHeight); b.Hash() != blkDHash {
  2164  		t.Fatalf("expected block at %d to have hash %s but got %s", blkDHeight, blkDHash.Hex(), b.Hash().Hex())
  2165  	}
  2166  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkDHash {
  2167  		t.Fatalf("expected current block to have hash %s but got %s", blkDHash.Hex(), b.Hash().Hex())
  2168  	}
  2169  }
  2170  
  2171  // Regression test to ensure that a VM that prefers block B is able to parse
  2172  // block C but unable to parse block D because it names B as an uncle, which
  2173  // are not supported.
  2174  //   A
  2175  //  / \
  2176  // B   C
  2177  //     |
  2178  //     D
  2179  func TestUncleBlock(t *testing.T) {
  2180  	importAmount := uint64(1000000000)
  2181  	issuer1, vm1, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  2182  		testShortIDAddrs[0]: importAmount,
  2183  	})
  2184  	issuer2, vm2, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  2185  		testShortIDAddrs[0]: importAmount,
  2186  	})
  2187  
  2188  	defer func() {
  2189  		if err := vm1.Shutdown(); err != nil {
  2190  			t.Fatal(err)
  2191  		}
  2192  		if err := vm2.Shutdown(); err != nil {
  2193  			t.Fatal(err)
  2194  		}
  2195  	}()
  2196  
  2197  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  2198  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  2199  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  2200  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  2201  
  2202  	key := testKeys[0].ToECDSA()
  2203  	address := testEthAddrs[0]
  2204  
  2205  	importTx, err := vm1.newImportTx(vm1.ctx.XChainID, address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  2206  	if err != nil {
  2207  		t.Fatal(err)
  2208  	}
  2209  
  2210  	if err := vm1.issueTx(importTx, true /*=local*/); err != nil {
  2211  		t.Fatal(err)
  2212  	}
  2213  
  2214  	<-issuer1
  2215  
  2216  	vm1BlkA, err := vm1.BuildBlock()
  2217  	if err != nil {
  2218  		t.Fatalf("Failed to build block with import transaction: %s", err)
  2219  	}
  2220  
  2221  	if err := vm1BlkA.Verify(); err != nil {
  2222  		t.Fatalf("Block failed verification on VM1: %s", err)
  2223  	}
  2224  
  2225  	if status := vm1BlkA.Status(); status != choices.Processing {
  2226  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2227  	}
  2228  
  2229  	if err := vm1.SetPreference(vm1BlkA.ID()); err != nil {
  2230  		t.Fatal(err)
  2231  	}
  2232  
  2233  	vm2BlkA, err := vm2.ParseBlock(vm1BlkA.Bytes())
  2234  	if err != nil {
  2235  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  2236  	}
  2237  	if err := vm2BlkA.Verify(); err != nil {
  2238  		t.Fatalf("Block failed verification on VM2: %s", err)
  2239  	}
  2240  	if status := vm2BlkA.Status(); status != choices.Processing {
  2241  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  2242  	}
  2243  	if err := vm2.SetPreference(vm2BlkA.ID()); err != nil {
  2244  		t.Fatal(err)
  2245  	}
  2246  
  2247  	if err := vm1BlkA.Accept(); err != nil {
  2248  		t.Fatalf("VM1 failed to accept block: %s", err)
  2249  	}
  2250  	if err := vm2BlkA.Accept(); err != nil {
  2251  		t.Fatalf("VM2 failed to accept block: %s", err)
  2252  	}
  2253  
  2254  	newHead := <-newTxPoolHeadChan1
  2255  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  2256  		t.Fatalf("Expected new block to match")
  2257  	}
  2258  	newHead = <-newTxPoolHeadChan2
  2259  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  2260  		t.Fatalf("Expected new block to match")
  2261  	}
  2262  
  2263  	txs := make([]*types.Transaction, 10)
  2264  	for i := 0; i < 10; i++ {
  2265  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  2266  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainID), key)
  2267  		if err != nil {
  2268  			t.Fatal(err)
  2269  		}
  2270  		txs[i] = signedTx
  2271  	}
  2272  
  2273  	var errs []error
  2274  
  2275  	errs = vm1.txPool.AddRemotesSync(txs)
  2276  	for i, err := range errs {
  2277  		if err != nil {
  2278  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  2279  		}
  2280  	}
  2281  
  2282  	<-issuer1
  2283  
  2284  	vm1BlkB, err := vm1.BuildBlock()
  2285  	if err != nil {
  2286  		t.Fatal(err)
  2287  	}
  2288  
  2289  	if err := vm1BlkB.Verify(); err != nil {
  2290  		t.Fatal(err)
  2291  	}
  2292  
  2293  	if status := vm1BlkB.Status(); status != choices.Processing {
  2294  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2295  	}
  2296  
  2297  	if err := vm1.SetPreference(vm1BlkB.ID()); err != nil {
  2298  		t.Fatal(err)
  2299  	}
  2300  
  2301  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  2302  	for i, err := range errs {
  2303  		if err != nil {
  2304  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  2305  		}
  2306  	}
  2307  
  2308  	<-issuer2
  2309  	vm2BlkC, err := vm2.BuildBlock()
  2310  	if err != nil {
  2311  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  2312  	}
  2313  
  2314  	if err := vm2BlkC.Verify(); err != nil {
  2315  		t.Fatalf("BlkC failed verification on VM2: %s", err)
  2316  	}
  2317  
  2318  	if status := vm2BlkC.Status(); status != choices.Processing {
  2319  		t.Fatalf("Expected status of built block C to be %s, but found %s", choices.Processing, status)
  2320  	}
  2321  
  2322  	if err := vm2.SetPreference(vm2BlkC.ID()); err != nil {
  2323  		t.Fatal(err)
  2324  	}
  2325  
  2326  	newHead = <-newTxPoolHeadChan2
  2327  	if newHead.Head.Hash() != common.Hash(vm2BlkC.ID()) {
  2328  		t.Fatalf("Expected new block to match")
  2329  	}
  2330  
  2331  	errs = vm2.txPool.AddRemotesSync(txs[5:10])
  2332  	for i, err := range errs {
  2333  		if err != nil {
  2334  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  2335  		}
  2336  	}
  2337  
  2338  	<-issuer2
  2339  	vm2BlkD, err := vm2.BuildBlock()
  2340  	if err != nil {
  2341  		t.Fatalf("Failed to build BlkD on VM2: %s", err)
  2342  	}
  2343  
  2344  	// Create uncle block from blkD
  2345  	blkDEthBlock := vm2BlkD.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2346  	uncles := []*types.Header{vm1BlkB.(*chain.BlockWrapper).Block.(*Block).ethBlock.Header()}
  2347  	uncleBlockHeader := types.CopyHeader(blkDEthBlock.Header())
  2348  	uncleBlockHeader.UncleHash = types.CalcUncleHash(uncles)
  2349  
  2350  	uncleEthBlock := types.NewBlock(
  2351  		uncleBlockHeader,
  2352  		blkDEthBlock.Transactions(),
  2353  		uncles,
  2354  		nil,
  2355  		new(trie.Trie),
  2356  		blkDEthBlock.ExtData(),
  2357  		false,
  2358  	)
  2359  	uncleBlock, err := vm2.newBlock(uncleEthBlock)
  2360  	if err != nil {
  2361  		t.Fatal(err)
  2362  	}
  2363  	if err := uncleBlock.Verify(); !errors.Is(err, errUnclesUnsupported) {
  2364  		t.Fatalf("VM2 should have failed with %q but got %q", errUnclesUnsupported, err.Error())
  2365  	}
  2366  	if _, err := vm1.ParseBlock(vm2BlkC.Bytes()); err != nil {
  2367  		t.Fatalf("VM1 errored parsing blkC: %s", err)
  2368  	}
  2369  	if _, err := vm1.ParseBlock(uncleBlock.Bytes()); !errors.Is(err, errUnclesUnsupported) {
  2370  		t.Fatalf("VM1 should have failed with %q but got %q", errUnclesUnsupported, err.Error())
  2371  	}
  2372  }
  2373  
  2374  // Regression test to ensure that a VM that is not able to parse a block that
  2375  // contains no transactions.
  2376  func TestEmptyBlock(t *testing.T) {
  2377  	importAmount := uint64(1000000000)
  2378  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  2379  		testShortIDAddrs[0]: importAmount,
  2380  	})
  2381  
  2382  	defer func() {
  2383  		if err := vm.Shutdown(); err != nil {
  2384  			t.Fatal(err)
  2385  		}
  2386  	}()
  2387  
  2388  	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  2389  	if err != nil {
  2390  		t.Fatal(err)
  2391  	}
  2392  
  2393  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  2394  		t.Fatal(err)
  2395  	}
  2396  
  2397  	<-issuer
  2398  
  2399  	blk, err := vm.BuildBlock()
  2400  	if err != nil {
  2401  		t.Fatalf("Failed to build block with import transaction: %s", err)
  2402  	}
  2403  
  2404  	// Create empty block from blkA
  2405  	ethBlock := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  2406  
  2407  	emptyEthBlock := types.NewBlock(
  2408  		types.CopyHeader(ethBlock.Header()),
  2409  		nil,
  2410  		nil,
  2411  		nil,
  2412  		new(trie.Trie),
  2413  		nil,
  2414  		false,
  2415  	)
  2416  
  2417  	if len(emptyEthBlock.ExtData()) != 0 || emptyEthBlock.Header().ExtDataHash != (common.Hash{}) {
  2418  		t.Fatalf("emptyEthBlock should not have any extra data")
  2419  	}
  2420  
  2421  	emptyBlock, err := vm.newBlock(emptyEthBlock)
  2422  	if err != nil {
  2423  		t.Fatal(err)
  2424  	}
  2425  
  2426  	if _, err := vm.ParseBlock(emptyBlock.Bytes()); !errors.Is(err, errEmptyBlock) {
  2427  		t.Fatalf("VM should have failed with errEmptyBlock but got %s", err.Error())
  2428  	}
  2429  	if err := emptyBlock.Verify(); !errors.Is(err, errEmptyBlock) {
  2430  		t.Fatalf("block should have failed verification with errEmptyBlock but got %s", err.Error())
  2431  	}
  2432  }
  2433  
  2434  // Regression test to ensure that a VM that verifies block B, C, then
  2435  // D (preferring block B) reorgs when C and then D are accepted.
  2436  //   A
  2437  //  / \
  2438  // B   C
  2439  //     |
  2440  //     D
  2441  func TestAcceptReorg(t *testing.T) {
  2442  	importAmount := uint64(1000000000)
  2443  	issuer1, vm1, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  2444  		testShortIDAddrs[0]: importAmount,
  2445  	})
  2446  	issuer2, vm2, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  2447  		testShortIDAddrs[0]: importAmount,
  2448  	})
  2449  
  2450  	defer func() {
  2451  		if err := vm1.Shutdown(); err != nil {
  2452  			t.Fatal(err)
  2453  		}
  2454  
  2455  		if err := vm2.Shutdown(); err != nil {
  2456  			t.Fatal(err)
  2457  		}
  2458  	}()
  2459  
  2460  	newTxPoolHeadChan1 := make(chan core.NewTxPoolReorgEvent, 1)
  2461  	vm1.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan1)
  2462  	newTxPoolHeadChan2 := make(chan core.NewTxPoolReorgEvent, 1)
  2463  	vm2.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan2)
  2464  
  2465  	key := testKeys[0].ToECDSA()
  2466  	address := testEthAddrs[0]
  2467  
  2468  	importTx, err := vm1.newImportTx(vm1.ctx.XChainID, address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  2469  	if err != nil {
  2470  		t.Fatal(err)
  2471  	}
  2472  
  2473  	if err := vm1.issueTx(importTx, true /*=local*/); err != nil {
  2474  		t.Fatal(err)
  2475  	}
  2476  
  2477  	<-issuer1
  2478  
  2479  	vm1BlkA, err := vm1.BuildBlock()
  2480  	if err != nil {
  2481  		t.Fatalf("Failed to build block with import transaction: %s", err)
  2482  	}
  2483  
  2484  	if err := vm1BlkA.Verify(); err != nil {
  2485  		t.Fatalf("Block failed verification on VM1: %s", err)
  2486  	}
  2487  
  2488  	if status := vm1BlkA.Status(); status != choices.Processing {
  2489  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2490  	}
  2491  
  2492  	if err := vm1.SetPreference(vm1BlkA.ID()); err != nil {
  2493  		t.Fatal(err)
  2494  	}
  2495  
  2496  	vm2BlkA, err := vm2.ParseBlock(vm1BlkA.Bytes())
  2497  	if err != nil {
  2498  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  2499  	}
  2500  	if err := vm2BlkA.Verify(); err != nil {
  2501  		t.Fatalf("Block failed verification on VM2: %s", err)
  2502  	}
  2503  	if status := vm2BlkA.Status(); status != choices.Processing {
  2504  		t.Fatalf("Expected status of block on VM2 to be %s, but found %s", choices.Processing, status)
  2505  	}
  2506  	if err := vm2.SetPreference(vm2BlkA.ID()); err != nil {
  2507  		t.Fatal(err)
  2508  	}
  2509  
  2510  	if err := vm1BlkA.Accept(); err != nil {
  2511  		t.Fatalf("VM1 failed to accept block: %s", err)
  2512  	}
  2513  	if err := vm2BlkA.Accept(); err != nil {
  2514  		t.Fatalf("VM2 failed to accept block: %s", err)
  2515  	}
  2516  
  2517  	newHead := <-newTxPoolHeadChan1
  2518  	if newHead.Head.Hash() != common.Hash(vm1BlkA.ID()) {
  2519  		t.Fatalf("Expected new block to match")
  2520  	}
  2521  	newHead = <-newTxPoolHeadChan2
  2522  	if newHead.Head.Hash() != common.Hash(vm2BlkA.ID()) {
  2523  		t.Fatalf("Expected new block to match")
  2524  	}
  2525  
  2526  	// Create list of 10 successive transactions to build block A on vm1
  2527  	// and to be split into two separate blocks on VM2
  2528  	txs := make([]*types.Transaction, 10)
  2529  	for i := 0; i < 10; i++ {
  2530  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  2531  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm1.chainID), key)
  2532  		if err != nil {
  2533  			t.Fatal(err)
  2534  		}
  2535  		txs[i] = signedTx
  2536  	}
  2537  
  2538  	// Add the remote transactions, build the block, and set VM1's preference
  2539  	// for block B
  2540  	errs := vm1.txPool.AddRemotesSync(txs)
  2541  	for i, err := range errs {
  2542  		if err != nil {
  2543  			t.Fatalf("Failed to add transaction to VM1 at index %d: %s", i, err)
  2544  		}
  2545  	}
  2546  
  2547  	<-issuer1
  2548  
  2549  	vm1BlkB, err := vm1.BuildBlock()
  2550  	if err != nil {
  2551  		t.Fatal(err)
  2552  	}
  2553  
  2554  	if err := vm1BlkB.Verify(); err != nil {
  2555  		t.Fatal(err)
  2556  	}
  2557  
  2558  	if status := vm1BlkB.Status(); status != choices.Processing {
  2559  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2560  	}
  2561  
  2562  	if err := vm1.SetPreference(vm1BlkB.ID()); err != nil {
  2563  		t.Fatal(err)
  2564  	}
  2565  
  2566  	errs = vm2.txPool.AddRemotesSync(txs[0:5])
  2567  	for i, err := range errs {
  2568  		if err != nil {
  2569  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  2570  		}
  2571  	}
  2572  
  2573  	<-issuer2
  2574  
  2575  	vm2BlkC, err := vm2.BuildBlock()
  2576  	if err != nil {
  2577  		t.Fatalf("Failed to build BlkC on VM2: %s", err)
  2578  	}
  2579  
  2580  	if err := vm2BlkC.Verify(); err != nil {
  2581  		t.Fatalf("BlkC failed verification on VM2: %s", err)
  2582  	}
  2583  
  2584  	if err := vm2.SetPreference(vm2BlkC.ID()); err != nil {
  2585  		t.Fatal(err)
  2586  	}
  2587  
  2588  	newHead = <-newTxPoolHeadChan2
  2589  	if newHead.Head.Hash() != common.Hash(vm2BlkC.ID()) {
  2590  		t.Fatalf("Expected new block to match")
  2591  	}
  2592  
  2593  	errs = vm2.txPool.AddRemotesSync(txs[5:])
  2594  	for i, err := range errs {
  2595  		if err != nil {
  2596  			t.Fatalf("Failed to add transaction to VM2 at index %d: %s", i, err)
  2597  		}
  2598  	}
  2599  
  2600  	<-issuer2
  2601  
  2602  	vm2BlkD, err := vm2.BuildBlock()
  2603  	if err != nil {
  2604  		t.Fatalf("Failed to build BlkD on VM2: %s", err)
  2605  	}
  2606  
  2607  	// Parse blocks produced in vm2
  2608  	vm1BlkC, err := vm1.ParseBlock(vm2BlkC.Bytes())
  2609  	if err != nil {
  2610  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  2611  	}
  2612  
  2613  	vm1BlkD, err := vm1.ParseBlock(vm2BlkD.Bytes())
  2614  	if err != nil {
  2615  		t.Fatalf("Unexpected error parsing block from vm2: %s", err)
  2616  	}
  2617  
  2618  	if err := vm1BlkC.Verify(); err != nil {
  2619  		t.Fatalf("Block failed verification on VM1: %s", err)
  2620  	}
  2621  	if err := vm1BlkD.Verify(); err != nil {
  2622  		t.Fatalf("Block failed verification on VM1: %s", err)
  2623  	}
  2624  
  2625  	blkBHash := vm1BlkB.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  2626  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkBHash {
  2627  		t.Fatalf("expected current block to have hash %s but got %s", blkBHash.Hex(), b.Hash().Hex())
  2628  	}
  2629  
  2630  	if err := vm1BlkC.Accept(); err != nil {
  2631  		t.Fatal(err)
  2632  	}
  2633  
  2634  	blkCHash := vm1BlkC.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  2635  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkCHash {
  2636  		t.Fatalf("expected current block to have hash %s but got %s", blkCHash.Hex(), b.Hash().Hex())
  2637  	}
  2638  	if err := vm1BlkB.Reject(); err != nil {
  2639  		t.Fatal(err)
  2640  	}
  2641  
  2642  	if err := vm1BlkD.Accept(); err != nil {
  2643  		t.Fatal(err)
  2644  	}
  2645  	blkDHash := vm1BlkD.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  2646  	if b := vm1.blockChain.CurrentBlock(); b.Hash() != blkDHash {
  2647  		t.Fatalf("expected current block to have hash %s but got %s", blkDHash.Hex(), b.Hash().Hex())
  2648  	}
  2649  }
  2650  
  2651  func TestFutureBlock(t *testing.T) {
  2652  	importAmount := uint64(1000000000)
  2653  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  2654  		testShortIDAddrs[0]: importAmount,
  2655  	})
  2656  
  2657  	defer func() {
  2658  		if err := vm.Shutdown(); err != nil {
  2659  			t.Fatal(err)
  2660  		}
  2661  	}()
  2662  
  2663  	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  2664  	if err != nil {
  2665  		t.Fatal(err)
  2666  	}
  2667  
  2668  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  2669  		t.Fatal(err)
  2670  	}
  2671  
  2672  	<-issuer
  2673  
  2674  	blkA, err := vm.BuildBlock()
  2675  	if err != nil {
  2676  		t.Fatalf("Failed to build block with import transaction: %s", err)
  2677  	}
  2678  
  2679  	// Create empty block from blkA
  2680  	internalBlkA := blkA.(*chain.BlockWrapper).Block.(*Block)
  2681  	modifiedHeader := types.CopyHeader(internalBlkA.ethBlock.Header())
  2682  	// Set the VM's clock to the time of the produced block
  2683  	vm.clock.Set(time.Unix(int64(modifiedHeader.Time), 0))
  2684  	// Set the modified time to exceed the allowed future time
  2685  	modifiedTime := modifiedHeader.Time + uint64(maxFutureBlockTime.Seconds()+1)
  2686  	modifiedHeader.Time = modifiedTime
  2687  	modifiedBlock := types.NewBlock(
  2688  		modifiedHeader,
  2689  		nil,
  2690  		nil,
  2691  		nil,
  2692  		new(trie.Trie),
  2693  		internalBlkA.ethBlock.ExtData(),
  2694  		false,
  2695  	)
  2696  
  2697  	futureBlock, err := vm.newBlock(modifiedBlock)
  2698  	if err != nil {
  2699  		t.Fatal(err)
  2700  	}
  2701  
  2702  	if err := futureBlock.Verify(); err == nil {
  2703  		t.Fatal("Future block should have failed verification due to block timestamp too far in the future")
  2704  	} else if !strings.Contains(err.Error(), "block timestamp is too far in the future") {
  2705  		t.Fatalf("Expected error to be block timestamp too far in the future but found %s", err)
  2706  	}
  2707  }
  2708  
  2709  // Regression test to ensure we can build blocks if we are starting with the
  2710  // Apricot Phase 1 ruleset in genesis.
  2711  func TestBuildApricotPhase1Block(t *testing.T) {
  2712  	importAmount := uint64(1000000000)
  2713  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase1, "", "", map[ids.ShortID]uint64{
  2714  		testShortIDAddrs[0]: importAmount,
  2715  	})
  2716  	defer func() {
  2717  		if err := vm.Shutdown(); err != nil {
  2718  			t.Fatal(err)
  2719  		}
  2720  	}()
  2721  
  2722  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  2723  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  2724  
  2725  	key := testKeys[0].ToECDSA()
  2726  	address := testEthAddrs[0]
  2727  
  2728  	importTx, err := vm.newImportTx(vm.ctx.XChainID, address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  2729  	if err != nil {
  2730  		t.Fatal(err)
  2731  	}
  2732  
  2733  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  2734  		t.Fatal(err)
  2735  	}
  2736  
  2737  	<-issuer
  2738  
  2739  	blk, err := vm.BuildBlock()
  2740  	if err != nil {
  2741  		t.Fatal(err)
  2742  	}
  2743  
  2744  	if err := blk.Verify(); err != nil {
  2745  		t.Fatal(err)
  2746  	}
  2747  
  2748  	if status := blk.Status(); status != choices.Processing {
  2749  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2750  	}
  2751  
  2752  	if err := vm.SetPreference(blk.ID()); err != nil {
  2753  		t.Fatal(err)
  2754  	}
  2755  
  2756  	if err := blk.Accept(); err != nil {
  2757  		t.Fatal(err)
  2758  	}
  2759  
  2760  	newHead := <-newTxPoolHeadChan
  2761  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  2762  		t.Fatalf("Expected new block to match")
  2763  	}
  2764  
  2765  	txs := make([]*types.Transaction, 10)
  2766  	for i := 0; i < 5; i++ {
  2767  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  2768  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), key)
  2769  		if err != nil {
  2770  			t.Fatal(err)
  2771  		}
  2772  		txs[i] = signedTx
  2773  	}
  2774  	for i := 5; i < 10; i++ {
  2775  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.ApricotPhase1MinGasPrice), nil)
  2776  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), key)
  2777  		if err != nil {
  2778  			t.Fatal(err)
  2779  		}
  2780  		txs[i] = signedTx
  2781  	}
  2782  	errs := vm.txPool.AddRemotesSync(txs)
  2783  	for i, err := range errs {
  2784  		if err != nil {
  2785  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  2786  		}
  2787  	}
  2788  
  2789  	<-issuer
  2790  
  2791  	blk, err = vm.BuildBlock()
  2792  	if err != nil {
  2793  		t.Fatal(err)
  2794  	}
  2795  
  2796  	if err := blk.Verify(); err != nil {
  2797  		t.Fatal(err)
  2798  	}
  2799  
  2800  	if status := blk.Status(); status != choices.Processing {
  2801  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2802  	}
  2803  
  2804  	if err := blk.Accept(); err != nil {
  2805  		t.Fatal(err)
  2806  	}
  2807  
  2808  	if status := blk.Status(); status != choices.Accepted {
  2809  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
  2810  	}
  2811  
  2812  	lastAcceptedID, err := vm.LastAccepted()
  2813  	if err != nil {
  2814  		t.Fatal(err)
  2815  	}
  2816  	if lastAcceptedID != blk.ID() {
  2817  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID)
  2818  	}
  2819  
  2820  	// Confirm all txs are present
  2821  	ethBlkTxs := vm.blockChain.GetBlockByNumber(2).Transactions()
  2822  	for i, tx := range txs {
  2823  		if len(ethBlkTxs) <= i {
  2824  			t.Fatalf("missing transactions expected: %d but found: %d", len(txs), len(ethBlkTxs))
  2825  		}
  2826  		if ethBlkTxs[i].Hash() != tx.Hash() {
  2827  			t.Fatalf("expected tx at index %d to have hash: %x but has: %x", i, txs[i].Hash(), tx.Hash())
  2828  		}
  2829  	}
  2830  }
  2831  
  2832  func TestLastAcceptedBlockNumberAllow(t *testing.T) {
  2833  	importAmount := uint64(1000000000)
  2834  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase0, "", "", map[ids.ShortID]uint64{
  2835  		testShortIDAddrs[0]: importAmount,
  2836  	})
  2837  
  2838  	defer func() {
  2839  		if err := vm.Shutdown(); err != nil {
  2840  			t.Fatal(err)
  2841  		}
  2842  	}()
  2843  
  2844  	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  2845  	if err != nil {
  2846  		t.Fatal(err)
  2847  	}
  2848  
  2849  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  2850  		t.Fatal(err)
  2851  	}
  2852  
  2853  	<-issuer
  2854  
  2855  	blk, err := vm.BuildBlock()
  2856  	if err != nil {
  2857  		t.Fatalf("Failed to build block with import transaction: %s", err)
  2858  	}
  2859  
  2860  	if err := blk.Verify(); err != nil {
  2861  		t.Fatalf("Block failed verification on VM: %s", err)
  2862  	}
  2863  
  2864  	if status := blk.Status(); status != choices.Processing {
  2865  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2866  	}
  2867  
  2868  	if err := vm.SetPreference(blk.ID()); err != nil {
  2869  		t.Fatal(err)
  2870  	}
  2871  
  2872  	blkHeight := blk.Height()
  2873  	blkHash := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock.Hash()
  2874  
  2875  	vm.blockChain.GetVMConfig().AllowUnfinalizedQueries = true
  2876  
  2877  	ctx := context.Background()
  2878  	b, err := vm.eth.APIBackend.BlockByNumber(ctx, rpc.BlockNumber(blkHeight))
  2879  	if err != nil {
  2880  		t.Fatal(err)
  2881  	}
  2882  	if b.Hash() != blkHash {
  2883  		t.Fatalf("expected block at %d to have hash %s but got %s", blkHeight, blkHash.Hex(), b.Hash().Hex())
  2884  	}
  2885  
  2886  	vm.blockChain.GetVMConfig().AllowUnfinalizedQueries = false
  2887  
  2888  	_, err = vm.eth.APIBackend.BlockByNumber(ctx, rpc.BlockNumber(blkHeight))
  2889  	if !errors.Is(err, eth.ErrUnfinalizedData) {
  2890  		t.Fatalf("expected ErrUnfinalizedData but got %s", err.Error())
  2891  	}
  2892  
  2893  	if err := blk.Accept(); err != nil {
  2894  		t.Fatalf("VM failed to accept block: %s", err)
  2895  	}
  2896  
  2897  	if b := vm.blockChain.GetBlockByNumber(blkHeight); b.Hash() != blkHash {
  2898  		t.Fatalf("expected block at %d to have hash %s but got %s", blkHeight, blkHash.Hex(), b.Hash().Hex())
  2899  	}
  2900  }
  2901  
  2902  // Builds [blkA] with a virtuous import transaction and [blkB] with a separate import transaction
  2903  // that does not conflict. Accepts [blkB] and rejects [blkA], then asserts that the virtuous atomic
  2904  // transaction in [blkA] is correctly re-issued into the atomic transaction mempool.
  2905  func TestReissueAtomicTx(t *testing.T) {
  2906  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase1, "", "", map[ids.ShortID]uint64{
  2907  		testShortIDAddrs[0]: 10000000,
  2908  		testShortIDAddrs[1]: 10000000,
  2909  	})
  2910  
  2911  	defer func() {
  2912  		if err := vm.Shutdown(); err != nil {
  2913  			t.Fatal(err)
  2914  		}
  2915  	}()
  2916  
  2917  	genesisBlkID, err := vm.LastAccepted()
  2918  	if err != nil {
  2919  		t.Fatal(err)
  2920  	}
  2921  
  2922  	importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  2923  	if err != nil {
  2924  		t.Fatal(err)
  2925  	}
  2926  
  2927  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  2928  		t.Fatal(err)
  2929  	}
  2930  
  2931  	<-issuer
  2932  
  2933  	blkA, err := vm.BuildBlock()
  2934  	if err != nil {
  2935  		t.Fatal(err)
  2936  	}
  2937  
  2938  	if status := blkA.Status(); status != choices.Processing {
  2939  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  2940  	}
  2941  
  2942  	if err := blkA.Verify(); err != nil {
  2943  		t.Fatal(err)
  2944  	}
  2945  
  2946  	if err := vm.SetPreference(blkA.ID()); err != nil {
  2947  		t.Fatal(err)
  2948  	}
  2949  
  2950  	// SetPreference to parent before rejecting (will rollback state to genesis
  2951  	// so that atomic transaction can be reissued, otherwise current block will
  2952  	// conflict with UTXO to be reissued)
  2953  	if err := vm.SetPreference(genesisBlkID); err != nil {
  2954  		t.Fatal(err)
  2955  	}
  2956  
  2957  	// Rejecting [blkA] should cause [importTx] to be re-issued into the mempool.
  2958  	if err := blkA.Reject(); err != nil {
  2959  		t.Fatal(err)
  2960  	}
  2961  
  2962  	// Sleep for a minimum of two seconds to ensure that [blkB] will have a different timestamp
  2963  	// than [blkA] so that the block will be unique. This is necessary since we have marked [blkA]
  2964  	// as Rejected.
  2965  	time.Sleep(2 * time.Second)
  2966  	<-issuer
  2967  	blkB, err := vm.BuildBlock()
  2968  	if err != nil {
  2969  		t.Fatal(err)
  2970  	}
  2971  
  2972  	if blkB.Height() != blkA.Height() {
  2973  		t.Fatalf("Expected blkB (%d) to have the same height as blkA (%d)", blkB.Height(), blkA.Height())
  2974  	}
  2975  	if status := blkA.Status(); status != choices.Rejected {
  2976  		t.Fatalf("Expected status of blkA to be %s, but found %s", choices.Rejected, status)
  2977  	}
  2978  	if status := blkB.Status(); status != choices.Processing {
  2979  		t.Fatalf("Expected status of blkB to be %s, but found %s", choices.Processing, status)
  2980  	}
  2981  
  2982  	if err := blkB.Verify(); err != nil {
  2983  		t.Fatal(err)
  2984  	}
  2985  
  2986  	if status := blkB.Status(); status != choices.Processing {
  2987  		t.Fatalf("Expected status of blkC to be %s, but found %s", choices.Processing, status)
  2988  	}
  2989  
  2990  	if err := vm.SetPreference(blkB.ID()); err != nil {
  2991  		t.Fatal(err)
  2992  	}
  2993  
  2994  	if err := blkB.Accept(); err != nil {
  2995  		t.Fatal(err)
  2996  	}
  2997  
  2998  	if status := blkB.Status(); status != choices.Accepted {
  2999  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
  3000  	}
  3001  
  3002  	if lastAcceptedID, err := vm.LastAccepted(); err != nil {
  3003  		t.Fatal(err)
  3004  	} else if lastAcceptedID != blkB.ID() {
  3005  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blkB.ID(), lastAcceptedID)
  3006  	}
  3007  
  3008  	// Check that [importTx] has been indexed correctly after [blkB] is accepted.
  3009  	_, height, err := vm.atomicTxRepository.GetByTxID(importTx.ID())
  3010  	if err != nil {
  3011  		t.Fatal(err)
  3012  	} else if height != blkB.Height() {
  3013  		t.Fatalf("Expected indexed height of import tx to be %d, but found %d", blkB.Height(), height)
  3014  	}
  3015  }
  3016  
  3017  func TestAtomicTxFailsEVMStateTransferBuildBlock(t *testing.T) {
  3018  	issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase1, "", "")
  3019  
  3020  	defer func() {
  3021  		if err := vm.Shutdown(); err != nil {
  3022  			t.Fatal(err)
  3023  		}
  3024  	}()
  3025  
  3026  	exportTxs := createExportTxOptions(t, vm, issuer, sharedMemory)
  3027  	exportTx1, exportTx2 := exportTxs[0], exportTxs[1]
  3028  
  3029  	if err := vm.issueTx(exportTx1, true /*=local*/); err != nil {
  3030  		t.Fatal(err)
  3031  	}
  3032  	<-issuer
  3033  	exportBlk1, err := vm.BuildBlock()
  3034  	if err != nil {
  3035  		t.Fatal(err)
  3036  	}
  3037  	if err := exportBlk1.Verify(); err != nil {
  3038  		t.Fatal(err)
  3039  	}
  3040  
  3041  	if err := vm.SetPreference(exportBlk1.ID()); err != nil {
  3042  		t.Fatal(err)
  3043  	}
  3044  
  3045  	if err := vm.issueTx(exportTx2, true /*=local*/); err == nil {
  3046  		t.Fatal("Should have failed to issue due to an invalid export tx")
  3047  	}
  3048  
  3049  	if err := vm.mempool.AddTx(exportTx2); err == nil {
  3050  		t.Fatal("Should have failed to add because conflicting")
  3051  	}
  3052  
  3053  	// Manually add transaction to mempool to bypass validation
  3054  	if err := vm.mempool.ForceAddTx(exportTx2); err != nil {
  3055  		t.Fatal(err)
  3056  	}
  3057  	<-issuer
  3058  
  3059  	_, err = vm.BuildBlock()
  3060  	if err == nil {
  3061  		t.Fatal("BuildBlock should have returned an error due to invalid export transaction")
  3062  	}
  3063  }
  3064  
  3065  func TestBuildInvalidBlockHead(t *testing.T) {
  3066  	issuer, vm, _, _, _ := GenesisVM(t, true, genesisJSONApricotPhase0, "", "")
  3067  
  3068  	defer func() {
  3069  		if err := vm.Shutdown(); err != nil {
  3070  			t.Fatal(err)
  3071  		}
  3072  	}()
  3073  
  3074  	key0 := testKeys[0]
  3075  	addr0 := key0.PublicKey().Address()
  3076  
  3077  	// Create the transaction
  3078  	utx := &UnsignedImportTx{
  3079  		NetworkID:    vm.ctx.NetworkID,
  3080  		BlockchainID: vm.ctx.ChainID,
  3081  		Outs: []EVMOutput{{
  3082  			Address: common.Address(addr0),
  3083  			Amount:  1 * units.Avax,
  3084  			AssetID: vm.ctx.AVAXAssetID,
  3085  		}},
  3086  		ImportedInputs: []*avax.TransferableInput{
  3087  			{
  3088  				Asset: avax.Asset{ID: vm.ctx.AVAXAssetID},
  3089  				In: &secp256k1fx.TransferInput{
  3090  					Amt: 1 * units.Avax,
  3091  					Input: secp256k1fx.Input{
  3092  						SigIndices: []uint32{0},
  3093  					},
  3094  				},
  3095  			},
  3096  		},
  3097  		SourceChain: vm.ctx.XChainID,
  3098  	}
  3099  	tx := &Tx{UnsignedAtomicTx: utx}
  3100  	if err := tx.Sign(vm.codec, [][]*crypto.PrivateKeySECP256K1R{{key0}}); err != nil {
  3101  		t.Fatal(err)
  3102  	}
  3103  
  3104  	currentBlock := vm.blockChain.CurrentBlock()
  3105  
  3106  	// Verify that the transaction fails verification when attempting to issue
  3107  	// it into the atomic mempool.
  3108  	if err := vm.issueTx(tx, true /*=local*/); err == nil {
  3109  		t.Fatal("Should have failed to issue invalid transaction")
  3110  	}
  3111  	// Force issue the transaction directly to the mempool
  3112  	if err := vm.mempool.AddTx(tx); err != nil {
  3113  		t.Fatal(err)
  3114  	}
  3115  
  3116  	<-issuer
  3117  
  3118  	if _, err := vm.BuildBlock(); err == nil {
  3119  		t.Fatalf("Unexpectedly created a block")
  3120  	}
  3121  
  3122  	newCurrentBlock := vm.blockChain.CurrentBlock()
  3123  
  3124  	if currentBlock.Hash() != newCurrentBlock.Hash() {
  3125  		t.Fatal("current block changed")
  3126  	}
  3127  }
  3128  
  3129  func TestConfigureLogLevel(t *testing.T) {
  3130  	configTests := []struct {
  3131  		name                     string
  3132  		logConfig                string
  3133  		genesisJSON, upgradeJSON string
  3134  		expectedErr              string
  3135  	}{
  3136  		{
  3137  			name:        "Log level info",
  3138  			logConfig:   "{\"log-level\": \"info\"}",
  3139  			genesisJSON: genesisJSONApricotPhase2,
  3140  			upgradeJSON: "",
  3141  			expectedErr: "",
  3142  		},
  3143  		{
  3144  			name:        "Invalid log level",
  3145  			logConfig:   "{\"log-level\": \"cchain\"}",
  3146  			genesisJSON: genesisJSONApricotPhase3,
  3147  			upgradeJSON: "",
  3148  			expectedErr: "failed to initialize logger due to",
  3149  		},
  3150  	}
  3151  	for _, test := range configTests {
  3152  		t.Run(test.name, func(t *testing.T) {
  3153  			vm := &VM{}
  3154  			ctx, dbManager, genesisBytes, issuer, _ := setupGenesis(t, test.genesisJSON)
  3155  			appSender := &engCommon.SenderTest{T: t}
  3156  			appSender.CantSendAppGossip = true
  3157  			appSender.SendAppGossipF = func([]byte) error { return nil }
  3158  			err := vm.Initialize(
  3159  				ctx,
  3160  				dbManager,
  3161  				genesisBytes,
  3162  				[]byte(""),
  3163  				[]byte(test.logConfig),
  3164  				issuer,
  3165  				[]*engCommon.Fx{},
  3166  				appSender,
  3167  			)
  3168  			if len(test.expectedErr) == 0 && err != nil {
  3169  				t.Fatal(err)
  3170  			} else if len(test.expectedErr) > 0 {
  3171  				if err == nil {
  3172  					t.Fatalf("initialize should have failed due to %s", test.expectedErr)
  3173  				} else if !strings.Contains(err.Error(), test.expectedErr) {
  3174  					t.Fatalf("Expected initialize to fail due to %s, but failed with %s", test.expectedErr, err.Error())
  3175  				}
  3176  			}
  3177  
  3178  			// If the VM was not initialized, do not attept to shut it down
  3179  			if err == nil {
  3180  				shutdownChan := make(chan error, 1)
  3181  				shutdownFunc := func() {
  3182  					err := vm.Shutdown()
  3183  					shutdownChan <- err
  3184  				}
  3185  				go shutdownFunc()
  3186  
  3187  				shutdownTimeout := 50 * time.Millisecond
  3188  				ticker := time.NewTicker(shutdownTimeout)
  3189  				select {
  3190  				case <-ticker.C:
  3191  					t.Fatalf("VM shutdown took longer than timeout: %v", shutdownTimeout)
  3192  				case err := <-shutdownChan:
  3193  					if err != nil {
  3194  						t.Fatalf("Shutdown errored: %s", err)
  3195  					}
  3196  				}
  3197  			}
  3198  		})
  3199  	}
  3200  }
  3201  
  3202  // Regression test to ensure we can build blocks if we are starting with the
  3203  // Apricot Phase 4 ruleset in genesis.
  3204  func TestBuildApricotPhase4Block(t *testing.T) {
  3205  	issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase4, "", "")
  3206  
  3207  	defer func() {
  3208  		if err := vm.Shutdown(); err != nil {
  3209  			t.Fatal(err)
  3210  		}
  3211  	}()
  3212  
  3213  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  3214  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  3215  
  3216  	key := testKeys[0].ToECDSA()
  3217  	address := testEthAddrs[0]
  3218  
  3219  	importAmount := uint64(1000000000)
  3220  	utxoID := avax.UTXOID{TxID: ids.GenerateTestID()}
  3221  
  3222  	utxo := &avax.UTXO{
  3223  		UTXOID: utxoID,
  3224  		Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
  3225  		Out: &secp256k1fx.TransferOutput{
  3226  			Amt: importAmount,
  3227  			OutputOwners: secp256k1fx.OutputOwners{
  3228  				Threshold: 1,
  3229  				Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
  3230  			},
  3231  		},
  3232  	}
  3233  	utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
  3234  	if err != nil {
  3235  		t.Fatal(err)
  3236  	}
  3237  
  3238  	xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
  3239  	inputID := utxo.InputID()
  3240  	if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{
  3241  		Key:   inputID[:],
  3242  		Value: utxoBytes,
  3243  		Traits: [][]byte{
  3244  			testKeys[0].PublicKey().Address().Bytes(),
  3245  		},
  3246  	}}}}); err != nil {
  3247  		t.Fatal(err)
  3248  	}
  3249  
  3250  	importTx, err := vm.newImportTx(vm.ctx.XChainID, address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  3251  	if err != nil {
  3252  		t.Fatal(err)
  3253  	}
  3254  
  3255  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  3256  		t.Fatal(err)
  3257  	}
  3258  
  3259  	<-issuer
  3260  
  3261  	blk, err := vm.BuildBlock()
  3262  	if err != nil {
  3263  		t.Fatal(err)
  3264  	}
  3265  
  3266  	if err := blk.Verify(); err != nil {
  3267  		t.Fatal(err)
  3268  	}
  3269  
  3270  	if status := blk.Status(); status != choices.Processing {
  3271  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  3272  	}
  3273  
  3274  	if err := vm.SetPreference(blk.ID()); err != nil {
  3275  		t.Fatal(err)
  3276  	}
  3277  
  3278  	if err := blk.Accept(); err != nil {
  3279  		t.Fatal(err)
  3280  	}
  3281  
  3282  	ethBlk := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  3283  	if eBlockGasCost := ethBlk.BlockGasCost(); eBlockGasCost == nil || eBlockGasCost.Cmp(common.Big0) != 0 {
  3284  		t.Fatalf("expected blockGasCost to be 0 but got %d", eBlockGasCost)
  3285  	}
  3286  	if eExtDataGasUsed := ethBlk.ExtDataGasUsed(); eExtDataGasUsed == nil || eExtDataGasUsed.Cmp(big.NewInt(1230)) != 0 {
  3287  		t.Fatalf("expected extDataGasUsed to be 1000 but got %d", eExtDataGasUsed)
  3288  	}
  3289  	minRequiredTip, err := dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header())
  3290  	if err != nil {
  3291  		t.Fatal(err)
  3292  	}
  3293  	if minRequiredTip == nil || minRequiredTip.Cmp(common.Big0) != 0 {
  3294  		t.Fatalf("expected minRequiredTip to be 0 but got %d", minRequiredTip)
  3295  	}
  3296  
  3297  	newHead := <-newTxPoolHeadChan
  3298  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  3299  		t.Fatalf("Expected new block to match")
  3300  	}
  3301  
  3302  	txs := make([]*types.Transaction, 10)
  3303  	for i := 0; i < 5; i++ {
  3304  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice), nil)
  3305  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), key)
  3306  		if err != nil {
  3307  			t.Fatal(err)
  3308  		}
  3309  		txs[i] = signedTx
  3310  	}
  3311  	for i := 5; i < 10; i++ {
  3312  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.ApricotPhase1MinGasPrice), nil)
  3313  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), key)
  3314  		if err != nil {
  3315  			t.Fatal(err)
  3316  		}
  3317  		txs[i] = signedTx
  3318  	}
  3319  	errs := vm.txPool.AddRemotes(txs)
  3320  	for i, err := range errs {
  3321  		if err != nil {
  3322  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  3323  		}
  3324  	}
  3325  
  3326  	<-issuer
  3327  
  3328  	blk, err = vm.BuildBlock()
  3329  	if err != nil {
  3330  		t.Fatal(err)
  3331  	}
  3332  
  3333  	if err := blk.Verify(); err != nil {
  3334  		t.Fatal(err)
  3335  	}
  3336  
  3337  	if status := blk.Status(); status != choices.Processing {
  3338  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  3339  	}
  3340  
  3341  	if err := blk.Accept(); err != nil {
  3342  		t.Fatal(err)
  3343  	}
  3344  
  3345  	ethBlk = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  3346  	if ethBlk.BlockGasCost() == nil || ethBlk.BlockGasCost().Cmp(big.NewInt(100)) < 0 {
  3347  		t.Fatalf("expected blockGasCost to be at least 100 but got %d", ethBlk.BlockGasCost())
  3348  	}
  3349  	if ethBlk.ExtDataGasUsed() == nil || ethBlk.ExtDataGasUsed().Cmp(common.Big0) != 0 {
  3350  		t.Fatalf("expected extDataGasUsed to be 0 but got %d", ethBlk.ExtDataGasUsed())
  3351  	}
  3352  	minRequiredTip, err = dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header())
  3353  	if err != nil {
  3354  		t.Fatal(err)
  3355  	}
  3356  	if minRequiredTip == nil || minRequiredTip.Cmp(big.NewInt(0.05*params.GWei)) < 0 {
  3357  		t.Fatalf("expected minRequiredTip to be at least 0.05 gwei but got %d", minRequiredTip)
  3358  	}
  3359  
  3360  	if status := blk.Status(); status != choices.Accepted {
  3361  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
  3362  	}
  3363  
  3364  	lastAcceptedID, err := vm.LastAccepted()
  3365  	if err != nil {
  3366  		t.Fatal(err)
  3367  	}
  3368  	if lastAcceptedID != blk.ID() {
  3369  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID)
  3370  	}
  3371  
  3372  	// Confirm all txs are present
  3373  	ethBlkTxs := vm.blockChain.GetBlockByNumber(2).Transactions()
  3374  	for i, tx := range txs {
  3375  		if len(ethBlkTxs) <= i {
  3376  			t.Fatalf("missing transactions expected: %d but found: %d", len(txs), len(ethBlkTxs))
  3377  		}
  3378  		if ethBlkTxs[i].Hash() != tx.Hash() {
  3379  			t.Fatalf("expected tx at index %d to have hash: %x but has: %x", i, txs[i].Hash(), tx.Hash())
  3380  		}
  3381  	}
  3382  }
  3383  
  3384  // Regression test to ensure we can build blocks if we are starting with the
  3385  // Apricot Phase 5 ruleset in genesis.
  3386  func TestBuildApricotPhase5Block(t *testing.T) {
  3387  	issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase5, "", "")
  3388  
  3389  	defer func() {
  3390  		if err := vm.Shutdown(); err != nil {
  3391  			t.Fatal(err)
  3392  		}
  3393  	}()
  3394  
  3395  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  3396  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  3397  
  3398  	key := testKeys[0].ToECDSA()
  3399  	address := testEthAddrs[0]
  3400  
  3401  	importAmount := uint64(1000000000)
  3402  	utxoID := avax.UTXOID{TxID: ids.GenerateTestID()}
  3403  
  3404  	utxo := &avax.UTXO{
  3405  		UTXOID: utxoID,
  3406  		Asset:  avax.Asset{ID: vm.ctx.AVAXAssetID},
  3407  		Out: &secp256k1fx.TransferOutput{
  3408  			Amt: importAmount,
  3409  			OutputOwners: secp256k1fx.OutputOwners{
  3410  				Threshold: 1,
  3411  				Addrs:     []ids.ShortID{testKeys[0].PublicKey().Address()},
  3412  			},
  3413  		},
  3414  	}
  3415  	utxoBytes, err := vm.codec.Marshal(codecVersion, utxo)
  3416  	if err != nil {
  3417  		t.Fatal(err)
  3418  	}
  3419  
  3420  	xChainSharedMemory := sharedMemory.NewSharedMemory(vm.ctx.XChainID)
  3421  	inputID := utxo.InputID()
  3422  	if err := xChainSharedMemory.Apply(map[ids.ID]*atomic.Requests{vm.ctx.ChainID: {PutRequests: []*atomic.Element{{
  3423  		Key:   inputID[:],
  3424  		Value: utxoBytes,
  3425  		Traits: [][]byte{
  3426  			testKeys[0].PublicKey().Address().Bytes(),
  3427  		},
  3428  	}}}}); err != nil {
  3429  		t.Fatal(err)
  3430  	}
  3431  
  3432  	importTx, err := vm.newImportTx(vm.ctx.XChainID, address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  3433  	if err != nil {
  3434  		t.Fatal(err)
  3435  	}
  3436  
  3437  	if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  3438  		t.Fatal(err)
  3439  	}
  3440  
  3441  	<-issuer
  3442  
  3443  	blk, err := vm.BuildBlock()
  3444  	if err != nil {
  3445  		t.Fatal(err)
  3446  	}
  3447  
  3448  	if err := blk.Verify(); err != nil {
  3449  		t.Fatal(err)
  3450  	}
  3451  
  3452  	if status := blk.Status(); status != choices.Processing {
  3453  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  3454  	}
  3455  
  3456  	if err := vm.SetPreference(blk.ID()); err != nil {
  3457  		t.Fatal(err)
  3458  	}
  3459  
  3460  	if err := blk.Accept(); err != nil {
  3461  		t.Fatal(err)
  3462  	}
  3463  
  3464  	ethBlk := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  3465  	if eBlockGasCost := ethBlk.BlockGasCost(); eBlockGasCost == nil || eBlockGasCost.Cmp(common.Big0) != 0 {
  3466  		t.Fatalf("expected blockGasCost to be 0 but got %d", eBlockGasCost)
  3467  	}
  3468  	if eExtDataGasUsed := ethBlk.ExtDataGasUsed(); eExtDataGasUsed == nil || eExtDataGasUsed.Cmp(big.NewInt(11230)) != 0 {
  3469  		t.Fatalf("expected extDataGasUsed to be 11230 but got %d", eExtDataGasUsed)
  3470  	}
  3471  	minRequiredTip, err := dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header())
  3472  	if err != nil {
  3473  		t.Fatal(err)
  3474  	}
  3475  	if minRequiredTip == nil || minRequiredTip.Cmp(common.Big0) != 0 {
  3476  		t.Fatalf("expected minRequiredTip to be 0 but got %d", minRequiredTip)
  3477  	}
  3478  
  3479  	newHead := <-newTxPoolHeadChan
  3480  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  3481  		t.Fatalf("Expected new block to match")
  3482  	}
  3483  
  3484  	txs := make([]*types.Transaction, 10)
  3485  	for i := 0; i < 10; i++ {
  3486  		tx := types.NewTransaction(uint64(i), address, big.NewInt(10), 21000, big.NewInt(params.LaunchMinGasPrice*3), nil)
  3487  		signedTx, err := types.SignTx(tx, types.NewEIP155Signer(vm.chainID), key)
  3488  		if err != nil {
  3489  			t.Fatal(err)
  3490  		}
  3491  		txs[i] = signedTx
  3492  	}
  3493  	errs := vm.txPool.AddRemotes(txs)
  3494  	for i, err := range errs {
  3495  		if err != nil {
  3496  			t.Fatalf("Failed to add tx at index %d: %s", i, err)
  3497  		}
  3498  	}
  3499  
  3500  	<-issuer
  3501  
  3502  	blk, err = vm.BuildBlock()
  3503  	if err != nil {
  3504  		t.Fatal(err)
  3505  	}
  3506  
  3507  	if err := blk.Verify(); err != nil {
  3508  		t.Fatal(err)
  3509  	}
  3510  
  3511  	if status := blk.Status(); status != choices.Processing {
  3512  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  3513  	}
  3514  
  3515  	if err := blk.Accept(); err != nil {
  3516  		t.Fatal(err)
  3517  	}
  3518  
  3519  	ethBlk = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock
  3520  	if ethBlk.BlockGasCost() == nil || ethBlk.BlockGasCost().Cmp(big.NewInt(100)) < 0 {
  3521  		t.Fatalf("expected blockGasCost to be at least 100 but got %d", ethBlk.BlockGasCost())
  3522  	}
  3523  	if ethBlk.ExtDataGasUsed() == nil || ethBlk.ExtDataGasUsed().Cmp(common.Big0) != 0 {
  3524  		t.Fatalf("expected extDataGasUsed to be 0 but got %d", ethBlk.ExtDataGasUsed())
  3525  	}
  3526  	minRequiredTip, err = dummy.MinRequiredTip(vm.chainConfig, ethBlk.Header())
  3527  	if err != nil {
  3528  		t.Fatal(err)
  3529  	}
  3530  	if minRequiredTip == nil || minRequiredTip.Cmp(big.NewInt(0.05*params.GWei)) < 0 {
  3531  		t.Fatalf("expected minRequiredTip to be at least 0.05 gwei but got %d", minRequiredTip)
  3532  	}
  3533  
  3534  	if status := blk.Status(); status != choices.Accepted {
  3535  		t.Fatalf("Expected status of accepted block to be %s, but found %s", choices.Accepted, status)
  3536  	}
  3537  
  3538  	lastAcceptedID, err := vm.LastAccepted()
  3539  	if err != nil {
  3540  		t.Fatal(err)
  3541  	}
  3542  	if lastAcceptedID != blk.ID() {
  3543  		t.Fatalf("Expected last accepted blockID to be the accepted block: %s, but found %s", blk.ID(), lastAcceptedID)
  3544  	}
  3545  
  3546  	// Confirm all txs are present
  3547  	ethBlkTxs := vm.blockChain.GetBlockByNumber(2).Transactions()
  3548  	for i, tx := range txs {
  3549  		if len(ethBlkTxs) <= i {
  3550  			t.Fatalf("missing transactions expected: %d but found: %d", len(txs), len(ethBlkTxs))
  3551  		}
  3552  		if ethBlkTxs[i].Hash() != tx.Hash() {
  3553  			t.Fatalf("expected tx at index %d to have hash: %x but has: %x", i, txs[i].Hash(), tx.Hash())
  3554  		}
  3555  	}
  3556  }
  3557  
  3558  // This is a regression test to ensure that if two consecutive atomic transactions fail verification
  3559  // in onFinalizeAndAssemble it will not cause a panic due to calling RevertToSnapshot(revID) on the
  3560  // same revision ID twice.
  3561  func TestConsecutiveAtomicTransactionsRevertSnapshot(t *testing.T) {
  3562  	issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase1, "", "")
  3563  
  3564  	defer func() {
  3565  		if err := vm.Shutdown(); err != nil {
  3566  			t.Fatal(err)
  3567  		}
  3568  	}()
  3569  
  3570  	newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1)
  3571  	vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan)
  3572  
  3573  	// Create three conflicting import transactions
  3574  	importTxs := createImportTxOptions(t, vm, sharedMemory)
  3575  
  3576  	// Issue the first import transaction, build, and accept the block.
  3577  	if err := vm.issueTx(importTxs[0], true); err != nil {
  3578  		t.Fatal(err)
  3579  	}
  3580  
  3581  	<-issuer
  3582  
  3583  	blk, err := vm.BuildBlock()
  3584  	if err != nil {
  3585  		t.Fatal(err)
  3586  	}
  3587  
  3588  	if err := blk.Verify(); err != nil {
  3589  		t.Fatal(err)
  3590  	}
  3591  
  3592  	if status := blk.Status(); status != choices.Processing {
  3593  		t.Fatalf("Expected status of built block to be %s, but found %s", choices.Processing, status)
  3594  	}
  3595  
  3596  	if err := vm.SetPreference(blk.ID()); err != nil {
  3597  		t.Fatal(err)
  3598  	}
  3599  
  3600  	if err := blk.Accept(); err != nil {
  3601  		t.Fatal(err)
  3602  	}
  3603  
  3604  	newHead := <-newTxPoolHeadChan
  3605  	if newHead.Head.Hash() != common.Hash(blk.ID()) {
  3606  		t.Fatalf("Expected new block to match")
  3607  	}
  3608  
  3609  	// Add the two conflicting transactions directly to the mempool, so that two consecutive transactions
  3610  	// will fail verification when build block is called.
  3611  	vm.mempool.AddTx(importTxs[1])
  3612  	vm.mempool.AddTx(importTxs[2])
  3613  
  3614  	if _, err := vm.BuildBlock(); err == nil {
  3615  		t.Fatal("Expected build block to fail due to empty block")
  3616  	}
  3617  }
  3618  
  3619  func TestAtomicTxBuildBlockDropsConflicts(t *testing.T) {
  3620  	importAmount := uint64(10000000)
  3621  	issuer, vm, _, _, _ := GenesisVMWithUTXOs(t, true, genesisJSONApricotPhase5, "", "", map[ids.ShortID]uint64{
  3622  		testShortIDAddrs[0]: importAmount,
  3623  		testShortIDAddrs[1]: importAmount,
  3624  		testShortIDAddrs[2]: importAmount,
  3625  	})
  3626  	conflictKey, err := accountKeystore.NewKey(rand.Reader)
  3627  	if err != nil {
  3628  		t.Fatal(err)
  3629  	}
  3630  	defer func() {
  3631  		if err := vm.Shutdown(); err != nil {
  3632  			t.Fatal(err)
  3633  		}
  3634  	}()
  3635  
  3636  	// Create a conflict set for each pair of transactions
  3637  	conflictSets := make([]ids.Set, len(testKeys))
  3638  	for index, key := range testKeys {
  3639  		importTx, err := vm.newImportTx(vm.ctx.XChainID, testEthAddrs[index], initialBaseFee, []*crypto.PrivateKeySECP256K1R{key})
  3640  		if err != nil {
  3641  			t.Fatal(err)
  3642  		}
  3643  		if err := vm.issueTx(importTx, true /*=local*/); err != nil {
  3644  			t.Fatal(err)
  3645  		}
  3646  		conflictSets[index].Add(importTx.ID())
  3647  		conflictTx, err := vm.newImportTx(vm.ctx.XChainID, conflictKey.Address, initialBaseFee, []*crypto.PrivateKeySECP256K1R{key})
  3648  		if err != nil {
  3649  			t.Fatal(err)
  3650  		}
  3651  		if err := vm.issueTx(conflictTx, true /*=local*/); err == nil {
  3652  			t.Fatal("should conflict with the utxoSet in the mempool")
  3653  		}
  3654  		// force add the tx
  3655  		vm.mempool.ForceAddTx(conflictTx)
  3656  		conflictSets[index].Add(conflictTx.ID())
  3657  	}
  3658  	<-issuer
  3659  	// Note: this only checks the path through OnFinalizeAndAssemble, we should make sure to add a test
  3660  	// that verifies blocks received from the network will also fail verification
  3661  	blk, err := vm.BuildBlock()
  3662  	if err != nil {
  3663  		t.Fatal(err)
  3664  	}
  3665  	atomicTxs := blk.(*chain.BlockWrapper).Block.(*Block).atomicTxs
  3666  	assert.True(t, len(atomicTxs) == len(testKeys), "Conflict transactions should be out of the batch")
  3667  	atomicTxIDs := ids.Set{}
  3668  	for _, tx := range atomicTxs {
  3669  		atomicTxIDs.Add(tx.ID())
  3670  	}
  3671  
  3672  	// Check that removing the txIDs actually included in the block from each conflict set
  3673  	// leaves one item remaining for each conflict set ie. only one tx from each conflict set
  3674  	// has been included in the block.
  3675  	for _, conflictSet := range conflictSets {
  3676  		conflictSet.Difference(atomicTxIDs)
  3677  		assert.Equal(t, 1, conflictSet.Len())
  3678  	}
  3679  
  3680  	if err := blk.Verify(); err != nil {
  3681  		t.Fatal(err)
  3682  	}
  3683  	if err := blk.Accept(); err != nil {
  3684  		t.Fatal(err)
  3685  	}
  3686  }
  3687  
  3688  func TestBuildBlockDoesNotExceedAtomicGasLimit(t *testing.T) {
  3689  	importAmount := uint64(10000000)
  3690  	issuer, vm, _, sharedMemory, _ := GenesisVM(t, true, genesisJSONApricotPhase5, "", "")
  3691  
  3692  	defer func() {
  3693  		if err := vm.Shutdown(); err != nil {
  3694  			t.Fatal(err)
  3695  		}
  3696  	}()
  3697  
  3698  	kc := secp256k1fx.NewKeychain()
  3699  	kc.Add(testKeys[0])
  3700  	txID, err := ids.ToID(hashing.ComputeHash256(testShortIDAddrs[0][:]))
  3701  	assert.NoError(t, err)
  3702  
  3703  	mempoolTxs := 200
  3704  	for i := 0; i < mempoolTxs; i++ {
  3705  		utxo, err := addUTXO(sharedMemory, vm.ctx, txID, uint32(i), vm.ctx.AVAXAssetID, importAmount, testShortIDAddrs[0])
  3706  		assert.NoError(t, err)
  3707  
  3708  		importTx, err := vm.newImportTxWithUTXOs(vm.ctx.XChainID, testEthAddrs[0], initialBaseFee, kc, []*avax.UTXO{utxo})
  3709  		if err != nil {
  3710  			t.Fatal(err)
  3711  		}
  3712  		if err := vm.issueTx(importTx, true); err != nil {
  3713  			t.Fatal(err)
  3714  		}
  3715  	}
  3716  
  3717  	<-issuer
  3718  	blk, err := vm.BuildBlock()
  3719  	if err != nil {
  3720  		t.Fatal(err)
  3721  	}
  3722  
  3723  	atomicTxs := blk.(*chain.BlockWrapper).Block.(*Block).atomicTxs
  3724  
  3725  	// Need to ensure that not all of the transactions in the mempool are included in the block.
  3726  	// This ensures that we hit the atomic gas limit while building the block before we hit the
  3727  	// upper limit on the size of the codec for marshalling the atomic transactions.
  3728  	if len(atomicTxs) >= mempoolTxs {
  3729  		t.Fatalf("Expected number of atomic transactions included in the block (%d) to be less than the number of transactions added to the mempool (%d)", len(atomicTxs), mempoolTxs)
  3730  	}
  3731  }
  3732  
  3733  func TestExtraStateChangeAtomicGasLimitExceeded(t *testing.T) {
  3734  	importAmount := uint64(10000000)
  3735  	// We create two VMs one in ApriotPhase4 and one in ApricotPhase5, so that we can construct a block
  3736  	// containing a large enough atomic transaction that it will exceed the atomic gas limit in
  3737  	// ApricotPhase5.
  3738  	issuer, vm1, _, sharedMemory1, _ := GenesisVM(t, true, genesisJSONApricotPhase4, "", "")
  3739  	_, vm2, _, sharedMemory2, _ := GenesisVM(t, true, genesisJSONApricotPhase5, "", "")
  3740  
  3741  	defer func() {
  3742  		if err := vm1.Shutdown(); err != nil {
  3743  			t.Fatal(err)
  3744  		}
  3745  		if err := vm2.Shutdown(); err != nil {
  3746  			t.Fatal(err)
  3747  		}
  3748  	}()
  3749  
  3750  	kc := secp256k1fx.NewKeychain()
  3751  	kc.Add(testKeys[0])
  3752  	txID, err := ids.ToID(hashing.ComputeHash256(testShortIDAddrs[0][:]))
  3753  	assert.NoError(t, err)
  3754  
  3755  	// Add enough UTXOs, such that the created import transaction will attempt to consume more gas than allowed
  3756  	// in ApricotPhase5.
  3757  	for i := 0; i < 100; i++ {
  3758  		_, err := addUTXO(sharedMemory1, vm1.ctx, txID, uint32(i), vm1.ctx.AVAXAssetID, importAmount, testShortIDAddrs[0])
  3759  		assert.NoError(t, err)
  3760  
  3761  		_, err = addUTXO(sharedMemory2, vm2.ctx, txID, uint32(i), vm2.ctx.AVAXAssetID, importAmount, testShortIDAddrs[0])
  3762  		assert.NoError(t, err)
  3763  	}
  3764  
  3765  	// Double the initial base fee used when estimating the cost of this transaction to ensure that when it is
  3766  	// used in ApricotPhase5 it still pays a sufficient fee with the fixed fee per atomic transaction.
  3767  	importTx, err := vm1.newImportTx(vm1.ctx.XChainID, testEthAddrs[0], new(big.Int).Mul(common.Big2, initialBaseFee), []*crypto.PrivateKeySECP256K1R{testKeys[0]})
  3768  	if err != nil {
  3769  		t.Fatal(err)
  3770  	}
  3771  	if err := vm1.issueTx(importTx, true); err != nil {
  3772  		t.Fatal(err)
  3773  	}
  3774  
  3775  	<-issuer
  3776  	blk1, err := vm1.BuildBlock()
  3777  	if err != nil {
  3778  		t.Fatal(err)
  3779  	}
  3780  	if err := blk1.Verify(); err != nil {
  3781  		t.Fatal(err)
  3782  	}
  3783  
  3784  	validEthBlock := blk1.(*chain.BlockWrapper).Block.(*Block).ethBlock
  3785  
  3786  	extraData, err := vm2.codec.Marshal(codecVersion, []*Tx{importTx})
  3787  	if err != nil {
  3788  		t.Fatal(err)
  3789  	}
  3790  
  3791  	// Construct the new block with the extra data in the new format (slice of atomic transactions).
  3792  	ethBlk2 := types.NewBlock(
  3793  		types.CopyHeader(validEthBlock.Header()),
  3794  		nil,
  3795  		nil,
  3796  		nil,
  3797  		new(trie.Trie),
  3798  		extraData,
  3799  		true,
  3800  	)
  3801  
  3802  	state, err := vm2.blockChain.State()
  3803  	if err != nil {
  3804  		t.Fatal(err)
  3805  	}
  3806  
  3807  	// Hack: test [onExtraStateChange] directly to ensure it catches the atomic gas limit error correctly.
  3808  	if _, _, err := vm2.onExtraStateChange(ethBlk2, state); err == nil || !strings.Contains(err.Error(), "exceeds atomic gas limit") {
  3809  		t.Fatalf("Expected block to fail verification due to exceeded atomic gas limit, but found error: %v", err)
  3810  	}
  3811  }
  3812  
  3813  func TestGetAtomicRepositoryRepairHeights(t *testing.T) {
  3814  	mainnetHeights := getAtomicRepositoryRepairHeights(bonusBlockMainnetHeights, canonicalBlockMainnetHeights)
  3815  	assert.Len(t, mainnetHeights, 76)
  3816  	sorted := sort.SliceIsSorted(mainnetHeights, func(i, j int) bool { return mainnetHeights[i] < mainnetHeights[j] })
  3817  	assert.True(t, sorted)
  3818  }