package mps import ( "math/big" "sync" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/privatecache" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" ) //TestDefaultPSRCopy tests that copying a the PSR object indeed makes the original and // the copy and their states independent of each other. func TestDefaultPSRCopy(t *testing.T) { testdb := rawdb.NewMemoryDatabase() testCache := state.NewDatabase(testdb) privateCacheProvider := privatecache.NewPrivateCacheProvider(testdb, nil, testCache, false) psr, _ := NewDefaultPrivateStateRepository(testdb, testCache, privateCacheProvider, common.Hash{}) testState, _ := psr.DefaultState() for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) testState.AddBalance(addr, big.NewInt(int64(i))) } testState.Finalise(false) psrCopy := psr.Copy().(*DefaultPrivateStateRepository) testStateCopy, _ := psrCopy.DefaultState() // modify all in memory for i := byte(0); i < 255; i++ { testState.AddBalance(common.BytesToAddress([]byte{i}), big.NewInt(2*int64(i))) testStateCopy.AddBalance(common.BytesToAddress([]byte{i}), big.NewInt(3*int64(i))) } // Finalise the changes on all concurrently finalise := func(wg *sync.WaitGroup, db *state.StateDB) { defer wg.Done() db.Finalise(true) } var wg sync.WaitGroup wg.Add(2) go finalise(&wg, testState) go finalise(&wg, testStateCopy) wg.Wait() assert.Equal(t, psr.db, psrCopy.db) assert.Equal(t, psr.stateCache, psrCopy.stateCache) // Verify that the all states have been updated independently for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) testObj := testState.GetOrNewStateObject(addr) testCopyObj := testStateCopy.GetOrNewStateObject(addr) if want := big.NewInt(3 * int64(i)); testObj.Balance().Cmp(want) != 0 { t.Errorf("empty obj %d: balance mismatch: have %v, want %v", i, testObj.Balance(), want) } if want := big.NewInt(4 * int64(i)); testCopyObj.Balance().Cmp(want) != 0 { t.Errorf("empty copy obj %d: balance mismatch: have %v, want %v", i, testCopyObj.Balance(), want) } } } //TestDefaultPSRReset tests that state objects are cleared from statedb after reset call //Any updated stateObjects not committed before reset will be cleared func TestDefaultPSRReset(t *testing.T) { testdb := rawdb.NewMemoryDatabase() testCache := state.NewDatabase(testdb) privateCacheProvider := privatecache.NewPrivateCacheProvider(testdb, nil, testCache, false) psr, _ := NewDefaultPrivateStateRepository(testdb, testCache, privateCacheProvider, common.Hash{}) testState, _ := psr.DefaultState() for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) testState.AddBalance(addr, big.NewInt(int64(i))) } testState.Finalise(false) for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) assert.True(t, testState.Exist(addr)) } psr.Reset() for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) assert.False(t, testState.Exist(addr)) } } func TestOnlyPrivateStateAccessible(t *testing.T) { testdb := rawdb.NewMemoryDatabase() testCache := state.NewDatabase(testdb) privateCacheProvider := privatecache.NewPrivateCacheProvider(testdb, nil, testCache, false) psr, _ := NewDefaultPrivateStateRepository(testdb, testCache, privateCacheProvider, common.Hash{}) privateState, _ := psr.DefaultState() assert.NotEqual(t, privateState, nil) privateState, _ = psr.StatePSI(types.DefaultPrivateStateIdentifier) assert.NotEqual(t, privateState, nil) _, err := psr.StatePSI(types.PrivateStateIdentifier("test")) assert.Error(t, err, "only the 'private' psi is supported by the default private state manager") } //TestDefaultPSRCommitAndWrite tests that statedb is updated but not written to db func TestDefaultPSRCommit(t *testing.T) { testdb := rawdb.NewMemoryDatabase() testCache := state.NewDatabase(testdb) privateCacheProvider := privatecache.NewPrivateCacheProvider(testdb, nil, testCache, false) psr, _ := NewDefaultPrivateStateRepository(testdb, testCache, privateCacheProvider, common.Hash{}) header := &types.Header{Number: big.NewInt(int64(1)), Root: common.Hash{123}} block := types.NewBlockWithHeader(header) testState, _ := psr.DefaultState() testRoot := testState.IntermediateRoot(false) assert.Equal(t, testRoot, common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) //make updates to states for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) testState.AddBalance(addr, big.NewInt(int64(i))) } assert.Equal(t, rawdb.GetPrivateStateRoot(testdb, block.Root()), common.Hash{}) psr.Commit(false, block) //private root updated but not committed assert.NotEqual(t, psr.root, common.Hash{}) assert.Equal(t, rawdb.GetPrivateStateRoot(testdb, block.Root()), common.Hash{}) testRoot = testState.IntermediateRoot(false) assert.NotEqual(t, testRoot, common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) } //TestDefaultPSRCommitAndWrite tests that statedb is updated and written to db func TestDefaultPSRCommitAndWrite(t *testing.T) { testdb := rawdb.NewMemoryDatabase() testCache := state.NewDatabase(testdb) privateCacheProvider := privatecache.NewPrivateCacheProvider(testdb, nil, testCache, false) psr, _ := NewDefaultPrivateStateRepository(testdb, testCache, privateCacheProvider, common.Hash{}) header := &types.Header{Number: big.NewInt(int64(1)), Root: common.Hash{123}} block := types.NewBlockWithHeader(header) testState, _ := psr.DefaultState() testRoot := testState.IntermediateRoot(false) assert.Equal(t, testRoot, common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) //make updates to states for i := byte(0); i < 255; i++ { addr := common.BytesToAddress([]byte{i}) testState.AddBalance(addr, big.NewInt(int64(i))) } assert.Equal(t, rawdb.GetPrivateStateRoot(testdb, block.Root()), common.Hash{}) psr.CommitAndWrite(false, block) //private root gets committed to db, but isn't updated on psr (only needed for commit) assert.Equal(t, psr.root, common.Hash{}) assert.NotEqual(t, rawdb.GetPrivateStateRoot(testdb, block.Root()), common.Hash{}) testRoot = testState.IntermediateRoot(false) assert.NotEqual(t, testRoot, common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")) }