github.com/koko1123/flow-go-1@v0.29.6/engine/execution/state/state_test.go (about)

     1  package state_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/dgraph-io/badger/v3"
     8  	"github.com/golang/mock/gomock"
     9  	"github.com/rs/zerolog"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	ledger2 "github.com/koko1123/flow-go-1/ledger"
    14  	"github.com/koko1123/flow-go-1/ledger/common/pathfinder"
    15  
    16  	"github.com/koko1123/flow-go-1/engine/execution/state"
    17  	ledger "github.com/koko1123/flow-go-1/ledger/complete"
    18  	"github.com/koko1123/flow-go-1/ledger/complete/wal/fixtures"
    19  	"github.com/koko1123/flow-go-1/model/flow"
    20  	"github.com/koko1123/flow-go-1/module/metrics"
    21  	"github.com/koko1123/flow-go-1/module/trace"
    22  	storage "github.com/koko1123/flow-go-1/storage/mock"
    23  	"github.com/koko1123/flow-go-1/storage/mocks"
    24  	"github.com/koko1123/flow-go-1/utils/unittest"
    25  )
    26  
    27  func prepareTest(f func(t *testing.T, es state.ExecutionState, l *ledger.Ledger)) func(*testing.T) {
    28  	return func(t *testing.T) {
    29  		unittest.RunWithBadgerDB(t, func(badgerDB *badger.DB) {
    30  			metricsCollector := &metrics.NoopCollector{}
    31  			diskWal := &fixtures.NoopWAL{}
    32  			ls, err := ledger.NewLedger(diskWal, 100, metricsCollector, zerolog.Nop(), ledger.DefaultPathFinderVersion)
    33  			require.NoError(t, err)
    34  			compactor := fixtures.NewNoopCompactor(ls)
    35  			<-compactor.Ready()
    36  			defer func() {
    37  				<-ls.Done()
    38  				<-compactor.Done()
    39  			}()
    40  
    41  			ctrl := gomock.NewController(t)
    42  
    43  			stateCommitments := mocks.NewMockCommits(ctrl)
    44  			blocks := mocks.NewMockBlocks(ctrl)
    45  			headers := mocks.NewMockHeaders(ctrl)
    46  			collections := mocks.NewMockCollections(ctrl)
    47  			events := mocks.NewMockEvents(ctrl)
    48  			serviceEvents := mocks.NewMockServiceEvents(ctrl)
    49  			txResults := mocks.NewMockTransactionResults(ctrl)
    50  
    51  			stateCommitment := ls.InitialState()
    52  
    53  			stateCommitments.EXPECT().ByBlockID(gomock.Any()).Return(flow.StateCommitment(stateCommitment), nil)
    54  
    55  			chunkDataPacks := new(storage.ChunkDataPacks)
    56  
    57  			results := new(storage.ExecutionResults)
    58  			myReceipts := new(storage.MyExecutionReceipts)
    59  
    60  			es := state.NewExecutionState(
    61  				ls, stateCommitments, blocks, headers, collections, chunkDataPacks, results, myReceipts, events, serviceEvents, txResults, badgerDB, trace.NewNoopTracer(),
    62  			)
    63  
    64  			f(t, es, ls)
    65  		})
    66  	}
    67  }
    68  
    69  func TestExecutionStateWithTrieStorage(t *testing.T) {
    70  	registerID1 := "fruit"
    71  
    72  	registerID2 := "vegetable"
    73  
    74  	t.Run("commit write and read new state", prepareTest(func(t *testing.T, es state.ExecutionState, l *ledger.Ledger) {
    75  		// TODO: use real block ID
    76  		sc1, err := es.StateCommitmentByBlockID(context.Background(), flow.Identifier{})
    77  		assert.NoError(t, err)
    78  
    79  		view1 := es.NewView(sc1)
    80  
    81  		err = view1.Set(registerID1, "", flow.RegisterValue("apple"))
    82  		assert.NoError(t, err)
    83  		err = view1.Set(registerID2, "", flow.RegisterValue("carrot"))
    84  		assert.NoError(t, err)
    85  
    86  		sc2, update, err := state.CommitDelta(l, view1.Delta(), sc1)
    87  		assert.NoError(t, err)
    88  
    89  		assert.Equal(t, sc1[:], update.RootHash[:])
    90  		assert.Len(t, update.Paths, 2)
    91  		assert.Len(t, update.Payloads, 2)
    92  
    93  		key1 := ledger2.NewKey([]ledger2.KeyPart{ledger2.NewKeyPart(0, []byte(registerID1)), ledger2.NewKeyPart(2, []byte(""))})
    94  		path1, err := pathfinder.KeyToPath(key1, ledger.DefaultPathFinderVersion)
    95  		assert.NoError(t, err)
    96  
    97  		key2 := ledger2.NewKey([]ledger2.KeyPart{ledger2.NewKeyPart(0, []byte(registerID2)), ledger2.NewKeyPart(2, []byte(""))})
    98  		path2, err := pathfinder.KeyToPath(key2, ledger.DefaultPathFinderVersion)
    99  		assert.NoError(t, err)
   100  
   101  		assert.Equal(t, path1, update.Paths[0])
   102  		assert.Equal(t, path2, update.Paths[1])
   103  
   104  		k1, err := update.Payloads[0].Key()
   105  		require.NoError(t, err)
   106  
   107  		k2, err := update.Payloads[1].Key()
   108  		require.NoError(t, err)
   109  
   110  		assert.Equal(t, key1, k1)
   111  		assert.Equal(t, key2, k2)
   112  
   113  		assert.Equal(t, []byte("apple"), []byte(update.Payloads[0].Value()))
   114  		assert.Equal(t, []byte("carrot"), []byte(update.Payloads[1].Value()))
   115  
   116  		view2 := es.NewView(sc2)
   117  
   118  		b1, err := view2.Get(registerID1, "")
   119  		assert.NoError(t, err)
   120  		b2, err := view2.Get(registerID2, "")
   121  		assert.NoError(t, err)
   122  
   123  		assert.Equal(t, flow.RegisterValue("apple"), b1)
   124  		assert.Equal(t, flow.RegisterValue("carrot"), b2)
   125  	}))
   126  
   127  	t.Run("commit write and read previous state", prepareTest(func(t *testing.T, es state.ExecutionState, l *ledger.Ledger) {
   128  		// TODO: use real block ID
   129  		sc1, err := es.StateCommitmentByBlockID(context.Background(), flow.Identifier{})
   130  		assert.NoError(t, err)
   131  
   132  		view1 := es.NewView(sc1)
   133  
   134  		err = view1.Set(registerID1, "", []byte("apple"))
   135  		assert.NoError(t, err)
   136  		sc2, _, err := state.CommitDelta(l, view1.Delta(), sc1)
   137  		assert.NoError(t, err)
   138  
   139  		// update value and get resulting state commitment
   140  		view2 := es.NewView(sc2)
   141  		err = view2.Set(registerID1, "", []byte("orange"))
   142  		assert.NoError(t, err)
   143  
   144  		sc3, _, err := state.CommitDelta(l, view2.Delta(), sc2)
   145  		assert.NoError(t, err)
   146  
   147  		// create a view for previous state version
   148  		view3 := es.NewView(sc2)
   149  
   150  		// create a view for new state version
   151  		view4 := es.NewView(sc3)
   152  
   153  		// fetch the value at both versions
   154  		b1, err := view3.Get(registerID1, "")
   155  		assert.NoError(t, err)
   156  
   157  		b2, err := view4.Get(registerID1, "")
   158  		assert.NoError(t, err)
   159  
   160  		assert.Equal(t, flow.RegisterValue("apple"), b1)
   161  		assert.Equal(t, flow.RegisterValue("orange"), b2)
   162  	}))
   163  
   164  	t.Run("commit delta and read new state", prepareTest(func(t *testing.T, es state.ExecutionState, l *ledger.Ledger) {
   165  		// TODO: use real block ID
   166  		sc1, err := es.StateCommitmentByBlockID(context.Background(), flow.Identifier{})
   167  		assert.NoError(t, err)
   168  
   169  		// set initial value
   170  		view1 := es.NewView(sc1)
   171  		err = view1.Set(registerID1, "", []byte("apple"))
   172  		assert.NoError(t, err)
   173  		err = view1.Set(registerID2, "", []byte("apple"))
   174  		assert.NoError(t, err)
   175  
   176  		sc2, _, err := state.CommitDelta(l, view1.Delta(), sc1)
   177  		assert.NoError(t, err)
   178  
   179  		// update value and get resulting state commitment
   180  		view2 := es.NewView(sc2)
   181  		err = view2.Delete(registerID1, "")
   182  		assert.NoError(t, err)
   183  
   184  		sc3, _, err := state.CommitDelta(l, view2.Delta(), sc2)
   185  		assert.NoError(t, err)
   186  
   187  		// create a view for previous state version
   188  		view3 := es.NewView(sc2)
   189  
   190  		// create a view for new state version
   191  		view4 := es.NewView(sc3)
   192  
   193  		// fetch the value at both versions
   194  		b1, err := view3.Get(registerID1, "")
   195  		assert.NoError(t, err)
   196  
   197  		b2, err := view4.Get(registerID1, "")
   198  		assert.NoError(t, err)
   199  
   200  		assert.Equal(t, flow.RegisterValue("apple"), b1)
   201  		assert.Empty(t, b2)
   202  	}))
   203  
   204  	t.Run("commit delta and persist state commit for the second time should be OK", prepareTest(func(t *testing.T, es state.ExecutionState, l *ledger.Ledger) {
   205  		// TODO: use real block ID
   206  		sc1, err := es.StateCommitmentByBlockID(context.Background(), flow.Identifier{})
   207  		assert.NoError(t, err)
   208  
   209  		// set initial value
   210  		view1 := es.NewView(sc1)
   211  		err = view1.Set(registerID1, "", flow.RegisterValue("apple"))
   212  		assert.NoError(t, err)
   213  		err = view1.Set(registerID2, "", flow.RegisterValue("apple"))
   214  		assert.NoError(t, err)
   215  
   216  		sc2, _, err := state.CommitDelta(l, view1.Delta(), sc1)
   217  		assert.NoError(t, err)
   218  
   219  		// committing for the second time should be OK
   220  		sc2Same, _, err := state.CommitDelta(l, view1.Delta(), sc1)
   221  		assert.NoError(t, err)
   222  
   223  		require.Equal(t, sc2, sc2Same)
   224  	}))
   225  
   226  }