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