github.com/onflow/flow-go@v0.33.17/fvm/evm/emulator/state/base_test.go (about) 1 package state_test 2 3 import ( 4 "math/big" 5 "testing" 6 7 gethCommon "github.com/ethereum/go-ethereum/common" 8 gethTypes "github.com/ethereum/go-ethereum/core/types" 9 "github.com/stretchr/testify/require" 10 11 "github.com/onflow/flow-go/fvm/evm/emulator/state" 12 "github.com/onflow/flow-go/fvm/evm/testutils" 13 "github.com/onflow/flow-go/fvm/evm/types" 14 "github.com/onflow/flow-go/model/flow" 15 ) 16 17 func TestBaseView(t *testing.T) { 18 t.Parallel() 19 20 t.Run("test account functionalities", func(t *testing.T) { 21 ledger := testutils.GetSimpleValueStore() 22 rootAddr := flow.Address{1, 2, 3, 4, 5, 6, 7, 8} 23 view, err := state.NewBaseView(ledger, rootAddr) 24 require.NoError(t, err) 25 26 addr1 := testutils.RandomCommonAddress(t) 27 28 // data calls for a non-existent account 29 checkAccount(t, 30 view, 31 addr1, 32 false, 33 big.NewInt(0), 34 uint64(0), 35 nil, 36 gethTypes.EmptyCodeHash, 37 ) 38 39 // create an account with code 40 newBal := big.NewInt(10) 41 newNonce := uint64(5) 42 newCode := []byte("some code") 43 newCodeHash := gethCommon.Hash{1, 2} 44 45 err = view.CreateAccount(addr1, newBal, newNonce, newCode, newCodeHash) 46 require.NoError(t, err) 47 48 // check data from cache 49 checkAccount(t, 50 view, 51 addr1, 52 true, 53 newBal, 54 newNonce, 55 newCode, 56 newCodeHash, 57 ) 58 59 // commit the changes and create a new baseview 60 err = view.Commit() 61 require.NoError(t, err) 62 63 view, err = state.NewBaseView(ledger, rootAddr) 64 require.NoError(t, err) 65 66 checkAccount(t, 67 view, 68 addr1, 69 true, 70 newBal, 71 newNonce, 72 newCode, 73 newCodeHash, 74 ) 75 76 // test update account 77 78 newBal = big.NewInt(12) 79 newNonce = uint64(6) 80 newCode = []byte("some new code") 81 newCodeHash = gethCommon.Hash{2, 3} 82 err = view.UpdateAccount(addr1, newBal, newNonce, newCode, newCodeHash) 83 require.NoError(t, err) 84 85 // check data from cache 86 checkAccount(t, 87 view, 88 addr1, 89 true, 90 newBal, 91 newNonce, 92 newCode, 93 newCodeHash, 94 ) 95 96 // commit the changes and create a new baseview 97 err = view.Commit() 98 require.NoError(t, err) 99 100 view, err = state.NewBaseView(ledger, rootAddr) 101 require.NoError(t, err) 102 103 checkAccount(t, 104 view, 105 addr1, 106 true, 107 newBal, 108 newNonce, 109 newCode, 110 newCodeHash, 111 ) 112 113 // test delete account 114 115 err = view.DeleteAccount(addr1) 116 require.NoError(t, err) 117 118 // check from cache 119 checkAccount(t, 120 view, 121 addr1, 122 false, 123 big.NewInt(0), 124 uint64(0), 125 nil, 126 gethTypes.EmptyCodeHash, 127 ) 128 129 // commit the changes and create a new baseview 130 err = view.Commit() 131 require.NoError(t, err) 132 133 view, err = state.NewBaseView(ledger, rootAddr) 134 require.NoError(t, err) 135 136 checkAccount(t, 137 view, 138 addr1, 139 false, 140 big.NewInt(0), 141 uint64(0), 142 nil, 143 gethTypes.EmptyCodeHash, 144 ) 145 }) 146 147 t.Run("test slot storage", func(t *testing.T) { 148 ledger := testutils.GetSimpleValueStore() 149 rootAddr := flow.Address{1, 2, 3, 4, 5, 6, 7, 8} 150 view, err := state.NewBaseView(ledger, rootAddr) 151 require.NoError(t, err) 152 153 addr1 := testutils.RandomCommonAddress(t) 154 key1 := testutils.RandomCommonHash(t) 155 slot1 := types.SlotAddress{ 156 Address: addr1, 157 Key: key1, 158 } 159 160 // non-existent account 161 value, err := view.GetState(slot1) 162 require.NoError(t, err) 163 require.Equal(t, value, gethCommon.Hash{}) 164 165 // store a new value 166 newValue := testutils.RandomCommonHash(t) 167 168 // updating slot for non-existent account should fail 169 err = view.UpdateSlot(slot1, newValue) 170 require.Error(t, err) 171 172 // account should have code to have slots 173 err = view.CreateAccount(addr1, big.NewInt(10), 0, []byte("ABC"), gethCommon.Hash{1, 2, 3}) 174 require.NoError(t, err) 175 176 err = view.UpdateSlot(slot1, newValue) 177 require.NoError(t, err) 178 179 // return result from the cache 180 value, err = view.GetState(slot1) 181 require.NoError(t, err) 182 require.Equal(t, newValue, value) 183 184 // commit changes 185 err = view.Commit() 186 require.NoError(t, err) 187 188 view2, err := state.NewBaseView(ledger, rootAddr) 189 require.NoError(t, err) 190 191 // return state from ledger 192 value, err = view2.GetState(slot1) 193 require.NoError(t, err) 194 require.Equal(t, newValue, value) 195 }) 196 197 t.Run("default values method calls", func(t *testing.T) { 198 // calls to these method that has always same value 199 view, err := state.NewBaseView(testutils.GetSimpleValueStore(), flow.Address{1, 2, 3, 4}) 200 require.NoError(t, err) 201 202 dest, bal := view.HasSelfDestructed(gethCommon.Address{}) 203 require.Equal(t, false, dest) 204 require.Equal(t, new(big.Int), bal) 205 require.Equal(t, false, view.IsCreated(gethCommon.Address{})) 206 require.Equal(t, uint64(0), view.GetRefund()) 207 require.Equal(t, gethCommon.Hash{}, view.GetTransientState(types.SlotAddress{})) 208 require.Equal(t, false, view.AddressInAccessList(gethCommon.Address{})) 209 addrFound, slotFound := view.SlotInAccessList(types.SlotAddress{}) 210 require.Equal(t, false, addrFound) 211 require.Equal(t, false, slotFound) 212 }) 213 } 214 215 func checkAccount(t *testing.T, 216 view *state.BaseView, 217 addr gethCommon.Address, 218 exists bool, 219 balance *big.Int, 220 nonce uint64, 221 code []byte, 222 codeHash gethCommon.Hash, 223 ) { 224 ex, err := view.Exist(addr) 225 require.NoError(t, err) 226 require.Equal(t, exists, ex) 227 228 bal, err := view.GetBalance(addr) 229 require.NoError(t, err) 230 require.Equal(t, balance, bal) 231 232 no, err := view.GetNonce(addr) 233 require.NoError(t, err) 234 require.Equal(t, nonce, no) 235 236 cd, err := view.GetCode(addr) 237 require.NoError(t, err) 238 require.Equal(t, code, cd) 239 240 cs, err := view.GetCodeSize(addr) 241 require.NoError(t, err) 242 require.Equal(t, len(code), cs) 243 244 ch, err := view.GetCodeHash(addr) 245 require.NoError(t, err) 246 require.Equal(t, codeHash, ch) 247 }