github.com/ethereum/go-ethereum@v1.16.1/core/state/statedb_hooked_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 state
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"testing"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/core/tracing"
    26  	"github.com/ethereum/go-ethereum/core/types"
    27  	"github.com/holiman/uint256"
    28  )
    29  
    30  // This method tests that the 'burn' from sending-to-selfdestructed accounts
    31  // is accounted for.
    32  // (There is also a higher-level test in eth/tracers: TestSupplySelfDestruct )
    33  func TestBurn(t *testing.T) {
    34  	// Note: burn can happen even after EIP-6780, if within one single transaction,
    35  	// the following occur:
    36  	// 1. contract B creates contract A
    37  	// 2. contract A is destructed
    38  	// 3. contract B sends ether to A
    39  
    40  	var burned = new(uint256.Int)
    41  	s, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
    42  	hooked := NewHookedState(s, &tracing.Hooks{
    43  		OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
    44  			if reason == tracing.BalanceDecreaseSelfdestructBurn {
    45  				burned.Add(burned, uint256.MustFromBig(prev))
    46  			}
    47  		},
    48  	})
    49  	createAndDestroy := func(addr common.Address) {
    50  		hooked.AddBalance(addr, uint256.NewInt(100), tracing.BalanceChangeUnspecified)
    51  		hooked.CreateContract(addr)
    52  		hooked.SelfDestruct(addr)
    53  		// sanity-check that balance is now 0
    54  		if have, want := hooked.GetBalance(addr), new(uint256.Int); !have.Eq(want) {
    55  			t.Fatalf("post-destruct balance wrong: have %v want %v", have, want)
    56  		}
    57  	}
    58  	addA := common.Address{0xaa}
    59  	addB := common.Address{0xbb}
    60  	addC := common.Address{0xcc}
    61  
    62  	// Tx 1: create and destroy address A and B in one tx
    63  	createAndDestroy(addA)
    64  	createAndDestroy(addB)
    65  	hooked.AddBalance(addA, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
    66  	hooked.AddBalance(addB, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
    67  	hooked.Finalise(true)
    68  
    69  	// Tx 2: create and destroy address C, then commit
    70  	createAndDestroy(addC)
    71  	hooked.AddBalance(addC, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
    72  	hooked.Finalise(true)
    73  
    74  	s.Commit(0, false, false)
    75  	if have, want := burned, uint256.NewInt(600); !have.Eq(want) {
    76  		t.Fatalf("burn-count wrong, have %v want %v", have, want)
    77  	}
    78  }
    79  
    80  // TestHooks is a basic sanity-check of all hooks
    81  func TestHooks(t *testing.T) {
    82  	inner, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
    83  	inner.SetTxContext(common.Hash{0x11}, 100) // For the log
    84  	var result []string
    85  	var wants = []string{
    86  		"0xaa00000000000000000000000000000000000000.balance: 0->100 (Unspecified)",
    87  		"0xaa00000000000000000000000000000000000000.balance: 100->50 (Transfer)",
    88  		"0xaa00000000000000000000000000000000000000.nonce: 0->1337",
    89  		"0xaa00000000000000000000000000000000000000.code:  (0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) ->0x1325 (0xa12ae05590de0c93a00bc7ac773c2fdb621e44f814985e72194f921c0050f728)",
    90  		"0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000000 ->0x0000000000000000000000000000000000000000000000000000000000000011",
    91  		"0xaa00000000000000000000000000000000000000.storage slot 0x0000000000000000000000000000000000000000000000000000000000000001: 0x0000000000000000000000000000000000000000000000000000000000000011 ->0x0000000000000000000000000000000000000000000000000000000000000022",
    92  		"log 100",
    93  	}
    94  	emitF := func(format string, a ...any) {
    95  		result = append(result, fmt.Sprintf(format, a...))
    96  	}
    97  	sdb := NewHookedState(inner, &tracing.Hooks{
    98  		OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
    99  			emitF("%v.balance: %v->%v (%v)", addr, prev, new, reason)
   100  		},
   101  		OnNonceChange: func(addr common.Address, prev, new uint64) {
   102  			emitF("%v.nonce: %v->%v", addr, prev, new)
   103  		},
   104  		OnCodeChange: func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte) {
   105  			emitF("%v.code: %#x (%v) ->%#x (%v)", addr, prevCode, prevCodeHash, code, codeHash)
   106  		},
   107  		OnStorageChange: func(addr common.Address, slot common.Hash, prev, new common.Hash) {
   108  			emitF("%v.storage slot %v: %v ->%v", addr, slot, prev, new)
   109  		},
   110  		OnLog: func(log *types.Log) {
   111  			emitF("log %v", log.TxIndex)
   112  		},
   113  	})
   114  	sdb.AddBalance(common.Address{0xaa}, uint256.NewInt(100), tracing.BalanceChangeUnspecified)
   115  	sdb.SubBalance(common.Address{0xaa}, uint256.NewInt(50), tracing.BalanceChangeTransfer)
   116  	sdb.SetNonce(common.Address{0xaa}, 1337, tracing.NonceChangeGenesis)
   117  	sdb.SetCode(common.Address{0xaa}, []byte{0x13, 37})
   118  	sdb.SetState(common.Address{0xaa}, common.HexToHash("0x01"), common.HexToHash("0x11"))
   119  	sdb.SetState(common.Address{0xaa}, common.HexToHash("0x01"), common.HexToHash("0x22"))
   120  	sdb.SetTransientState(common.Address{0xaa}, common.HexToHash("0x02"), common.HexToHash("0x01"))
   121  	sdb.SetTransientState(common.Address{0xaa}, common.HexToHash("0x02"), common.HexToHash("0x02"))
   122  	sdb.AddLog(&types.Log{
   123  		Address: common.Address{0xbb},
   124  	})
   125  	for i, want := range wants {
   126  		if have := result[i]; have != want {
   127  			t.Fatalf("error event %d, have\n%v\nwant%v\n", i, have, want)
   128  		}
   129  	}
   130  }