github.com/ethereum/go-ethereum@v1.16.1/core/verkle_witness_test.go (about) 1 // Copyright 2024 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "bytes" 21 "encoding/binary" 22 "encoding/hex" 23 "math/big" 24 "slices" 25 "testing" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/consensus/beacon" 29 "github.com/ethereum/go-ethereum/consensus/ethash" 30 "github.com/ethereum/go-ethereum/core/rawdb" 31 "github.com/ethereum/go-ethereum/core/state" 32 "github.com/ethereum/go-ethereum/core/tracing" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/core/vm" 35 "github.com/ethereum/go-ethereum/crypto" 36 "github.com/ethereum/go-ethereum/params" 37 "github.com/ethereum/go-ethereum/trie/utils" 38 "github.com/ethereum/go-ethereum/triedb" 39 "github.com/ethereum/go-verkle" 40 "github.com/holiman/uint256" 41 ) 42 43 var ( 44 testVerkleChainConfig = ¶ms.ChainConfig{ 45 ChainID: big.NewInt(1), 46 HomesteadBlock: big.NewInt(0), 47 EIP150Block: big.NewInt(0), 48 EIP155Block: big.NewInt(0), 49 EIP158Block: big.NewInt(0), 50 ByzantiumBlock: big.NewInt(0), 51 ConstantinopleBlock: big.NewInt(0), 52 PetersburgBlock: big.NewInt(0), 53 IstanbulBlock: big.NewInt(0), 54 MuirGlacierBlock: big.NewInt(0), 55 BerlinBlock: big.NewInt(0), 56 LondonBlock: big.NewInt(0), 57 Ethash: new(params.EthashConfig), 58 ShanghaiTime: u64(0), 59 VerkleTime: u64(0), 60 TerminalTotalDifficulty: common.Big0, 61 EnableVerkleAtGenesis: true, 62 BlobScheduleConfig: ¶ms.BlobScheduleConfig{ 63 Verkle: params.DefaultPragueBlobConfig, 64 }, 65 // TODO uncomment when proof generation is merged 66 // ProofInBlocks: true, 67 } 68 testKaustinenLikeChainConfig = ¶ms.ChainConfig{ 69 ChainID: big.NewInt(69420), 70 HomesteadBlock: big.NewInt(0), 71 EIP150Block: big.NewInt(0), 72 EIP155Block: big.NewInt(0), 73 EIP158Block: big.NewInt(0), 74 ByzantiumBlock: big.NewInt(0), 75 ConstantinopleBlock: big.NewInt(0), 76 PetersburgBlock: big.NewInt(0), 77 IstanbulBlock: big.NewInt(0), 78 MuirGlacierBlock: big.NewInt(0), 79 BerlinBlock: big.NewInt(0), 80 LondonBlock: big.NewInt(0), 81 Ethash: new(params.EthashConfig), 82 ShanghaiTime: u64(0), 83 VerkleTime: u64(0), 84 TerminalTotalDifficulty: common.Big0, 85 EnableVerkleAtGenesis: true, 86 BlobScheduleConfig: ¶ms.BlobScheduleConfig{ 87 Verkle: params.DefaultPragueBlobConfig, 88 }, 89 } 90 ) 91 92 func TestProcessVerkle(t *testing.T) { 93 var ( 94 code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`) 95 intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, true, true, true) 96 // A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness 97 // will not contain that copied data. 98 // Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985 99 codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) 100 intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true) 101 signer = types.LatestSigner(testVerkleChainConfig) 102 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 103 bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain 104 coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") 105 gspec = &Genesis{ 106 Config: testVerkleChainConfig, 107 Alloc: GenesisAlloc{ 108 coinbase: { 109 Balance: big.NewInt(1000000000000000000), // 1 ether 110 Nonce: 0, 111 }, 112 params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, 113 params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0}, 114 params.WithdrawalQueueAddress: {Nonce: 1, Code: params.WithdrawalQueueCode, Balance: common.Big0}, 115 params.ConsolidationQueueAddress: {Nonce: 1, Code: params.ConsolidationQueueCode, Balance: common.Big0}, 116 }, 117 } 118 ) 119 // Verkle trees use the snapshot, which must be enabled before the 120 // data is saved into the tree+database. 121 // genesis := gspec.MustCommit(bcdb, triedb) 122 options := DefaultConfig().WithStateScheme(rawdb.PathScheme) 123 options.SnapshotLimit = 0 124 blockchain, _ := NewBlockChain(bcdb, gspec, beacon.New(ethash.NewFaker()), options) 125 defer blockchain.Stop() 126 127 txCost1 := params.TxGas 128 txCost2 := params.TxGas 129 contractCreationCost := intrinsicContractCreationGas + 130 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation */ 131 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* creation with value */ 132 739 /* execution costs */ 133 codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + 134 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (tx) */ 135 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at pc=0x20) */ 136 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */ 137 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */ 138 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */ 139 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */ 140 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */ 141 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */ 142 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */ 143 params.WitnessChunkReadCost + /* SLOAD in constructor */ 144 params.WitnessChunkWriteCost + /* SSTORE in constructor */ 145 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at PC=0x121) */ 146 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */ 147 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #0 */ 148 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #1 */ 149 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #2 */ 150 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #3 */ 151 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #4 */ 152 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* code chunk #5 */ 153 params.WitnessChunkReadCost + /* SLOAD in constructor */ 154 params.WitnessChunkWriteCost + /* SSTORE in constructor */ 155 params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash for tx creation */ 156 15*(params.WitnessChunkReadCost+params.WitnessChunkWriteCost) + /* code chunks #0..#14 */ 157 uint64(4844) /* execution costs */ 158 blockGasUsagesExpected := []uint64{ 159 txCost1*2 + txCost2, 160 txCost1*2 + txCost2 + contractCreationCost + codeWithExtCodeCopyGas, 161 } 162 _, _, chain, _, proofs, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { 163 gen.SetPoS() 164 165 // TODO need to check that the tx cost provided is the exact amount used (no remaining left-over) 166 tx, _ := types.SignTx(types.NewTransaction(uint64(i)*3, common.Address{byte(i), 2, 3}, big.NewInt(999), txCost1, big.NewInt(875000000), nil), signer, testKey) 167 gen.AddTx(tx) 168 tx, _ = types.SignTx(types.NewTransaction(uint64(i)*3+1, common.Address{}, big.NewInt(999), txCost1, big.NewInt(875000000), nil), signer, testKey) 169 gen.AddTx(tx) 170 tx, _ = types.SignTx(types.NewTransaction(uint64(i)*3+2, common.Address{}, big.NewInt(0), txCost2, big.NewInt(875000000), nil), signer, testKey) 171 gen.AddTx(tx) 172 173 // Add two contract creations in block #2 174 if i == 1 { 175 tx, _ = types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 6, 176 Value: big.NewInt(16), 177 Gas: 3000000, 178 GasPrice: big.NewInt(875000000), 179 Data: code, 180 }) 181 gen.AddTx(tx) 182 183 tx, _ = types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 7, 184 Value: big.NewInt(0), 185 Gas: 3000000, 186 GasPrice: big.NewInt(875000000), 187 Data: codeWithExtCodeCopy, 188 }) 189 gen.AddTx(tx) 190 } 191 }) 192 193 // Check proof for both blocks 194 err := verkle.Verify(proofs[0], gspec.ToBlock().Root().Bytes(), chain[0].Root().Bytes(), statediffs[0]) 195 if err != nil { 196 t.Fatal(err) 197 } 198 err = verkle.Verify(proofs[1], chain[0].Root().Bytes(), chain[1].Root().Bytes(), statediffs[1]) 199 if err != nil { 200 t.Fatal(err) 201 } 202 203 t.Log("verified verkle proof, inserting blocks into the chain") 204 205 endnum, err := blockchain.InsertChain(chain) 206 if err != nil { 207 t.Fatalf("block %d imported with error: %v", endnum, err) 208 } 209 210 for i := 0; i < 2; i++ { 211 b := blockchain.GetBlockByNumber(uint64(i) + 1) 212 if b == nil { 213 t.Fatalf("expected block %d to be present in chain", i+1) 214 } 215 if b.Hash() != chain[i].Hash() { 216 t.Fatalf("block #%d not found at expected height", b.NumberU64()) 217 } 218 if b.GasUsed() != blockGasUsagesExpected[i] { 219 t.Fatalf("expected block #%d txs to use %d, got %d\n", b.NumberU64(), blockGasUsagesExpected[i], b.GasUsed()) 220 } 221 } 222 } 223 224 func TestProcessParentBlockHash(t *testing.T) { 225 // This test uses blocks where, 226 // block 1 parent hash is 0x0100.... 227 // block 2 parent hash is 0x0200.... 228 // etc 229 checkBlockHashes := func(statedb *state.StateDB, isVerkle bool) { 230 statedb.SetNonce(params.HistoryStorageAddress, 1, tracing.NonceChangeUnspecified) 231 statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) 232 // Process n blocks, from 1 .. num 233 var num = 2 234 for i := 1; i <= num; i++ { 235 header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)} 236 chainConfig := params.MergedTestChainConfig 237 if isVerkle { 238 chainConfig = testVerkleChainConfig 239 } 240 vmContext := NewEVMBlockContext(header, nil, new(common.Address)) 241 evm := vm.NewEVM(vmContext, statedb, chainConfig, vm.Config{}) 242 ProcessParentBlockHash(header.ParentHash, evm) 243 } 244 // Read block hashes for block 0 .. num-1 245 for i := 0; i < num; i++ { 246 have, want := getContractStoredBlockHash(statedb, uint64(i), isVerkle), common.Hash{byte(i + 1)} 247 if have != want { 248 t.Errorf("block %d, verkle=%v, have parent hash %v, want %v", i, isVerkle, have, want) 249 } 250 } 251 } 252 t.Run("MPT", func(t *testing.T) { 253 statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) 254 checkBlockHashes(statedb, false) 255 }) 256 t.Run("Verkle", func(t *testing.T) { 257 db := rawdb.NewMemoryDatabase() 258 cacheConfig := DefaultConfig().WithStateScheme(rawdb.PathScheme) 259 cacheConfig.SnapshotLimit = 0 260 triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) 261 statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabase(triedb, nil)) 262 checkBlockHashes(statedb, true) 263 }) 264 } 265 266 // getContractStoredBlockHash is a utility method which reads the stored parent blockhash for block 'number' 267 func getContractStoredBlockHash(statedb *state.StateDB, number uint64, isVerkle bool) common.Hash { 268 ringIndex := number % params.HistoryServeWindow 269 var key common.Hash 270 binary.BigEndian.PutUint64(key[24:], ringIndex) 271 if isVerkle { 272 return statedb.GetState(params.HistoryStorageAddress, key) 273 } 274 return statedb.GetState(params.HistoryStorageAddress, key) 275 } 276 277 // TestProcessVerkleInvalidContractCreation checks for several modes of contract creation failures 278 func TestProcessVerkleInvalidContractCreation(t *testing.T) { 279 var ( 280 account1 = common.HexToAddress("0x687704DB07e902e9A8B3754031D168D46E3D586e") 281 account2 = common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d") 282 gspec = verkleTestGenesis(testKaustinenLikeChainConfig) 283 ) 284 // slightly modify it to suit the live txs from the testnet 285 gspec.Alloc[account2] = types.Account{ 286 Balance: big.NewInt(1000000000000000000), // 1 ether 287 Nonce: 1, 288 } 289 290 // Create two blocks that reproduce what is happening on kaustinen. 291 // - The first block contains two failing contract creation transactions, that 292 // write to storage before they revert. 293 // 294 // - The second block contains a single failing contract creation transaction, 295 // that fails right off the bat. 296 genesisH, _, chain, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { 297 gen.SetPoS() 298 299 if i == 0 { 300 for _, rlpData := range []string{ 301 // SSTORE at slot 41 and reverts 302 "f8d48084479c2c18830186a08080b8806000602955bda3f9600060ca55600060695523b360006039551983576000601255b0620c2fde2c592ac2600060bc55e0ac6000606455a63e22600060e655eb607e605c5360a2605d5360c7605e53601d605f5360eb606053606b606153608e60625360816063536079606453601e60655360fc60665360b7606753608b60685383021e7ca0cc20c65a97d2e526b8ec0f4266e8b01bdcde43b9aeb59d8bfb44e8eb8119c109a07a8e751813ae1b2ce734960dbc39a4f954917d7822a2c5d1dca18b06c584131f", 303 // SSTORE at slot 133 and reverts 304 "02f8db83010f2c01843b9aca0084479c2c18830186a08080b88060006085553fad6000600a55600060565555600060b55506600060cf557f1b8b38183e7bd1bdfaa7123c5a4976e54cce0e42049d841411978fd3595e25c66019527f0538943712953cf08900aae40222a40b2d5a4ac8075ad8cf0870e2be307edbb96039527f9f3174ff85024747041ae7a611acffb987c513c088d90ab288aec080a0cd6ac65ce2cb0a912371f6b5a551ba8caffc22ec55ad4d3cb53de41d05eb77b6a02e0dfe8513dfa6ec7bfd7eda6f5c0dac21b39b982436045e128cec46cfd3f960", 305 // this one is a simple transfer that succeeds, necessary to get the correct nonce in the other block. 306 "f8e80184479c2c18830186a094bbbbde4ca27f83fc18aa108170547ff57675936a80b8807ff71f7c15faadb969a76a5f54a81a0117e1e743cb7f24e378eda28442ea4c6eb6604a527fb5409e5718d44e23bfffac926e5ea726067f772772e7e19446acba0c853f62f5606a526020608a536088608b536039608c536004608d5360af608e537f7f7675d9f210e0a61564e6d11e7cd75f5bc9009ac9f6b94a0fc63035441a83021e7ba04a4a172d81ebb02847829b76a387ac09749c8b65668083699abe20c887fb9efca07c5b1a990702ec7b31a5e8e3935cd9a77649f8c25a84131229e24ab61aec6093", 307 } { 308 var tx = new(types.Transaction) 309 if err := tx.UnmarshalBinary(common.Hex2Bytes(rlpData)); err != nil { 310 t.Fatal(err) 311 } 312 gen.AddTx(tx) 313 } 314 } else { 315 var tx = new(types.Transaction) 316 // immediately reverts 317 if err := tx.UnmarshalBinary(common.Hex2Bytes("01f8d683010f2c028443ad7d0e830186a08080b880b00e7fa3c849dce891cce5fae8a4c46cbb313d6aec0c0ffe7863e05fb7b22d4807674c6055527ffbfcb0938f3e18f7937aa8fa95d880afebd5c4cec0d85186095832d03c85cf8a60755260ab60955360cf6096536066609753606e60985360fa609953609e609a53608e609b536024609c5360f6609d536072609e5360a4609fc080a08fc6f7101f292ff1fb0de8ac69c2d320fbb23bfe61cf327173786ea5daee6e37a044c42d91838ef06646294bf4f9835588aee66243b16a66a2da37641fae4c045f")); err != nil { 318 t.Fatal(err) 319 } 320 gen.AddTx(tx) 321 } 322 }) 323 324 tx1ContractAddress := crypto.CreateAddress(account1, 0) 325 tx1ContractStem := utils.GetTreeKey(tx1ContractAddress[:], uint256.NewInt(0), 105) 326 tx1ContractStem = tx1ContractStem[:31] 327 328 tx2ContractAddress := crypto.CreateAddress(account2, 1) 329 tx2SlotKey := [32]byte{} 330 tx2SlotKey[31] = 133 331 tx2ContractStem := utils.StorageSlotKey(tx2ContractAddress[:], tx2SlotKey[:]) 332 tx2ContractStem = tx2ContractStem[:31] 333 334 eip2935Stem := utils.GetTreeKey(params.HistoryStorageAddress[:], uint256.NewInt(0), 0) 335 eip2935Stem = eip2935Stem[:31] 336 337 // Check that the witness contains what we expect: a storage entry for each of the two contract 338 // creations that failed: one at 133 for the 2nd tx, and one at 105 for the first tx. 339 for _, stemStateDiff := range statediffs[0] { 340 // Check that the slot number 133, which is overflowing the account header, 341 // is present. Note that the offset of the 2nd group (first group after the 342 // header) is skipping the first 64 values, hence we still have an offset 343 // of 133, and not 133 - 64. 344 if bytes.Equal(stemStateDiff.Stem[:], tx2ContractStem[:]) { 345 for _, suffixDiff := range stemStateDiff.SuffixDiffs { 346 if suffixDiff.Suffix != 133 { 347 t.Fatalf("invalid suffix diff found for %x in block #1: %d\n", stemStateDiff.Stem, suffixDiff.Suffix) 348 } 349 if suffixDiff.CurrentValue != nil { 350 t.Fatalf("invalid prestate value found for %x in block #1: %v != nil\n", stemStateDiff.Stem, suffixDiff.CurrentValue) 351 } 352 if suffixDiff.NewValue != nil { 353 t.Fatalf("invalid poststate value found for %x in block #1: %v != nil\n", stemStateDiff.Stem, suffixDiff.NewValue) 354 } 355 } 356 } else if bytes.Equal(stemStateDiff.Stem[:], tx1ContractStem) { 357 // For this contract creation, check that only the account header and storage slot 41 358 // are found in the witness. 359 for _, suffixDiff := range stemStateDiff.SuffixDiffs { 360 if suffixDiff.Suffix != 105 && suffixDiff.Suffix != 0 && suffixDiff.Suffix != 1 { 361 t.Fatalf("invalid suffix diff found for %x in block #1: %d\n", stemStateDiff.Stem, suffixDiff.Suffix) 362 } 363 } 364 } else if bytes.Equal(stemStateDiff.Stem[:], eip2935Stem) { 365 // Check the eip 2935 group of leaves. 366 // Check that only one leaf was accessed, and is present in the witness. 367 if len(stemStateDiff.SuffixDiffs) > 1 { 368 t.Fatalf("invalid suffix diff count found for BLOCKHASH contract: %d != 1", len(stemStateDiff.SuffixDiffs)) 369 } 370 // Check that this leaf is the first storage slot 371 if stemStateDiff.SuffixDiffs[0].Suffix != 64 { 372 t.Fatalf("invalid suffix diff value found for BLOCKHASH contract: %d != 64", stemStateDiff.SuffixDiffs[0].Suffix) 373 } 374 // check that the prestate value is nil and that the poststate value isn't. 375 if stemStateDiff.SuffixDiffs[0].CurrentValue != nil { 376 t.Fatalf("non-nil current value in BLOCKHASH contract insert: %x", stemStateDiff.SuffixDiffs[0].CurrentValue) 377 } 378 if stemStateDiff.SuffixDiffs[0].NewValue == nil { 379 t.Fatalf("nil new value in BLOCKHASH contract insert") 380 } 381 if *stemStateDiff.SuffixDiffs[0].NewValue != genesisH { 382 t.Fatalf("invalid BLOCKHASH value: %x != %x", *stemStateDiff.SuffixDiffs[0].NewValue, genesisH) 383 } 384 } else { 385 // For all other entries present in the witness, check that nothing beyond 386 // the account header was accessed. 387 for _, suffixDiff := range stemStateDiff.SuffixDiffs { 388 if suffixDiff.Suffix > 2 { 389 t.Fatalf("invalid suffix diff found for %x in block #1: %d\n", stemStateDiff.Stem, suffixDiff.Suffix) 390 } 391 } 392 } 393 } 394 395 // Check that no account has a value above 4 in the 2nd block as no storage nor 396 // code should make it to the witness. 397 for _, stemStateDiff := range statediffs[1] { 398 for _, suffixDiff := range stemStateDiff.SuffixDiffs { 399 if bytes.Equal(stemStateDiff.Stem[:], eip2935Stem) { 400 // BLOCKHASH contract stem 401 if len(stemStateDiff.SuffixDiffs) > 1 { 402 t.Fatalf("invalid suffix diff count found for BLOCKHASH contract at block #2: %d != 1", len(stemStateDiff.SuffixDiffs)) 403 } 404 if stemStateDiff.SuffixDiffs[0].Suffix != 65 { 405 t.Fatalf("invalid suffix diff value found for BLOCKHASH contract at block #2: %d != 65", stemStateDiff.SuffixDiffs[0].Suffix) 406 } 407 if stemStateDiff.SuffixDiffs[0].NewValue == nil { 408 t.Fatalf("missing post state value for BLOCKHASH contract at block #2") 409 } 410 if *stemStateDiff.SuffixDiffs[0].NewValue != chain[0].Hash() { 411 t.Fatalf("invalid post state value for BLOCKHASH contract at block #2: %x != %x", chain[0].Hash(), (*stemStateDiff.SuffixDiffs[0].NewValue)[:]) 412 } 413 } else if suffixDiff.Suffix > 4 { 414 t.Fatalf("invalid suffix diff found for %x in block #2: %d\n", stemStateDiff.Stem, suffixDiff.Suffix) 415 } 416 } 417 } 418 } 419 420 func verkleTestGenesis(config *params.ChainConfig) *Genesis { 421 var ( 422 coinbase = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7") 423 account1 = common.HexToAddress("0x687704DB07e902e9A8B3754031D168D46E3D586e") 424 account2 = common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d") 425 ) 426 return &Genesis{ 427 Config: config, 428 Alloc: GenesisAlloc{ 429 coinbase: GenesisAccount{ 430 Balance: big.NewInt(1000000000000000000), // 1 ether 431 Nonce: 0, 432 }, 433 account1: GenesisAccount{ 434 Balance: big.NewInt(1000000000000000000), // 1 ether 435 Nonce: 0, 436 }, 437 account2: GenesisAccount{ 438 Balance: big.NewInt(1000000000000000000), // 1 ether 439 Nonce: 3, 440 }, 441 params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, 442 params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode, Balance: common.Big0}, 443 params.WithdrawalQueueAddress: {Nonce: 1, Code: params.WithdrawalQueueCode, Balance: common.Big0}, 444 params.ConsolidationQueueAddress: {Nonce: 1, Code: params.ConsolidationQueueCode, Balance: common.Big0}, 445 }, 446 } 447 } 448 449 // TestProcessVerkleContractWithEmptyCode checks that the witness contains all valid 450 // entries, if the initcode returns an empty code. 451 func TestProcessVerkleContractWithEmptyCode(t *testing.T) { 452 // The test txs were taken from a secondary testnet with chain id 69421 453 config := *testKaustinenLikeChainConfig 454 config.ChainID.SetUint64(69421) 455 gspec := verkleTestGenesis(&config) 456 457 genesisH, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { 458 gen.SetPoS() 459 var tx types.Transaction 460 // a transaction that does some PUSH1n but returns a 0-sized contract 461 txpayload := common.Hex2Bytes("02f8db83010f2d03843b9aca008444cf6a05830186a08080b8807fdfbbb59f2371a76485ce557fd0de00c298d3ede52a3eab56d35af674eb49ec5860335260826053536001605453604c60555360f3605653606060575360446058536096605953600c605a5360df605b5360f3605c5360fb605d53600c605e53609a605f53607f60605360fe606153603d60625360f4606353604b60645360cac001a0486b6dc55b8a311568b7239a2cae1d77e7446dba71df61eaafd53f73820a138fa010bd48a45e56133ac4c5645142c2ea48950d40eb35050e9510b6bad9e15c5865") 462 if err := tx.UnmarshalBinary(txpayload); err != nil { 463 t.Fatal(err) 464 } 465 gen.AddTx(&tx) 466 }) 467 468 eip2935Stem := utils.GetTreeKey(params.HistoryStorageAddress[:], uint256.NewInt(0), 0) 469 eip2935Stem = eip2935Stem[:31] 470 471 for _, stemStateDiff := range statediffs[0] { 472 // Handle the case of the history contract: make sure only the correct 473 // slots are added to the witness. 474 if bytes.Equal(stemStateDiff.Stem[:], eip2935Stem) { 475 // BLOCKHASH contract stem 476 if len(stemStateDiff.SuffixDiffs) > 1 { 477 t.Fatalf("invalid suffix diff count found for BLOCKHASH contract: %d != 1", len(stemStateDiff.SuffixDiffs)) 478 } 479 if stemStateDiff.SuffixDiffs[0].Suffix != 64 { 480 t.Fatalf("invalid suffix diff value found for BLOCKHASH contract: %d != 64", stemStateDiff.SuffixDiffs[0].Suffix) 481 } 482 // check that the "current value" is nil and that the new value isn't. 483 if stemStateDiff.SuffixDiffs[0].CurrentValue != nil { 484 t.Fatalf("non-nil current value in BLOCKHASH contract insert: %x", stemStateDiff.SuffixDiffs[0].CurrentValue) 485 } 486 if stemStateDiff.SuffixDiffs[0].NewValue == nil { 487 t.Fatalf("nil new value in BLOCKHASH contract insert") 488 } 489 if *stemStateDiff.SuffixDiffs[0].NewValue != genesisH { 490 t.Fatalf("invalid BLOCKHASH value: %x != %x", *stemStateDiff.SuffixDiffs[0].NewValue, genesisH) 491 } 492 } else { 493 for _, suffixDiff := range stemStateDiff.SuffixDiffs { 494 if suffixDiff.Suffix > 2 { 495 // if d8898012c484fb48610ecb7963886339207dab004bce968b007b616ffa18e0 shows up, it means that the PUSHn 496 // in the transaction above added entries into the witness, when they should not have since they are 497 // part of a contract deployment. 498 t.Fatalf("invalid suffix diff found for %x in block #1: %d\n", stemStateDiff.Stem, suffixDiff.Suffix) 499 } 500 } 501 } 502 } 503 } 504 505 // TestProcessVerkleExtCodeHashOpcode verifies that calling EXTCODEHASH on another 506 // deployed contract, creates all the right entries in the witness. 507 func TestProcessVerkleExtCodeHashOpcode(t *testing.T) { 508 // The test txs were taken from a secondary testnet with chain id 69421 509 config := *testKaustinenLikeChainConfig 510 config.ChainID.SetUint64(69421) 511 512 var ( 513 signer = types.LatestSigner(&config) 514 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 515 gspec = verkleTestGenesis(&config) 516 ) 517 dummyContract := []byte{ 518 byte(vm.PUSH1), 2, 519 byte(vm.PUSH1), 12, 520 byte(vm.PUSH1), 0x00, 521 byte(vm.CODECOPY), 522 523 byte(vm.PUSH1), 2, 524 byte(vm.PUSH1), 0x00, 525 byte(vm.RETURN), 526 527 byte(vm.PUSH1), 42, 528 } 529 deployer := crypto.PubkeyToAddress(testKey.PublicKey) 530 dummyContractAddr := crypto.CreateAddress(deployer, 0) 531 532 // contract that calls EXTCODEHASH on the dummy contract 533 extCodeHashContract := []byte{ 534 byte(vm.PUSH1), 22, 535 byte(vm.PUSH1), 12, 536 byte(vm.PUSH1), 0x00, 537 byte(vm.CODECOPY), 538 539 byte(vm.PUSH1), 22, 540 byte(vm.PUSH1), 0x00, 541 byte(vm.RETURN), 542 543 byte(vm.PUSH20), 544 0x3a, 0x22, 0x0f, 0x35, 0x12, 0x52, 0x08, 0x9d, 0x38, 0x5b, 0x29, 0xbe, 0xca, 0x14, 0xe2, 0x7f, 0x20, 0x4c, 0x29, 0x6a, 545 byte(vm.EXTCODEHASH), 546 } 547 extCodeHashContractAddr := crypto.CreateAddress(deployer, 1) 548 549 _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { 550 gen.SetPoS() 551 552 if i == 0 { 553 // Create dummy contract. 554 tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, 555 Value: big.NewInt(0), 556 Gas: 100_000, 557 GasPrice: big.NewInt(875000000), 558 Data: dummyContract, 559 }) 560 gen.AddTx(tx) 561 562 // Create contract with EXTCODEHASH opcode. 563 tx, _ = types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 1, 564 Value: big.NewInt(0), 565 Gas: 100_000, 566 GasPrice: big.NewInt(875000000), 567 Data: extCodeHashContract}) 568 gen.AddTx(tx) 569 } else { 570 tx, _ := types.SignTx(types.NewTransaction(2, extCodeHashContractAddr, big.NewInt(0), 100_000, big.NewInt(875000000), nil), signer, testKey) 571 gen.AddTx(tx) 572 } 573 }) 574 575 contractKeccakTreeKey := utils.CodeHashKey(dummyContractAddr[:]) 576 577 var stateDiffIdx = -1 578 for i, stemStateDiff := range statediffs[1] { 579 if bytes.Equal(stemStateDiff.Stem[:], contractKeccakTreeKey[:31]) { 580 stateDiffIdx = i 581 break 582 } 583 } 584 if stateDiffIdx == -1 { 585 t.Fatalf("no state diff found for stem") 586 } 587 588 codeHashStateDiff := statediffs[1][stateDiffIdx].SuffixDiffs[0] 589 // Check location of code hash was accessed 590 if codeHashStateDiff.Suffix != utils.CodeHashLeafKey { 591 t.Fatalf("code hash invalid suffix") 592 } 593 // check the code hash wasn't present in the prestate, as 594 // the contract was deployed in this block. 595 if codeHashStateDiff.CurrentValue == nil { 596 t.Fatalf("codeHash.CurrentValue must not be empty") 597 } 598 // check the poststate value corresponds to the code hash 599 // of the deployed contract. 600 expCodeHash := crypto.Keccak256Hash(dummyContract[12:]) 601 if *codeHashStateDiff.CurrentValue != expCodeHash { 602 t.Fatalf("codeHash.CurrentValue unexpected code hash") 603 } 604 if codeHashStateDiff.NewValue != nil { 605 t.Fatalf("codeHash.NewValue must be nil") 606 } 607 } 608 609 // TestProcessVerkleBalanceOpcode checks that calling balance 610 // on another contract will add the correct entries to the witness. 611 func TestProcessVerkleBalanceOpcode(t *testing.T) { 612 // The test txs were taken from a secondary testnet with chain id 69421 613 config := *testKaustinenLikeChainConfig 614 config.ChainID.SetUint64(69421) 615 616 var ( 617 signer = types.LatestSigner(&config) 618 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 619 account2 = common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d") 620 gspec = verkleTestGenesis(&config) 621 ) 622 _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { 623 gen.SetPoS() 624 txData := slices.Concat( 625 []byte{byte(vm.PUSH20)}, 626 common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d").Bytes(), 627 []byte{byte(vm.BALANCE)}) 628 629 tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, 630 Value: big.NewInt(0), 631 Gas: 100_000, 632 GasPrice: big.NewInt(875000000), 633 Data: txData}) 634 gen.AddTx(tx) 635 }) 636 637 account2BalanceTreeKey := utils.BasicDataKey(account2[:]) 638 639 var stateDiffIdx = -1 640 for i, stemStateDiff := range statediffs[0] { 641 if bytes.Equal(stemStateDiff.Stem[:], account2BalanceTreeKey[:31]) { 642 stateDiffIdx = i 643 break 644 } 645 } 646 if stateDiffIdx == -1 { 647 t.Fatalf("no state diff found for stem") 648 } 649 650 var zero [32]byte 651 balanceStateDiff := statediffs[0][stateDiffIdx].SuffixDiffs[0] 652 if balanceStateDiff.Suffix != utils.BasicDataLeafKey { 653 t.Fatalf("invalid suffix diff") 654 } 655 // check the prestate balance wasn't 0 or missing 656 if balanceStateDiff.CurrentValue == nil || *balanceStateDiff.CurrentValue == zero { 657 t.Fatalf("invalid current value %v", *balanceStateDiff.CurrentValue) 658 } 659 // check that the poststate witness value for the balance is nil, 660 // meaning that it didn't get updated. 661 if balanceStateDiff.NewValue != nil { 662 t.Fatalf("invalid new value") 663 } 664 } 665 666 // TestProcessVerkleSelfDestructInSeparateTx controls the contents of the witness after 667 // a non-eip6780-compliant selfdestruct occurs. 668 func TestProcessVerkleSelfDestructInSeparateTx(t *testing.T) { 669 // The test txs were taken from a secondary testnet with chain id 69421 670 config := *testKaustinenLikeChainConfig 671 config.ChainID.SetUint64(69421) 672 673 var ( 674 signer = types.LatestSigner(&config) 675 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 676 account2 = common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d") 677 gspec = verkleTestGenesis(&config) 678 ) 679 680 // runtime code: selfdestruct ( 0x6177843db3138ae69679A54b95cf345ED759450d ) 681 runtimeCode := slices.Concat( 682 []byte{byte(vm.PUSH20)}, 683 account2.Bytes(), 684 []byte{byte(vm.SELFDESTRUCT)}) 685 686 //The goal of this test is to test SELFDESTRUCT that happens in a contract 687 // execution which is created in a previous transaction. 688 selfDestructContract := slices.Concat([]byte{ 689 byte(vm.PUSH1), byte(len(runtimeCode)), 690 byte(vm.PUSH1), 12, 691 byte(vm.PUSH1), 0x00, 692 byte(vm.CODECOPY), // Codecopy( to-offset: 0, code offset: 12, length: 22 ) 693 694 byte(vm.PUSH1), byte(len(runtimeCode)), 695 byte(vm.PUSH1), 0x00, 696 byte(vm.RETURN), // Return ( 0 : len(runtimecode) 697 }, 698 runtimeCode) 699 700 deployer := crypto.PubkeyToAddress(testKey.PublicKey) 701 contract := crypto.CreateAddress(deployer, 0) 702 703 _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { 704 gen.SetPoS() 705 706 if i == 0 { 707 // Create selfdestruct contract, sending 42 wei. 708 tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, 709 Value: big.NewInt(42), 710 Gas: 100_000, 711 GasPrice: big.NewInt(875000000), 712 Data: selfDestructContract, 713 }) 714 gen.AddTx(tx) 715 } else { 716 // Call it. 717 tx, _ := types.SignTx(types.NewTransaction(1, contract, big.NewInt(0), 100_000, big.NewInt(875000000), nil), signer, testKey) 718 gen.AddTx(tx) 719 } 720 }) 721 722 var zero [32]byte 723 { // Check self-destructed contract in the witness 724 selfDestructContractTreeKey := utils.CodeHashKey(contract[:]) 725 726 var stateDiffIdx = -1 727 for i, stemStateDiff := range statediffs[1] { 728 if bytes.Equal(stemStateDiff.Stem[:], selfDestructContractTreeKey[:31]) { 729 stateDiffIdx = i 730 break 731 } 732 } 733 if stateDiffIdx == -1 { 734 t.Fatalf("no state diff found for stem") 735 } 736 737 balanceStateDiff := statediffs[1][stateDiffIdx].SuffixDiffs[0] 738 if balanceStateDiff.Suffix != utils.BasicDataLeafKey { 739 t.Fatalf("balance invalid suffix") 740 } 741 742 // The original balance was 42. 743 var oldBalance [16]byte 744 oldBalance[15] = 42 745 if !bytes.Equal((*balanceStateDiff.CurrentValue)[utils.BasicDataBalanceOffset:], oldBalance[:]) { 746 t.Fatalf("the pre-state balance before self-destruct must be %x, got %x", oldBalance, *balanceStateDiff.CurrentValue) 747 } 748 749 // The new balance must be 0. 750 if !bytes.Equal((*balanceStateDiff.NewValue)[utils.BasicDataBalanceOffset:], zero[utils.BasicDataBalanceOffset:]) { 751 t.Fatalf("the post-state balance after self-destruct must be 0") 752 } 753 } 754 { // Check self-destructed target in the witness. 755 selfDestructTargetTreeKey := utils.CodeHashKey(account2[:]) 756 757 var stateDiffIdx = -1 758 for i, stemStateDiff := range statediffs[1] { 759 if bytes.Equal(stemStateDiff.Stem[:], selfDestructTargetTreeKey[:31]) { 760 stateDiffIdx = i 761 break 762 } 763 } 764 if stateDiffIdx == -1 { 765 t.Fatalf("no state diff found for stem") 766 } 767 768 balanceStateDiff := statediffs[1][stateDiffIdx].SuffixDiffs[0] 769 if balanceStateDiff.Suffix != utils.BasicDataLeafKey { 770 t.Fatalf("balance invalid suffix") 771 } 772 if balanceStateDiff.CurrentValue == nil { 773 t.Fatalf("codeHash.CurrentValue must not be empty") 774 } 775 if balanceStateDiff.NewValue == nil { 776 t.Fatalf("codeHash.NewValue must not be empty") 777 } 778 preStateBalance := binary.BigEndian.Uint64(balanceStateDiff.CurrentValue[utils.BasicDataBalanceOffset+8:]) 779 postStateBalance := binary.BigEndian.Uint64(balanceStateDiff.NewValue[utils.BasicDataBalanceOffset+8:]) 780 if postStateBalance-preStateBalance != 42 { 781 t.Fatalf("the post-state balance after self-destruct must be 42, got %d-%d=%d", postStateBalance, preStateBalance, postStateBalance-preStateBalance) 782 } 783 } 784 } 785 786 // TestProcessVerkleSelfDestructInSeparateTx controls the contents of the witness after 787 // a eip6780-compliant selfdestruct occurs. 788 func TestProcessVerkleSelfDestructInSameTx(t *testing.T) { 789 // The test txs were taken from a secondary testnet with chain id 69421 790 config := *testKaustinenLikeChainConfig 791 config.ChainID.SetUint64(69421) 792 793 var ( 794 signer = types.LatestSigner(&config) 795 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 796 account2 = common.HexToAddress("0x6177843db3138ae69679A54b95cf345ED759450d") 797 gspec = verkleTestGenesis(&config) 798 ) 799 800 // The goal of this test is to test SELFDESTRUCT that happens in a contract 801 // execution which is created in **the same** transaction sending the remaining 802 // balance to an external (i.e: not itself) account. 803 804 selfDestructContract := slices.Concat( 805 []byte{byte(vm.PUSH20)}, 806 account2.Bytes(), 807 []byte{byte(vm.SELFDESTRUCT)}) 808 deployer := crypto.PubkeyToAddress(testKey.PublicKey) 809 contract := crypto.CreateAddress(deployer, 0) 810 811 _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { 812 gen.SetPoS() 813 tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, 814 Value: big.NewInt(42), 815 Gas: 100_000, 816 GasPrice: big.NewInt(875000000), 817 Data: selfDestructContract, 818 }) 819 gen.AddTx(tx) 820 }) 821 822 { // Check self-destructed contract in the witness 823 selfDestructContractTreeKey := utils.CodeHashKey(contract[:]) 824 825 var stateDiffIdx = -1 826 for i, stemStateDiff := range statediffs[0] { 827 if bytes.Equal(stemStateDiff.Stem[:], selfDestructContractTreeKey[:31]) { 828 stateDiffIdx = i 829 break 830 } 831 } 832 if stateDiffIdx == -1 { 833 t.Fatalf("no state diff found for stem") 834 } 835 836 balanceStateDiff := statediffs[0][stateDiffIdx].SuffixDiffs[0] 837 if balanceStateDiff.Suffix != utils.BasicDataLeafKey { 838 t.Fatalf("balance invalid suffix") 839 } 840 841 if balanceStateDiff.CurrentValue != nil { 842 t.Fatalf("the pre-state balance before must be nil, since the contract didn't exist") 843 } 844 845 if balanceStateDiff.NewValue != nil { 846 t.Fatalf("the post-state balance after self-destruct must be nil since the contract shouldn't be created at all") 847 } 848 } 849 { // Check self-destructed target in the witness. 850 selfDestructTargetTreeKey := utils.CodeHashKey(account2[:]) 851 852 var stateDiffIdx = -1 853 for i, stemStateDiff := range statediffs[0] { 854 if bytes.Equal(stemStateDiff.Stem[:], selfDestructTargetTreeKey[:31]) { 855 stateDiffIdx = i 856 break 857 } 858 } 859 if stateDiffIdx == -1 { 860 t.Fatalf("no state diff found for stem") 861 } 862 863 balanceStateDiff := statediffs[0][stateDiffIdx].SuffixDiffs[0] 864 if balanceStateDiff.Suffix != utils.BasicDataLeafKey { 865 t.Fatalf("balance invalid suffix") 866 } 867 if balanceStateDiff.CurrentValue == nil { 868 t.Fatalf("codeHash.CurrentValue must not be empty") 869 } 870 if balanceStateDiff.NewValue == nil { 871 t.Fatalf("codeHash.NewValue must not be empty") 872 } 873 preStateBalance := binary.BigEndian.Uint64(balanceStateDiff.CurrentValue[utils.BasicDataBalanceOffset+8:]) 874 postStateBalance := binary.BigEndian.Uint64(balanceStateDiff.NewValue[utils.BasicDataBalanceOffset+8:]) 875 if postStateBalance-preStateBalance != 42 { 876 t.Fatalf("the post-state balance after self-destruct must be 42. got %d", postStateBalance) 877 } 878 } 879 } 880 881 // TestProcessVerkleSelfDestructInSeparateTxWithSelfBeneficiary checks the content of the witness 882 // if a selfdestruct occurs in a different tx than the one that created it, but the beneficiary 883 // is the selfdestructed account. 884 func TestProcessVerkleSelfDestructInSeparateTxWithSelfBeneficiary(t *testing.T) { 885 // The test txs were taken from a secondary testnet with chain id 69421 886 config := *testKaustinenLikeChainConfig 887 config.ChainID.SetUint64(69421) 888 889 var ( 890 signer = types.LatestSigner(&config) 891 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 892 gspec = verkleTestGenesis(&config) 893 ) 894 // The goal of this test is to test SELFDESTRUCT that happens in a contract 895 // execution which is created in a *previous* transaction sending the remaining 896 // balance to itself. 897 selfDestructContract := []byte{ 898 byte(vm.PUSH1), 2, // PUSH1 2 899 byte(vm.PUSH1), 10, // PUSH1 12 900 byte(vm.PUSH0), // PUSH0 901 byte(vm.CODECOPY), // Codecopy ( to offset 0, code@offset: 10, length: 2) 902 903 byte(vm.PUSH1), 22, 904 byte(vm.PUSH0), 905 byte(vm.RETURN), // RETURN( memory[0:2] ) 906 907 // Deployed code 908 byte(vm.ADDRESS), 909 byte(vm.SELFDESTRUCT), 910 } 911 deployer := crypto.PubkeyToAddress(testKey.PublicKey) 912 contract := crypto.CreateAddress(deployer, 0) 913 914 _, _, _, _, _, statediffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 2, func(i int, gen *BlockGen) { 915 gen.SetPoS() 916 if i == 0 { 917 // Create self-destruct contract, sending 42 wei. 918 tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, 919 Value: big.NewInt(42), 920 Gas: 100_000, 921 GasPrice: big.NewInt(875000000), 922 Data: selfDestructContract, 923 }) 924 gen.AddTx(tx) 925 } else { 926 // Call it. 927 tx, _ := types.SignTx(types.NewTransaction(1, contract, big.NewInt(0), 100_000, big.NewInt(875000000), nil), signer, testKey) 928 gen.AddTx(tx) 929 } 930 }) 931 932 { 933 // Check self-destructed contract in the witness. 934 // The way 6780 is implemented today, it always SubBalance from the self-destructed contract, and AddBalance 935 // to the beneficiary. In this case both addresses are the same, thus this might be optimizable from a gas 936 // perspective. But until that happens, we need to honor this "balance reading" adding it to the witness. 937 938 selfDestructContractTreeKey := utils.CodeHashKey(contract[:]) 939 940 var stateDiffIdx = -1 941 for i, stemStateDiff := range statediffs[1] { 942 if bytes.Equal(stemStateDiff.Stem[:], selfDestructContractTreeKey[:31]) { 943 stateDiffIdx = i 944 break 945 } 946 } 947 if stateDiffIdx == -1 { 948 t.Fatal("no state diff found for stem") 949 } 950 951 balanceStateDiff := statediffs[1][stateDiffIdx].SuffixDiffs[0] 952 if balanceStateDiff.Suffix != utils.BasicDataLeafKey { 953 t.Fatal("balance invalid suffix") 954 } 955 956 // The original balance was 42. 957 var oldBalance [16]byte 958 oldBalance[15] = 42 959 if !bytes.Equal((*balanceStateDiff.CurrentValue)[utils.BasicDataBalanceOffset:], oldBalance[:]) { 960 t.Fatal("the pre-state balance before self-destruct must be 42") 961 } 962 963 // Note that the SubBalance+AddBalance net effect is a 0 change, so NewValue 964 // must be nil. 965 if balanceStateDiff.NewValue != nil { 966 t.Fatal("the post-state balance after self-destruct must be empty") 967 } 968 } 969 } 970 971 // TestProcessVerkleSelfDestructInSameTxWithSelfBeneficiary checks the content of the witness 972 // if a selfdestruct occurs in the same tx as the one that created it, but the beneficiary 973 // is the selfdestructed account. 974 func TestProcessVerkleSelfDestructInSameTxWithSelfBeneficiary(t *testing.T) { 975 // The test txs were taken from a secondary testnet with chain id 69421 976 config := *testKaustinenLikeChainConfig 977 config.ChainID.SetUint64(69421) 978 979 var ( 980 signer = types.LatestSigner(&config) 981 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 982 gspec = verkleTestGenesis(&config) 983 deployer = crypto.PubkeyToAddress(testKey.PublicKey) 984 contract = crypto.CreateAddress(deployer, 0) 985 ) 986 987 // The goal of this test is to test SELFDESTRUCT that happens while executing 988 // the init code of a contract creation, that occurs in **the same** transaction. 989 // The balance is sent to itself. 990 t.Logf("Contract: %v", contract.String()) 991 992 selfDestructContract := []byte{byte(vm.ADDRESS), byte(vm.SELFDESTRUCT)} 993 994 _, _, _, _, _, stateDiffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { 995 gen.SetPoS() 996 tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, 997 Value: big.NewInt(42), 998 Gas: 100_000, 999 GasPrice: big.NewInt(875000000), 1000 Data: selfDestructContract, 1001 }) 1002 gen.AddTx(tx) 1003 }) 1004 stateDiff := stateDiffs[0] // state difference of block 1 1005 1006 { // Check self-destructed contract in the witness 1007 selfDestructContractTreeKey := utils.CodeHashKey(contract[:]) 1008 1009 var stateDiffIdx = -1 1010 for i, stemStateDiff := range stateDiff { 1011 if bytes.Equal(stemStateDiff.Stem[:], selfDestructContractTreeKey[:31]) { 1012 stateDiffIdx = i 1013 break 1014 } 1015 } 1016 if stateDiffIdx == -1 { 1017 t.Fatal("no state diff found for stem") 1018 } 1019 balanceStateDiff := stateDiff[stateDiffIdx].SuffixDiffs[0] 1020 if balanceStateDiff.Suffix != utils.BasicDataLeafKey { 1021 t.Fatal("balance invalid suffix") 1022 } 1023 if balanceStateDiff.CurrentValue != nil { 1024 t.Fatal("the pre-state balance before must be nil, since the contract didn't exist") 1025 } 1026 // Ensure that the value is burnt, and therefore that the balance of the self-destructed 1027 // contract isn't modified (it should remain missing from the state) 1028 if balanceStateDiff.NewValue != nil { 1029 t.Fatal("the post-state balance after self-destruct must be nil since the contract shouldn't be created at all") 1030 } 1031 } 1032 } 1033 1034 // TestProcessVerkleSelfDestructInSameTxWithSelfBeneficiaryAndPrefundedAccount checks the 1035 // content of the witness if a selfdestruct occurs in the same tx as the one that created it, 1036 // it, but the beneficiary is the selfdestructed account. The difference with the test above, 1037 // is that the created account is prefunded and so the final value should be 0. 1038 func TestProcessVerkleSelfDestructInSameTxWithSelfBeneficiaryAndPrefundedAccount(t *testing.T) { 1039 // The test txs were taken from a secondary testnet with chain id 69421 1040 config := *testKaustinenLikeChainConfig 1041 config.ChainID.SetUint64(69421) 1042 1043 var ( 1044 signer = types.LatestSigner(&config) 1045 testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 1046 gspec = verkleTestGenesis(&config) 1047 deployer = crypto.PubkeyToAddress(testKey.PublicKey) 1048 contract = crypto.CreateAddress(deployer, 0) 1049 ) 1050 // Prefund the account, at an address that the contract will be deployed at, 1051 // before it selfdestrucs. We can therefore check that the account itseld is 1052 // NOT destroyed, which is what the current version of the spec requires. 1053 // TODO(gballet) revisit after the spec has been modified. 1054 gspec.Alloc[contract] = types.Account{ 1055 Balance: big.NewInt(100), 1056 } 1057 1058 selfDestructContract := []byte{byte(vm.ADDRESS), byte(vm.SELFDESTRUCT)} 1059 1060 _, _, _, _, _, stateDiffs := GenerateVerkleChainWithGenesis(gspec, beacon.New(ethash.NewFaker()), 1, func(i int, gen *BlockGen) { 1061 gen.SetPoS() 1062 tx, _ := types.SignNewTx(testKey, signer, &types.LegacyTx{Nonce: 0, 1063 Value: big.NewInt(42), 1064 Gas: 100_000, 1065 GasPrice: big.NewInt(875000000), 1066 Data: selfDestructContract, 1067 }) 1068 gen.AddTx(tx) 1069 }) 1070 stateDiff := stateDiffs[0] // state difference of block 1 1071 1072 { // Check self-destructed contract in the witness 1073 selfDestructContractTreeKey := utils.CodeHashKey(contract[:]) 1074 1075 var stateDiffIdx = -1 1076 for i, stemStateDiff := range stateDiff { 1077 if bytes.Equal(stemStateDiff.Stem[:], selfDestructContractTreeKey[:31]) { 1078 stateDiffIdx = i 1079 break 1080 } 1081 } 1082 if stateDiffIdx == -1 { 1083 t.Fatal("no state diff found for stem") 1084 } 1085 balanceStateDiff := stateDiff[stateDiffIdx].SuffixDiffs[0] 1086 if balanceStateDiff.Suffix != utils.BasicDataLeafKey { 1087 t.Fatal("balance invalid suffix") 1088 } 1089 expected, _ := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000064") 1090 if balanceStateDiff.CurrentValue == nil || !bytes.Equal(balanceStateDiff.CurrentValue[:], expected) { 1091 t.Fatalf("incorrect prestate balance: %x != %x", *balanceStateDiff.CurrentValue, expected) 1092 } 1093 // Ensure that the value is burnt, and therefore that the balance of the self-destructed 1094 // contract isn't modified (it should remain missing from the state) 1095 expected = make([]byte, 32) 1096 if balanceStateDiff.NewValue == nil { 1097 t.Fatal("incorrect nil poststate balance") 1098 } 1099 if !bytes.Equal(balanceStateDiff.NewValue[:], expected[:]) { 1100 t.Fatalf("incorrect poststate balance: %x != %x", *balanceStateDiff.NewValue, expected[:]) 1101 } 1102 } 1103 }