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 }