github.com/iotexproject/iotex-core@v1.14.1-rc1/action/protocol/execution/evm/evmstatedbadapter_test.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package evm 7 8 import ( 9 "bytes" 10 "context" 11 "math/big" 12 "testing" 13 14 "github.com/ethereum/go-ethereum/common" 15 "github.com/ethereum/go-ethereum/core/types" 16 "github.com/golang/mock/gomock" 17 "github.com/iotexproject/go-pkgs/hash" 18 "github.com/iotexproject/iotex-address/address" 19 "github.com/pkg/errors" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 23 "github.com/iotexproject/iotex-core/action/protocol" 24 "github.com/iotexproject/iotex-core/blockchain/genesis" 25 "github.com/iotexproject/iotex-core/db/batch" 26 "github.com/iotexproject/iotex-core/state" 27 "github.com/iotexproject/iotex-core/test/identityset" 28 "github.com/iotexproject/iotex-core/test/mock/mock_chainmanager" 29 ) 30 31 func initMockStateManager(ctrl *gomock.Controller) (*mock_chainmanager.MockStateManager, error) { 32 sm := mock_chainmanager.NewMockStateManager(ctrl) 33 cb := batch.NewCachedBatch() 34 sm.EXPECT().State(gomock.Any(), gomock.Any()).DoAndReturn( 35 func(account interface{}, opts ...protocol.StateOption) (uint64, error) { 36 cfg, err := protocol.CreateStateConfig(opts...) 37 if err != nil { 38 return 0, err 39 } 40 ns := "state" 41 if cfg.Namespace != "" { 42 ns = cfg.Namespace 43 } 44 val, err := cb.Get(ns, cfg.Key) 45 if err != nil { 46 return 0, state.ErrStateNotExist 47 } 48 return 0, state.Deserialize(account, val) 49 }).AnyTimes() 50 sm.EXPECT().PutState(gomock.Any(), gomock.Any()).DoAndReturn( 51 func(account interface{}, opts ...protocol.StateOption) (uint64, error) { 52 cfg, err := protocol.CreateStateConfig(opts...) 53 if err != nil { 54 return 0, err 55 } 56 ss, err := state.Serialize(account) 57 if err != nil { 58 return 0, err 59 } 60 ns := "state" 61 if cfg.Namespace != "" { 62 ns = cfg.Namespace 63 } 64 cb.Put(ns, cfg.Key, ss, "failed to put state") 65 return 0, nil 66 }).AnyTimes() 67 sm.EXPECT().DelState(gomock.Any()).DoAndReturn( 68 func(opts ...protocol.StateOption) (uint64, error) { 69 cfg, err := protocol.CreateStateConfig(opts...) 70 if err != nil { 71 return 0, err 72 } 73 ns := "state" 74 if cfg.Namespace != "" { 75 ns = cfg.Namespace 76 } 77 cb.Delete(ns, cfg.Key, "failed to delete state") 78 return 0, nil 79 }).AnyTimes() 80 sm.EXPECT().Snapshot().DoAndReturn(cb.Snapshot).AnyTimes() 81 sm.EXPECT().Revert(gomock.Any()).DoAndReturn(cb.RevertSnapshot).AnyTimes() 82 return sm, nil 83 } 84 85 func TestAddBalance(t *testing.T) { 86 require := require.New(t) 87 ctrl := gomock.NewController(t) 88 89 sm, err := initMockStateManager(ctrl) 90 require.NoError(err) 91 addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec") 92 stateDB, err := NewStateDBAdapter( 93 sm, 94 1, 95 hash.ZeroHash256, 96 NotFixTopicCopyBugOption(), 97 FixSnapshotOrderOption(), 98 ) 99 require.NoError(err) 100 addAmount := big.NewInt(40000) 101 stateDB.AddBalance(addr, addAmount) 102 require.Equal(addAmount, stateDB.lastAddBalanceAmount) 103 beneficiary, _ := address.FromBytes(addr[:]) 104 require.Equal(beneficiary.String(), stateDB.lastAddBalanceAddr) 105 amount := stateDB.GetBalance(addr) 106 require.Equal(amount, addAmount) 107 stateDB.AddBalance(addr, addAmount) 108 amount = stateDB.GetBalance(addr) 109 require.Equal(amount, big.NewInt(80000)) 110 stateDB.AddBalance(addr, new(big.Int)) 111 require.Zero(len(stateDB.lastAddBalanceAmount.Bytes())) 112 } 113 114 func TestRefundAPIs(t *testing.T) { 115 require := require.New(t) 116 ctrl := gomock.NewController(t) 117 118 sm, err := initMockStateManager(ctrl) 119 require.NoError(err) 120 stateDB, err := NewStateDBAdapter( 121 sm, 122 1, 123 hash.ZeroHash256, 124 NotFixTopicCopyBugOption(), 125 FixSnapshotOrderOption(), 126 ) 127 require.NoError(err) 128 require.Zero(stateDB.GetRefund()) 129 refund := uint64(1024) 130 stateDB.AddRefund(refund) 131 require.Equal(refund, stateDB.GetRefund()) 132 } 133 134 func TestEmptyAndCode(t *testing.T) { 135 require := require.New(t) 136 ctrl := gomock.NewController(t) 137 138 sm, err := initMockStateManager(ctrl) 139 require.NoError(err) 140 addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec") 141 stateDB, err := NewStateDBAdapter( 142 sm, 143 1, 144 hash.ZeroHash256, 145 NotFixTopicCopyBugOption(), 146 FixSnapshotOrderOption(), 147 ) 148 require.NoError(err) 149 require.True(stateDB.Empty(addr)) 150 stateDB.CreateAccount(addr) 151 require.True(stateDB.Empty(addr)) 152 stateDB.SetCode(addr, []byte("0123456789")) 153 require.True(bytes.Equal(stateDB.GetCode(addr), []byte("0123456789"))) 154 require.False(stateDB.Empty(addr)) 155 } 156 157 var kvs = map[common.Hash]common.Hash{ 158 common.HexToHash("0123456701234567012345670123456701234567012345670123456701234560"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234560"), 159 common.HexToHash("0123456701234567012345670123456701234567012345670123456701234561"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234561"), 160 common.HexToHash("0123456701234567012345670123456701234567012345670123456701234562"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234562"), 161 common.HexToHash("0123456701234567012345670123456701234567012345670123456701234563"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234563"), 162 common.HexToHash("2345670123456701234567012345670123456701234567012345670123456301"): common.HexToHash("2345670123456701234567012345670123456701234567012345670123456301"), 163 common.HexToHash("4567012345670123456701234567012345670123456701234567012345630123"): common.HexToHash("4567012345670123456701234567012345670123456701234567012345630123"), 164 common.HexToHash("6701234567012345670123456701234567012345670123456701234563012345"): common.HexToHash("6701234567012345670123456701234567012345670123456701234563012345"), 165 common.HexToHash("0123456701234567012345670123456701234567012345670123456301234567"): common.HexToHash("0123456701234567012345670123456701234567012345670123456301234567"), 166 common.HexToHash("ab45670123456701234567012345670123456701234567012345630123456701"): common.HexToHash("ab45670123456701234567012345670123456701234567012345630123456701"), 167 common.HexToHash("cd67012345670123456701234567012345670123456701234563012345670123"): common.HexToHash("cd67012345670123456701234567012345670123456701234563012345670123"), 168 common.HexToHash("ef01234567012345670123456701234567012345670123456301234567012345"): common.HexToHash("ef01234567012345670123456701234567012345670123456301234567012345"), 169 } 170 171 func TestForEachStorage(t *testing.T) { 172 require := require.New(t) 173 ctrl := gomock.NewController(t) 174 175 sm, err := initMockStateManager(ctrl) 176 require.NoError(err) 177 addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec") 178 stateDB, err := NewStateDBAdapter( 179 sm, 180 1, 181 hash.ZeroHash256, 182 NotFixTopicCopyBugOption(), 183 FixSnapshotOrderOption(), 184 ) 185 require.NoError(err) 186 stateDB.CreateAccount(addr) 187 for k, v := range kvs { 188 stateDB.SetState(addr, k, v) 189 } 190 require.NoError( 191 stateDB.ForEachStorage(addr, func(k common.Hash, v common.Hash) bool { 192 require.Equal(k, v) 193 delete(kvs, k) 194 return true 195 }), 196 ) 197 require.Equal(0, len(kvs)) 198 } 199 200 func TestReadContractStorage(t *testing.T) { 201 require := require.New(t) 202 ctrl := gomock.NewController(t) 203 204 sm, err := initMockStateManager(ctrl) 205 require.NoError(err) 206 addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec") 207 stateDB, err := NewStateDBAdapter( 208 sm, 209 1, 210 hash.ZeroHash256, 211 AsyncContractTrieOption(), 212 FixSnapshotOrderOption(), 213 ) 214 require.NoError(err) 215 stateDB.CreateAccount(addr) 216 kvs := map[common.Hash]common.Hash{ 217 common.HexToHash("0123456701234567012345670123456701234567012345670123456701234560"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234560"), 218 common.HexToHash("0123456701234567012345670123456701234567012345670123456701234561"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234561"), 219 common.HexToHash("0123456701234567012345670123456701234567012345670123456701234562"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234562"), 220 common.HexToHash("0123456701234567012345670123456701234567012345670123456701234563"): common.HexToHash("0123456701234567012345670123456701234567012345670123456701234563"), 221 common.HexToHash("2345670123456701234567012345670123456701234567012345670123456301"): common.HexToHash("2345670123456701234567012345670123456701234567012345670123456301"), 222 common.HexToHash("4567012345670123456701234567012345670123456701234567012345630123"): common.HexToHash("4567012345670123456701234567012345670123456701234567012345630123"), 223 common.HexToHash("6701234567012345670123456701234567012345670123456701234563012345"): common.HexToHash("6701234567012345670123456701234567012345670123456701234563012345"), 224 common.HexToHash("0123456701234567012345670123456701234567012345670123456301234567"): common.HexToHash("0123456701234567012345670123456701234567012345670123456301234567"), 225 common.HexToHash("ab45670123456701234567012345670123456701234567012345630123456701"): common.HexToHash("ab45670123456701234567012345670123456701234567012345630123456701"), 226 common.HexToHash("cd67012345670123456701234567012345670123456701234563012345670123"): common.HexToHash("cd67012345670123456701234567012345670123456701234563012345670123"), 227 common.HexToHash("ef01234567012345670123456701234567012345670123456301234567012345"): common.HexToHash("ef01234567012345670123456701234567012345670123456301234567012345"), 228 } 229 for k, v := range kvs { 230 stateDB.SetState(addr, k, v) 231 } 232 stateDB.CommitContracts() 233 234 ctx := protocol.WithBlockchainCtx(protocol.WithFeatureCtx(protocol.WithBlockCtx( 235 genesis.WithGenesisContext(context.Background(), genesis.Default), 236 protocol.BlockCtx{BlockHeight: genesis.Default.MidwayBlockHeight})), 237 protocol.BlockchainCtx{}) 238 for k, v := range kvs { 239 b, err := ReadContractStorage(ctx, sm, addr, k[:]) 240 require.NoError(err) 241 require.Equal(v[:], b) 242 } 243 } 244 245 func TestNonce(t *testing.T) { 246 require := require.New(t) 247 ctrl := gomock.NewController(t) 248 249 addr := common.HexToAddress("02ae2a956d21e8d481c3a69e146633470cf625ec") 250 t.Run("legacy nonce account with confirmed nonce", func(t *testing.T) { 251 sm, err := initMockStateManager(ctrl) 252 require.NoError(err) 253 opt := []StateDBAdapterOption{ 254 NotFixTopicCopyBugOption(), 255 FixSnapshotOrderOption(), 256 LegacyNonceAccountOption(), 257 UseConfirmedNonceOption(), 258 } 259 stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...) 260 require.NoError(err) 261 require.Equal(uint64(0), stateDB.GetNonce(addr)) 262 stateDB.SetNonce(addr, 1) 263 require.Equal(uint64(1), stateDB.GetNonce(addr)) 264 }) 265 t.Run("legacy nonce account with pending nonce", func(t *testing.T) { 266 sm, err := initMockStateManager(ctrl) 267 require.NoError(err) 268 opt := []StateDBAdapterOption{ 269 NotFixTopicCopyBugOption(), 270 FixSnapshotOrderOption(), 271 LegacyNonceAccountOption(), 272 } 273 stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...) 274 require.NoError(err) 275 require.Equal(uint64(1), stateDB.GetNonce(addr)) 276 stateDB.SetNonce(addr, 2) 277 require.Equal(uint64(2), stateDB.GetNonce(addr)) 278 }) 279 t.Run("zero nonce account with confirmed nonce", func(t *testing.T) { 280 sm, err := initMockStateManager(ctrl) 281 require.NoError(err) 282 opt := []StateDBAdapterOption{ 283 NotFixTopicCopyBugOption(), 284 FixSnapshotOrderOption(), 285 UseConfirmedNonceOption(), 286 } 287 _, err = NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...) 288 require.Error(err) 289 }) 290 t.Run("zero nonce account with pending nonce", func(t *testing.T) { 291 sm, err := initMockStateManager(ctrl) 292 require.NoError(err) 293 opt := []StateDBAdapterOption{ 294 NotFixTopicCopyBugOption(), 295 FixSnapshotOrderOption(), 296 } 297 stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...) 298 require.NoError(err) 299 require.Equal(uint64(0), stateDB.GetNonce(addr)) 300 stateDB.SetNonce(addr, 1) 301 require.Equal(uint64(1), stateDB.GetNonce(addr)) 302 }) 303 t.Run("legacy fresh nonce account with pending nonce", func(t *testing.T) { 304 sm, err := initMockStateManager(ctrl) 305 require.NoError(err) 306 opt := []StateDBAdapterOption{ 307 NotFixTopicCopyBugOption(), 308 FixSnapshotOrderOption(), 309 ZeroNonceForFreshAccountOption(), 310 } 311 stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...) 312 require.NoError(err) 313 require.Equal(uint64(0), stateDB.GetNonce(addr)) 314 stateDB.SetNonce(addr, 1) 315 require.Equal(uint64(1), stateDB.GetNonce(addr)) 316 }) 317 } 318 319 var tests = []stateDBTest{ 320 { 321 []bal{ 322 {_addr1, big.NewInt(40000)}, 323 }, 324 []code{ 325 {_c1, _bytecode}, 326 }, 327 []evmSet{ 328 {_c1, _k1, _v1}, 329 {_c1, _k2, _v2}, 330 {_c3, _k3, _v4}, 331 }, 332 15000, 333 []sui{ 334 {nil, _c4, _c2, false, false}, 335 {nil, _c2, _c4, false, false}, 336 }, 337 []image{ 338 {common.BytesToHash(_v1[:]), []byte("cat")}, 339 {common.BytesToHash(_v2[:]), []byte("dog")}, 340 }, 341 []access{ 342 {_c1, []common.Hash{_k1, _k2}, []common.Hash{_k3, _k4}, false}, 343 }, 344 []*types.Log{ 345 newTestLog(_c3), newTestLog(_c2), newTestLog(_c1), 346 }, 347 3, 0, 348 "io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", "io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", "", 349 }, 350 { 351 []bal{ 352 {_addr1, big.NewInt(40000)}, 353 }, 354 []code{ 355 {_c2, _bytecode}, 356 }, 357 []evmSet{ 358 {_c1, _k1, _v3}, 359 {_c1, _k2, _v4}, 360 {_c2, _k3, _v3}, 361 {_c2, _k4, _v4}, 362 }, 363 2000, 364 []sui{ 365 {nil, _c4, _c1, true, true}, 366 {big.NewInt(1000), _c2, _c3, true, true}, 367 }, 368 []image{ 369 {common.BytesToHash(_v3[:]), []byte("hen")}, 370 }, 371 []access{ 372 {_c1, []common.Hash{_k3, _k4}, nil, true}, 373 {_c2, []common.Hash{_k1, _k3}, []common.Hash{_k2, _k4}, false}, 374 }, 375 []*types.Log{ 376 newTestLog(_c4), 377 }, 378 4, 1, 379 "io1zg0qrlpyvc68pnmz4c4f2mfc6jqu8f57jjy09q", 380 "io1j4kjr6x5s8p6dyqlcfrxxdrsea32u2hpvpl5us", 381 "io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe", 382 }, 383 { 384 nil, 385 nil, 386 []evmSet{ 387 {_c2, _k3, _v1}, 388 {_c2, _k4, _v2}, 389 }, 390 15000, 391 []sui{ 392 {big.NewInt(0), _c1, _addr1, true, true}, 393 }, 394 []image{ 395 {common.BytesToHash(_v4[:]), []byte("fox")}, 396 }, 397 []access{ 398 {_c2, []common.Hash{_k2, _k4}, nil, true}, 399 }, 400 []*types.Log{ 401 newTestLog(_c1), newTestLog(_c2), 402 }, 403 6, 2, 404 "io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe", 405 "io1q2hz49tdy85dfqwr560pge3ngux0vf0vmhanad", 406 "io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", 407 }, 408 } 409 410 func TestSnapshotRevertAndCommit(t *testing.T) { 411 testSnapshotAndRevert := func(t *testing.T, async, fixSnapshot, revertLog bool) { 412 require := require.New(t) 413 ctrl := gomock.NewController(t) 414 415 sm, err := initMockStateManager(ctrl) 416 require.NoError(err) 417 opt := []StateDBAdapterOption{ 418 NotFixTopicCopyBugOption(), 419 SuicideTxLogMismatchPanicOption(), 420 } 421 if async { 422 opt = append(opt, AsyncContractTrieOption()) 423 } 424 if fixSnapshot { 425 opt = append(opt, FixSnapshotOrderOption()) 426 } 427 if revertLog { 428 opt = append(opt, RevertLogOption()) 429 } 430 stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opt...) 431 require.NoError(err) 432 433 for i, test := range tests { 434 // add balance 435 for _, e := range test.balance { 436 stateDB.AddBalance(e.addr, e.v) 437 } 438 // set code 439 for _, e := range test.codes { 440 stateDB.SetCode(e.addr, e.v) 441 v := stateDB.GetCode(e.addr) 442 require.Equal(e.v, v) 443 } 444 // set states 445 for _, e := range test.states { 446 stateDB.SetState(e.addr, e.k, e.v) 447 } 448 // set refund 449 stateDB.refund = test.refund 450 // set suicide 451 for _, e := range test.suicide { 452 if e.amount != nil { 453 stateDB.AddBalance(e.addr, e.amount) 454 } 455 stateDB.AddBalance(e.beneficiary, stateDB.GetBalance(e.addr)) // simulate transfer to beneficiary inside Suicide() 456 require.Equal(e.suicide, stateDB.Suicide(e.addr)) 457 require.Equal(e.exist, stateDB.Exist(e.addr)) 458 require.Zero(new(big.Int).Cmp(stateDB.GetBalance(e.addr))) 459 } 460 // set preimage 461 for _, e := range test.preimage { 462 stateDB.AddPreimage(e.hash, e.v) 463 } 464 // set access list 465 for _, e := range test.accessList { 466 require.Equal(e.exist, stateDB.AddressInAccessList(e.addr)) 467 for _, slot := range e.slots { 468 aOk, sOk := stateDB.SlotInAccessList(e.addr, slot) 469 require.Equal(e.exist, aOk) 470 require.False(sOk) 471 stateDB.AddSlotToAccessList(e.addr, slot) 472 e.exist = true 473 aOk, sOk = stateDB.SlotInAccessList(e.addr, slot) 474 require.True(aOk) 475 require.True(sOk) 476 } 477 for _, slot := range e.nx { 478 aOk, sOk := stateDB.SlotInAccessList(e.addr, slot) 479 require.True(aOk) 480 require.False(sOk) 481 } 482 } 483 // set logs and txLogs 484 for _, l := range test.logs { 485 stateDB.AddLog(l) 486 } 487 488 require.Equal(test.logSize, len(stateDB.logs)) 489 require.Equal(test.txLogSize, len(stateDB.transactionLogs)) 490 require.Equal(test.logAddr, stateDB.logs[test.logSize-1].Address) 491 if test.txLogSize > 0 { 492 require.Equal(test.txSender, stateDB.transactionLogs[test.txLogSize-1].Sender) 493 require.Equal(test.txReceiver, stateDB.transactionLogs[test.txLogSize-1].Recipient) 494 } 495 require.Equal(i, stateDB.Snapshot()) 496 } 497 498 reverts := []stateDBTest{ 499 { 500 []bal{ 501 {_addr1, big.NewInt(0)}, 502 }, 503 []code{}, 504 []evmSet{ 505 {_c1, _k1, _v3}, 506 {_c1, _k2, _v4}, 507 {_c2, _k3, _v1}, 508 {_c2, _k4, _v2}, 509 }, 510 tests[2].refund, 511 []sui{ 512 {nil, common.Address{}, _c1, true, true}, 513 {nil, common.Address{}, _c3, true, true}, 514 {nil, common.Address{}, _c2, false, true}, 515 {nil, common.Address{}, _c4, false, false}, 516 {nil, common.Address{}, _addr1, true, true}, 517 }, 518 []image{ 519 {common.BytesToHash(_v1[:]), []byte("cat")}, 520 {common.BytesToHash(_v2[:]), []byte("dog")}, 521 {common.BytesToHash(_v3[:]), []byte("hen")}, 522 {common.BytesToHash(_v4[:]), []byte("fox")}, 523 }, 524 []access{ 525 {_c1, []common.Hash{_k1, _k2, _k3, _k4}, nil, true}, 526 {_c2, []common.Hash{_k1, _k2, _k3, _k4}, nil, true}, 527 }, 528 nil, 529 6, 2, 530 "io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe", 531 "io1q2hz49tdy85dfqwr560pge3ngux0vf0vmhanad", 532 "io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", 533 }, 534 { 535 []bal{ 536 {_addr1, big.NewInt(80000)}, 537 }, 538 []code{}, 539 tests[1].states, 540 tests[1].refund, 541 []sui{ 542 {nil, common.Address{}, _c1, true, true}, 543 {nil, common.Address{}, _c3, true, true}, 544 {nil, common.Address{}, _c2, false, true}, 545 {nil, common.Address{}, _c4, false, false}, 546 {nil, common.Address{}, _addr1, false, true}, 547 }, 548 []image{ 549 {common.BytesToHash(_v1[:]), []byte("cat")}, 550 {common.BytesToHash(_v2[:]), []byte("dog")}, 551 {common.BytesToHash(_v3[:]), []byte("hen")}, 552 {common.BytesToHash(_v4[:]), []byte(nil)}, 553 }, 554 []access{ 555 {_c1, []common.Hash{_k1, _k2, _k3, _k4}, nil, true}, 556 {_c2, []common.Hash{_k1, _k3}, []common.Hash{_k2, _k4}, true}, 557 }, 558 nil, 559 4, 1, 560 "io1zg0qrlpyvc68pnmz4c4f2mfc6jqu8f57jjy09q", 561 "io1j4kjr6x5s8p6dyqlcfrxxdrsea32u2hpvpl5us", 562 "io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe", 563 }, 564 { 565 []bal{ 566 {_addr1, big.NewInt(40000)}, 567 }, 568 []code{}, 569 []evmSet{ 570 {_c1, _k1, _v1}, 571 {_c1, _k2, _v2}, 572 {_c3, _k3, _v4}, 573 }, 574 tests[0].refund, 575 []sui{ 576 {nil, common.Address{}, _c1, false, true}, 577 {nil, common.Address{}, _c3, false, true}, 578 {nil, common.Address{}, _c2, false, false}, 579 {nil, common.Address{}, _c4, false, false}, 580 {nil, common.Address{}, _addr1, false, true}, 581 }, 582 []image{ 583 {common.BytesToHash(_v1[:]), []byte("cat")}, 584 {common.BytesToHash(_v2[:]), []byte("dog")}, 585 {common.BytesToHash(_v3[:]), []byte(nil)}, 586 {common.BytesToHash(_v4[:]), []byte(nil)}, 587 }, 588 []access{ 589 {_c1, []common.Hash{_k1, _k2}, []common.Hash{_k3, _k4}, true}, 590 {_c2, nil, []common.Hash{_k1, _k2, _k3, _k4}, false}, 591 }, 592 nil, 593 3, 0, 594 "io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", 595 "io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", 596 "", 597 }, 598 } 599 600 // test revert 601 for i, test := range reverts { 602 stateDB.RevertToSnapshot(len(reverts) - 1 - i) 603 // test balance 604 for _, e := range test.balance { 605 amount := stateDB.GetBalance(e.addr) 606 require.Equal(e.v, amount) 607 } 608 if async && !fixSnapshot { 609 // test preimage 610 for _, e := range reverts[0].preimage { 611 v := stateDB.preimages[e.hash] 612 require.Equal(e.v, []byte(v)) 613 } 614 } else { 615 // test states 616 for _, e := range test.states { 617 require.Equal(e.v, stateDB.GetState(e.addr, e.k)) 618 } 619 // test refund 620 require.Equal(test.refund, stateDB.refund) 621 // test preimage 622 for _, e := range test.preimage { 623 v := stateDB.preimages[e.hash] 624 require.Equal(e.v, []byte(v)) 625 } 626 // test access list 627 for _, e := range test.accessList { 628 require.Equal(e.exist, stateDB.AddressInAccessList(e.addr)) 629 for _, slot := range e.slots { 630 aOk, sOk := stateDB.SlotInAccessList(e.addr, slot) 631 require.Equal(e.exist, aOk) 632 require.True(sOk) 633 } 634 for _, slot := range e.nx { 635 aOk, sOk := stateDB.SlotInAccessList(e.addr, slot) 636 require.Equal(e.exist, aOk) 637 require.False(sOk) 638 } 639 } 640 } 641 // test suicide/exist 642 for _, e := range test.suicide { 643 require.Equal(e.suicide, stateDB.HasSuicided(e.addr)) 644 require.Equal(e.exist, stateDB.Exist(e.addr)) 645 } 646 // test logs 647 if revertLog { 648 require.Equal(test.logSize, len(stateDB.logs)) 649 require.Equal(test.txLogSize, len(stateDB.transactionLogs)) 650 require.Equal(test.logAddr, stateDB.logs[test.logSize-1].Address) 651 if test.txLogSize > 0 { 652 require.Equal(test.txSender, stateDB.transactionLogs[test.txLogSize-1].Sender) 653 require.Equal(test.txReceiver, stateDB.transactionLogs[test.txLogSize-1].Recipient) 654 } 655 } else { 656 require.Equal(6, len(stateDB.logs)) 657 require.Equal(2, len(stateDB.transactionLogs)) 658 require.Equal("io1x3cv7c4w922k6wx5s8p6d8sjrcqlcfrxhkn5xe", stateDB.logs[5].Address) 659 require.Equal("io1q2hz49tdy85dfqwr560pge3ngux0vf0vmhanad", stateDB.transactionLogs[1].Sender) 660 require.Equal("io1q87zge3ngux0v2hz49tdy85dfqwr560pj9mk7r", stateDB.transactionLogs[1].Recipient) 661 } 662 } 663 664 // snapshot after revert 665 require.Equal(1, stateDB.Snapshot()) 666 if fixSnapshot { 667 require.Equal(1, len(stateDB.contractSnapshot)) 668 require.Equal(1, len(stateDB.suicideSnapshot)) 669 require.Equal(1, len(stateDB.preimageSnapshot)) 670 require.Equal(1, len(stateDB.accessListSnapshot)) 671 require.Equal(1, len(stateDB.refundSnapshot)) 672 } else { 673 require.Equal(3, len(stateDB.contractSnapshot)) 674 require.Equal(3, len(stateDB.suicideSnapshot)) 675 require.Equal(3, len(stateDB.preimageSnapshot)) 676 // refund fix and accessList are introduced after fixSnapshot 677 // so their snapshot are always properly cleared 678 require.Zero(len(stateDB.accessListSnapshot)) 679 require.Zero(len(stateDB.refundSnapshot)) 680 } 681 // commit snapshot 0's state 682 require.NoError(stateDB.CommitContracts()) 683 stateDB.clear() 684 //[TODO] need e2etest to verify state factory commit/re-open (whether result from state/balance/suicide/exist is same) 685 } 686 687 t.Run("contract snapshot/revert/commit", func(t *testing.T) { 688 testSnapshotAndRevert(t, false, true, false) 689 }) 690 t.Run("contract snapshot/revert/commit w/o bug fix and revert log", func(t *testing.T) { 691 testSnapshotAndRevert(t, false, false, true) 692 }) 693 t.Run("contract snapshot/revert/commit with async trie and revert log", func(t *testing.T) { 694 testSnapshotAndRevert(t, true, true, true) 695 }) 696 t.Run("contract snapshot/revert/commit with async trie and w/o bug fix", func(t *testing.T) { 697 testSnapshotAndRevert(t, true, false, false) 698 }) 699 } 700 701 func TestClearSnapshots(t *testing.T) { 702 testClearSnapshots := func(t *testing.T, async, fixSnapshotOrder bool) { 703 require := require.New(t) 704 ctrl := gomock.NewController(t) 705 706 sm, err := initMockStateManager(ctrl) 707 require.NoError(err) 708 opts := []StateDBAdapterOption{ 709 NotFixTopicCopyBugOption(), 710 RevertLogOption(), 711 } 712 if async { 713 opts = append(opts, AsyncContractTrieOption()) 714 } 715 if fixSnapshotOrder { 716 opts = append(opts, FixSnapshotOrderOption()) 717 } 718 stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opts...) 719 require.NoError(err) 720 721 for i, test := range tests { 722 // add balance 723 for _, e := range test.balance { 724 stateDB.AddBalance(e.addr, e.v) 725 } 726 // set code 727 for _, e := range test.codes { 728 stateDB.SetCode(e.addr, e.v) 729 v := stateDB.GetCode(e.addr) 730 require.Equal(e.v, v) 731 } 732 // set states 733 for _, e := range test.states { 734 stateDB.SetState(e.addr, e.k, e.v) 735 } 736 // set suicide 737 for _, e := range test.suicide { 738 require.Equal(e.suicide, stateDB.Suicide(e.addr)) 739 require.Equal(e.exist, stateDB.Exist(e.addr)) 740 } 741 // set preimage 742 for _, e := range test.preimage { 743 stateDB.AddPreimage(e.hash, e.v) 744 } 745 require.Equal(i, stateDB.Snapshot()) 746 } 747 748 // revert to snapshot 1 749 stateDB.RevertToSnapshot(1) 750 require.Equal(1, len(stateDB.logsSnapshot)) 751 752 if stateDB.fixSnapshotOrder { 753 // snapshot 1, 2 cleared, only 0 left in map 754 require.Equal(1, len(stateDB.suicideSnapshot)) 755 require.Equal(1, len(stateDB.contractSnapshot)) 756 require.Equal(1, len(stateDB.preimageSnapshot)) 757 require.Equal(2, stateDB.Snapshot()) 758 // now there are 2 snapshots: 0 and the newly added one 759 require.Equal(2, len(stateDB.suicideSnapshot)) 760 require.Equal(2, len(stateDB.contractSnapshot)) 761 require.Equal(2, len(stateDB.preimageSnapshot)) 762 require.Equal(2, len(stateDB.logsSnapshot)) 763 } else { 764 // snapshot not cleared 765 require.Equal(3, len(stateDB.suicideSnapshot)) 766 require.Equal(3, len(stateDB.contractSnapshot)) 767 require.Equal(3, len(stateDB.preimageSnapshot)) 768 require.Equal(2, stateDB.Snapshot()) 769 // still 3 old snapshots 770 require.Equal(3, len(stateDB.suicideSnapshot)) 771 require.Equal(3, len(stateDB.contractSnapshot)) 772 require.Equal(3, len(stateDB.preimageSnapshot)) 773 // log snapshot added after fixSnapshotOrder, so it is cleared and 1 remains 774 require.Equal(1, len(stateDB.logsSnapshot)) 775 } 776 777 } 778 t.Run("contract w/o clear snapshots", func(t *testing.T) { 779 testClearSnapshots(t, false, false) 780 }) 781 t.Run("contract with clear snapshots", func(t *testing.T) { 782 testClearSnapshots(t, false, true) 783 }) 784 } 785 786 func TestGetCommittedState(t *testing.T) { 787 t.Run("committed state with in mem DB", func(t *testing.T) { 788 require := require.New(t) 789 ctrl := gomock.NewController(t) 790 791 sm, err := initMockStateManager(ctrl) 792 require.NoError(err) 793 stateDB, err := NewStateDBAdapter( 794 sm, 795 1, 796 hash.ZeroHash256, 797 NotFixTopicCopyBugOption(), 798 FixSnapshotOrderOption(), 799 ) 800 require.NoError(err) 801 802 stateDB.SetState(_c1, _k1, _v1) 803 // _k2 does not exist 804 require.Equal(common.Hash{}, stateDB.GetCommittedState(_c1, common.BytesToHash(_k2[:]))) 805 require.Equal(_v1, stateDB.GetState(_c1, _k1)) 806 require.Equal(common.Hash{}, stateDB.GetCommittedState(_c1, common.BytesToHash(_k2[:]))) 807 808 // commit (_k1, _v1) 809 require.NoError(stateDB.CommitContracts()) 810 stateDB.clear() 811 812 require.Equal(_v1, stateDB.GetState(_c1, _k1)) 813 require.Equal(common.BytesToHash(_v1[:]), stateDB.GetCommittedState(_c1, common.BytesToHash(_k1[:]))) 814 stateDB.SetState(_c1, _k1, _v2) 815 require.Equal(common.BytesToHash(_v1[:]), stateDB.GetCommittedState(_c1, common.BytesToHash(_k1[:]))) 816 require.Equal(_v2, stateDB.GetState(_c1, _k1)) 817 require.Equal(common.BytesToHash(_v1[:]), stateDB.GetCommittedState(_c1, common.BytesToHash(_k1[:]))) 818 }) 819 } 820 821 func TestGetBalanceOnError(t *testing.T) { 822 ctrl := gomock.NewController(t) 823 824 sm := mock_chainmanager.NewMockStateManager(ctrl) 825 errs := []error{ 826 state.ErrStateNotExist, 827 errors.New("other error"), 828 } 829 for _, err := range errs { 830 sm.EXPECT().State(gomock.Any(), gomock.Any()).Return(uint64(0), err).Times(1) 831 addr := common.HexToAddress("test address") 832 stateDB, err := NewStateDBAdapter( 833 sm, 834 1, 835 hash.ZeroHash256, 836 NotFixTopicCopyBugOption(), 837 FixSnapshotOrderOption(), 838 ) 839 assert.NoError(t, err) 840 amount := stateDB.GetBalance(addr) 841 assert.Equal(t, big.NewInt(0), amount) 842 } 843 } 844 845 func TestPreimage(t *testing.T) { 846 require := require.New(t) 847 ctrl := gomock.NewController(t) 848 849 sm, err := initMockStateManager(ctrl) 850 require.NoError(err) 851 stateDB, err := NewStateDBAdapter( 852 sm, 853 1, 854 hash.ZeroHash256, 855 NotFixTopicCopyBugOption(), 856 FixSnapshotOrderOption(), 857 ) 858 require.NoError(err) 859 860 stateDB.AddPreimage(common.BytesToHash(_v1[:]), []byte("cat")) 861 stateDB.AddPreimage(common.BytesToHash(_v2[:]), []byte("dog")) 862 stateDB.AddPreimage(common.BytesToHash(_v3[:]), []byte("hen")) 863 // this won't overwrite preimage of _v1 864 stateDB.AddPreimage(common.BytesToHash(_v1[:]), []byte("fox")) 865 require.NoError(stateDB.CommitContracts()) 866 stateDB.clear() 867 var k protocol.SerializableBytes 868 _, err = stateDB.sm.State(&k, protocol.NamespaceOption(PreimageKVNameSpace), protocol.KeyOption(_v1[:])) 869 require.NoError(err) 870 require.Equal([]byte("cat"), []byte(k)) 871 _, err = stateDB.sm.State(&k, protocol.NamespaceOption(PreimageKVNameSpace), protocol.KeyOption(_v2[:])) 872 require.NoError(err) 873 require.Equal([]byte("dog"), []byte(k)) 874 _, err = stateDB.sm.State(&k, protocol.NamespaceOption(PreimageKVNameSpace), protocol.KeyOption(_v3[:])) 875 require.NoError(err) 876 require.Equal([]byte("hen"), []byte(k)) 877 } 878 879 func TestSortMap(t *testing.T) { 880 require := require.New(t) 881 uniqueSlice := func(slice []string) bool { 882 for _, v := range slice[1:] { 883 if v != slice[0] { 884 return false 885 } 886 } 887 return true 888 } 889 890 testFunc := func(t *testing.T, sm *mock_chainmanager.MockStateManager, opts ...StateDBAdapterOption) bool { 891 opts = append(opts, 892 NotFixTopicCopyBugOption(), 893 FixSnapshotOrderOption(), 894 ) 895 stateDB, err := NewStateDBAdapter(sm, 1, hash.ZeroHash256, opts...) 896 require.NoError(err) 897 size := 10 898 899 for i := 0; i < size; i++ { 900 addr := common.HexToAddress(identityset.Address(i).Hex()) 901 stateDB.SetCode(addr, []byte("0123456789")) 902 stateDB.SetState(addr, _k1, _k2) 903 } 904 sn := stateDB.Snapshot() 905 caches := []string{} 906 for i := 0; i < size; i++ { 907 stateDB.RevertToSnapshot(sn) 908 s := "" 909 if stateDB.disableSortCachedContracts { 910 for _, c := range stateDB.cachedContract { 911 s += string(c.SelfState().Root[:]) 912 } 913 } else { 914 for _, addr := range stateDB.cachedContractAddrs() { 915 c := stateDB.cachedContract[addr] 916 s += string(c.SelfState().Root[:]) 917 } 918 } 919 920 caches = append(caches, s) 921 } 922 return uniqueSlice(caches) 923 } 924 925 ctrl := gomock.NewController(t) 926 sm, err := initMockStateManager(ctrl) 927 require.NoError(err) 928 t.Run("before fix sort map", func(t *testing.T) { 929 require.False(testFunc(t, sm, DisableSortCachedContractsOption())) 930 }) 931 932 t.Run("after fix sort map", func(t *testing.T) { 933 require.True(testFunc(t, sm)) 934 }) 935 }