github.com/MetalBlockchain/subnet-evm@v0.4.9/plugin/evm/vm_upgrade_bytes_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 "encoding/json" 9 "errors" 10 "math/big" 11 "testing" 12 "time" 13 14 "github.com/MetalBlockchain/metalgo/snow" 15 "github.com/MetalBlockchain/metalgo/snow/engine/common" 16 "github.com/MetalBlockchain/metalgo/vms/components/chain" 17 "github.com/MetalBlockchain/subnet-evm/core" 18 "github.com/MetalBlockchain/subnet-evm/core/types" 19 "github.com/MetalBlockchain/subnet-evm/metrics" 20 "github.com/MetalBlockchain/subnet-evm/params" 21 "github.com/MetalBlockchain/subnet-evm/precompile" 22 "github.com/stretchr/testify/assert" 23 ) 24 25 func TestVMUpgradeBytesPrecompile(t *testing.T) { 26 // Make a TxAllowListConfig upgrade at genesis and convert it to JSON to apply as upgradeBytes. 27 enableAllowListTimestamp := time.Unix(0, 0) // enable at genesis 28 upgradeConfig := ¶ms.UpgradeConfig{ 29 PrecompileUpgrades: []params.PrecompileUpgrade{ 30 { 31 TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(enableAllowListTimestamp.Unix()), testEthAddrs[0:1], nil), 32 }, 33 }, 34 } 35 upgradeBytesJSON, err := json.Marshal(upgradeConfig) 36 if err != nil { 37 t.Fatalf("could not marshal upgradeConfig to json: %s", err) 38 } 39 40 // initialize the VM with these upgrade bytes 41 issuer, vm, dbManager, appSender := GenesisVM(t, true, genesisJSONSubnetEVM, "", string(upgradeBytesJSON)) 42 43 // Submit a successful transaction 44 tx0 := types.NewTransaction(uint64(0), testEthAddrs[0], big.NewInt(1), 21000, big.NewInt(testMinGasPrice), nil) 45 signedTx0, err := types.SignTx(tx0, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0]) 46 assert.NoError(t, err) 47 48 errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx0}) 49 if err := errs[0]; err != nil { 50 t.Fatalf("Failed to add tx at index: %s", err) 51 } 52 53 // Submit a rejected transaction, should throw an error 54 tx1 := types.NewTransaction(uint64(0), testEthAddrs[1], big.NewInt(2), 21000, big.NewInt(testMinGasPrice), nil) 55 signedTx1, err := types.SignTx(tx1, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[1]) 56 if err != nil { 57 t.Fatal(err) 58 } 59 errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1}) 60 if err := errs[0]; !errors.Is(err, precompile.ErrSenderAddressNotAllowListed) { 61 t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err) 62 } 63 64 // shutdown the vm 65 if err := vm.Shutdown(context.Background()); err != nil { 66 t.Fatal(err) 67 } 68 69 // prepare the new upgrade bytes to disable the TxAllowList 70 disableAllowListTimestamp := enableAllowListTimestamp.Add(10 * time.Hour) // arbitrary choice 71 upgradeConfig.PrecompileUpgrades = append( 72 upgradeConfig.PrecompileUpgrades, 73 params.PrecompileUpgrade{ 74 TxAllowListConfig: precompile.NewDisableTxAllowListConfig(big.NewInt(disableAllowListTimestamp.Unix())), 75 }, 76 ) 77 upgradeBytesJSON, err = json.Marshal(upgradeConfig) 78 if err != nil { 79 t.Fatalf("could not marshal upgradeConfig to json: %s", err) 80 } 81 82 // restart the vm 83 ctx := NewContext() 84 if err := vm.Initialize( 85 context.Background(), ctx, dbManager, []byte(genesisJSONSubnetEVM), upgradeBytesJSON, []byte{}, issuer, []*common.Fx{}, appSender, 86 ); err != nil { 87 t.Fatal(err) 88 } 89 defer func() { 90 if err := vm.Shutdown(context.Background()); err != nil { 91 t.Fatal(err) 92 } 93 }() 94 // Set the VM's state to NormalOp to initialize the tx pool. 95 if err := vm.SetState(context.Background(), snow.NormalOp); err != nil { 96 t.Fatal(err) 97 } 98 newTxPoolHeadChan := make(chan core.NewTxPoolReorgEvent, 1) 99 vm.txPool.SubscribeNewReorgEvent(newTxPoolHeadChan) 100 vm.clock.Set(disableAllowListTimestamp) 101 102 // Make a block, previous rules still apply (TxAllowList is active) 103 // Submit a successful transaction 104 errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx0}) 105 if err := errs[0]; err != nil { 106 t.Fatalf("Failed to add tx at index: %s", err) 107 } 108 109 // Submit a rejected transaction, should throw an error 110 errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1}) 111 if err := errs[0]; !errors.Is(err, precompile.ErrSenderAddressNotAllowListed) { 112 t.Fatalf("expected ErrSenderAddressNotAllowListed, got: %s", err) 113 } 114 115 blk := issueAndAccept(t, issuer, vm) 116 117 // Verify that the constructed block only has the whitelisted tx 118 block := blk.(*chain.BlockWrapper).Block.(*Block).ethBlock 119 txs := block.Transactions() 120 if txs.Len() != 1 { 121 t.Fatalf("Expected number of txs to be %d, but found %d", 1, txs.Len()) 122 } 123 assert.Equal(t, signedTx0.Hash(), txs[0].Hash()) 124 125 // verify the issued block is after the network upgrade 126 assert.True(t, block.Timestamp().Cmp(big.NewInt(disableAllowListTimestamp.Unix())) >= 0) 127 128 <-newTxPoolHeadChan // wait for new head in tx pool 129 130 // retry the rejected Tx, which should now succeed 131 errs = vm.txPool.AddRemotesSync([]*types.Transaction{signedTx1}) 132 if err := errs[0]; err != nil { 133 t.Fatalf("Failed to add tx at index: %s", err) 134 } 135 136 vm.clock.Set(vm.clock.Time().Add(2 * time.Second)) // add 2 seconds for gas fee to adjust 137 blk = issueAndAccept(t, issuer, vm) 138 139 // Verify that the constructed block only has the previously rejected tx 140 block = blk.(*chain.BlockWrapper).Block.(*Block).ethBlock 141 txs = block.Transactions() 142 if txs.Len() != 1 { 143 t.Fatalf("Expected number of txs to be %d, but found %d", 1, txs.Len()) 144 } 145 assert.Equal(t, signedTx1.Hash(), txs[0].Hash()) 146 } 147 148 func TestVMUpgradeBytesNetworkUpgrades(t *testing.T) { 149 // Hack: registering metrics uses global variables, so we need to disable metrics here so that we can initialize the VM twice. 150 metrics.Enabled = false 151 defer func() { 152 metrics.Enabled = true 153 }() 154 155 // Get a json specifying a Network upgrade at genesis 156 // to apply as upgradeBytes. 157 subnetEVMTimestamp := time.Unix(10, 0) 158 upgradeConfig := ¶ms.UpgradeConfig{ 159 NetworkUpgrades: ¶ms.NetworkUpgrades{ 160 SubnetEVMTimestamp: big.NewInt(subnetEVMTimestamp.Unix()), 161 }, 162 } 163 upgradeBytesJSON, err := json.Marshal(upgradeConfig) 164 if err != nil { 165 t.Fatalf("could not marshal upgradeConfig to json: %s", err) 166 } 167 configJSON := "{\"skip-subnet-evm-upgrade-check\": true}" 168 169 // initialize the VM with these upgrade bytes 170 issuer, vm, dbManager, appSender := GenesisVM(t, true, genesisJSONPreSubnetEVM, configJSON, string(upgradeBytesJSON)) 171 vm.clock.Set(subnetEVMTimestamp) 172 173 // verify upgrade is applied 174 if !vm.chainConfig.IsSubnetEVM(big.NewInt(subnetEVMTimestamp.Unix())) { 175 t.Fatal("expected subnet-evm network upgrade to have been enabled") 176 } 177 178 // Submit a successful transaction and build a block to move the chain head past the SubnetEVMTimestamp network upgrade 179 tx0 := types.NewTransaction(uint64(0), testEthAddrs[0], big.NewInt(1), 21000, big.NewInt(testMinGasPrice), nil) 180 signedTx0, err := types.SignTx(tx0, types.NewEIP155Signer(vm.chainConfig.ChainID), testKeys[0]) 181 assert.NoError(t, err) 182 errs := vm.txPool.AddRemotesSync([]*types.Transaction{signedTx0}) 183 if err := errs[0]; err != nil { 184 t.Fatalf("Failed to add tx at index: %s", err) 185 } 186 187 issueAndAccept(t, issuer, vm) // make a block 188 189 if err := vm.Shutdown(context.Background()); err != nil { 190 t.Fatal(err) 191 } 192 193 // VM should not start again without proper upgrade bytes. 194 err = vm.Initialize(context.Background(), vm.ctx, dbManager, []byte(genesisJSONPreSubnetEVM), []byte{}, []byte{}, issuer, []*common.Fx{}, appSender) 195 assert.ErrorContains(t, err, "mismatching SubnetEVM fork block timestamp in database") 196 197 // VM should not start if fork is moved back 198 upgradeConfig.NetworkUpgrades.SubnetEVMTimestamp = big.NewInt(2) 199 upgradeBytesJSON, err = json.Marshal(upgradeConfig) 200 if err != nil { 201 t.Fatalf("could not marshal upgradeConfig to json: %s", err) 202 } 203 err = vm.Initialize(context.Background(), vm.ctx, dbManager, []byte(genesisJSONPreSubnetEVM), upgradeBytesJSON, []byte{}, issuer, []*common.Fx{}, appSender) 204 assert.ErrorContains(t, err, "mismatching SubnetEVM fork block timestamp in database") 205 206 // VM should not start if fork is moved forward 207 upgradeConfig.NetworkUpgrades.SubnetEVMTimestamp = big.NewInt(30) 208 upgradeBytesJSON, err = json.Marshal(upgradeConfig) 209 if err != nil { 210 t.Fatalf("could not marshal upgradeConfig to json: %s", err) 211 } 212 err = vm.Initialize(context.Background(), vm.ctx, dbManager, []byte(genesisJSONPreSubnetEVM), upgradeBytesJSON, []byte{}, issuer, []*common.Fx{}, appSender) 213 assert.ErrorContains(t, err, "mismatching SubnetEVM fork block timestamp in database") 214 } 215 216 func TestVMUpgradeBytesNetworkUpgradesWithGenesis(t *testing.T) { 217 // make genesis w/ fork at block 5 218 var genesis core.Genesis 219 if err := json.Unmarshal([]byte(genesisJSONPreSubnetEVM), &genesis); err != nil { 220 t.Fatalf("could not unmarshal genesis bytes: %s", err) 221 } 222 genesisSubnetEVMTimestamp := big.NewInt(5) 223 genesis.Config.SubnetEVMTimestamp = genesisSubnetEVMTimestamp 224 genesisBytes, err := json.Marshal(&genesis) 225 if err != nil { 226 t.Fatalf("could not unmarshal genesis bytes: %s", err) 227 } 228 229 // Get a json specifying a Network upgrade at genesis 230 // to apply as upgradeBytes. 231 subnetEVMTimestamp := time.Unix(10, 0) 232 upgradeConfig := ¶ms.UpgradeConfig{ 233 NetworkUpgrades: ¶ms.NetworkUpgrades{ 234 SubnetEVMTimestamp: big.NewInt(subnetEVMTimestamp.Unix()), 235 }, 236 } 237 upgradeBytesJSON, err := json.Marshal(upgradeConfig) 238 if err != nil { 239 t.Fatalf("could not marshal upgradeConfig to json: %s", err) 240 } 241 configJSON := "{\"skip-subnet-evm-upgrade-check\": true}" 242 243 // initialize the VM with these upgrade bytes 244 _, vm, _, _ := GenesisVM(t, true, string(genesisBytes), configJSON, string(upgradeBytesJSON)) 245 246 // verify upgrade is rescheduled 247 assert.False(t, vm.chainConfig.IsSubnetEVM(genesisSubnetEVMTimestamp)) 248 assert.True(t, vm.chainConfig.IsSubnetEVM(big.NewInt(subnetEVMTimestamp.Unix()))) 249 250 if err := vm.Shutdown(context.Background()); err != nil { 251 t.Fatal(err) 252 } 253 254 // abort a fork specified in genesis 255 upgradeConfig.NetworkUpgrades.SubnetEVMTimestamp = nil 256 upgradeBytesJSON, err = json.Marshal(upgradeConfig) 257 if err != nil { 258 t.Fatalf("could not marshal upgradeConfig to json: %s", err) 259 } 260 261 // initialize the VM with these upgrade bytes 262 _, vm, _, _ = GenesisVM(t, true, string(genesisBytes), configJSON, string(upgradeBytesJSON)) 263 264 // verify upgrade is aborted 265 assert.False(t, vm.chainConfig.IsSubnetEVM(genesisSubnetEVMTimestamp)) 266 assert.False(t, vm.chainConfig.IsSubnetEVM(big.NewInt(subnetEVMTimestamp.Unix()))) 267 268 if err := vm.Shutdown(context.Background()); err != nil { 269 t.Fatal(err) 270 } 271 }