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 = &params.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: &params.BlobScheduleConfig{
    63  			Verkle: params.DefaultPragueBlobConfig,
    64  		},
    65  		// TODO uncomment when proof generation is merged
    66  		// ProofInBlocks:                 true,
    67  	}
    68  	testKaustinenLikeChainConfig = &params.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: &params.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  }