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 }