diff --git a/executor/substate_provider.go b/executor/substate_provider.go index 7a235a39..adf9f1a1 100644 --- a/executor/substate_provider.go +++ b/executor/substate_provider.go @@ -19,6 +19,8 @@ package executor //go:generate mockgen -source substate_provider.go -destination substate_provider_mocks.go -package executor import ( + "errors" + "github.com/0xsoniclabs/aida/txcontext" substatecontext "github.com/0xsoniclabs/aida/txcontext/substate" "github.com/0xsoniclabs/aida/utils" @@ -53,21 +55,21 @@ type substateProvider struct { func (s substateProvider) Run(from int, to int, consumer Consumer[txcontext.TxContext]) error { iter := s.db.NewSubstateIterator(from, s.numParallelDecoders) + release := func(err error) error { + iter.Release() + return errors.Join(err, iter.Error()) + } + for iter.Next() { tx := iter.Value() if tx.Block >= uint64(to) { - // TODO bug not release - return nil + return release(nil) } if err := consumer(TransactionInfo[txcontext.TxContext]{int(tx.Block), tx.Transaction, substatecontext.NewTxContext(tx)}); err != nil { - // TODO bug not release - return err + return release(err) } } - // this cannot be used in defer because Release() has a WaitGroup.Wait() call - // so if called after iter.Error() there is a change the error does not get distributed. - iter.Release() - return iter.Error() + return release(nil) } func (s substateProvider) Close() { diff --git a/executor/substate_provider_test.go b/executor/substate_provider_test.go index adddae78..0a638b3e 100644 --- a/executor/substate_provider_test.go +++ b/executor/substate_provider_test.go @@ -257,6 +257,79 @@ func TestSubstateProvider_Run(t *testing.T) { assert.NoError(t, err) } +func TestSubstateProvider_Run_ReleasesIteratorOnUpperBound(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockDb := db.NewMockSubstateDB(ctrl) + mockIter := db.NewMockIIterator[*substate.Substate](ctrl) + mockDb.EXPECT().NewSubstateIterator(0, 0).Return(mockIter) + mockIter.EXPECT().Next().Return(true) + mockIter.EXPECT().Value().Return(&substate.Substate{ + Block: 1, + }) + mockIter.EXPECT().Release().Return() + mockIter.EXPECT().Error().Return(nil) + + provider := &substateProvider{ + db: mockDb, + } + err := provider.Run(0, 1, func(info TransactionInfo[txcontext.TxContext]) error { + t.Fatal("consumer must not be called for transactions outside the requested range") + return nil + }) + assert.NoError(t, err) +} + +func TestSubstateProvider_Run_ReleasesIteratorOnConsumerError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockDb := db.NewMockSubstateDB(ctrl) + mockIter := db.NewMockIIterator[*substate.Substate](ctrl) + mockDb.EXPECT().NewSubstateIterator(0, 0).Return(mockIter) + mockIter.EXPECT().Next().Return(true) + mockIter.EXPECT().Value().Return(&substate.Substate{ + Block: 0, + }) + mockIter.EXPECT().Release().Return() + mockIter.EXPECT().Error().Return(nil) + + consumerErr := errors.New("consumer failed") + provider := &substateProvider{ + db: mockDb, + } + err := provider.Run(0, 1, func(info TransactionInfo[txcontext.TxContext]) error { + return consumerErr + }) + assert.ErrorIs(t, err, consumerErr) +} + +func TestSubstateProvider_Run_ReturnsIteratorErrorAfterRelease(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockDb := db.NewMockSubstateDB(ctrl) + mockIter := db.NewMockIIterator[*substate.Substate](ctrl) + mockDb.EXPECT().NewSubstateIterator(0, 0).Return(mockIter) + mockIter.EXPECT().Next().Return(true) + mockIter.EXPECT().Value().Return(&substate.Substate{ + Block: 1, + }) + mockIter.EXPECT().Release().Return() + iterErr := errors.New("iterator failed") + mockIter.EXPECT().Error().Return(iterErr) + + provider := &substateProvider{ + db: mockDb, + } + err := provider.Run(0, 1, func(info TransactionInfo[txcontext.TxContext]) error { + t.Fatal("consumer must not be called for transactions outside the requested range") + return nil + }) + assert.ErrorIs(t, err, iterErr) +} + func TestSubstateProvider_Close(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish()