diff --git a/common/common_test.go b/common/common_test.go index 3ce8b9b78be..42d39c3bef5 100644 --- a/common/common_test.go +++ b/common/common_test.go @@ -577,3 +577,10 @@ func TestGetLastBaseExecutionResultHandler(t *testing.T) { require.Equal(t, common.ErrNilBaseExecutionResult, err) }) } + +func TestPrepareLogEventsKey(t *testing.T) { + t.Parallel() + + logs := common.PrepareLogEventsKey([]byte("LogsX")) + require.Equal(t, "logsLogsX", string(logs)) +} diff --git a/dblookupext/factory/historyRepositoryFactory_test.go b/dblookupext/factory/historyRepositoryFactory_test.go index 1449142b6ad..e3483dbb1e5 100644 --- a/dblookupext/factory/historyRepositoryFactory_test.go +++ b/dblookupext/factory/historyRepositoryFactory_test.go @@ -47,6 +47,12 @@ func TestNewHistoryRepositoryFactory(t *testing.T) { require.Equal(t, process.ErrNilUint64Converter, err) require.Nil(t, hrf) + argsNilDataPool := getArgs() + argsNilDataPool.DataPool = nil + hrf, err = factory.NewHistoryRepositoryFactory(argsNilDataPool) + require.Equal(t, process.ErrNilDataPoolHolder, err) + require.Nil(t, hrf) + hrf, err = factory.NewHistoryRepositoryFactory(args) require.NoError(t, err) require.False(t, check.IfNil(hrf)) diff --git a/dblookupext/historyRepository_test.go b/dblookupext/historyRepository_test.go index 69913abc9c7..5435243ad50 100644 --- a/dblookupext/historyRepository_test.go +++ b/dblookupext/historyRepository_test.go @@ -2,6 +2,7 @@ package dblookupext import ( "errors" + "math/big" "sync" "testing" @@ -20,11 +21,14 @@ import ( dataRetrieverMock "github.com/multiversx/mx-chain-go/testscommon/dataRetriever" "github.com/multiversx/mx-chain-go/testscommon/genericMocks" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" + "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" storageStubs "github.com/multiversx/mx-chain-go/testscommon/storage" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +var expectedError = errors.New("expected error") + func createMockHistoryRepoArgs(epoch uint32) HistoryRepositoryArguments { sp, _ := esdtSupply.NewSuppliesProcessor(&mock.MarshalizerMock{}, &storageStubs.StorerStub{ GetCalled: func(key []byte) ([]byte, error) { @@ -95,12 +99,30 @@ func TestNewHistoryRepository(t *testing.T) { require.Nil(t, repo) require.Equal(t, process.ErrNilUint64Converter, err) + args = createMockHistoryRepoArgs(0) + args.DataPool = nil + repo, err = NewHistoryRepository(args) + require.Nil(t, repo) + require.Equal(t, process.ErrNilDataPoolHolder, err) + args = createMockHistoryRepoArgs(0) repo, err = NewHistoryRepository(args) require.Nil(t, err) require.NotNil(t, repo) } +func TestHistoryRepository_RecordBlockErrCannotCastToBlockBody(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(0) + + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + err = repo.RecordBlock([]byte("headerHash"), &block.Header{}, nil, nil, nil, nil, nil) + require.Equal(t, errCannotCastToBlockBody, err) +} + func TestHistoryRepository_RecordBlockInvalidBlockRoundByHashStorerExpectError(t *testing.T) { t.Parallel() @@ -842,4 +864,310 @@ func TestRecordHeaderV3(t *testing.T) { require.Nil(t, err) require.Equal(t, 42, int(epoch)) }) + + t.Run("record block v3 should error because the headerHash is not found in cache", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + args.DataPool = dataRetrieverMock.NewPoolsHolderMock() + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + executionResultHeaderHash := []byte("executionResultHeaderHash") + header := &block.HeaderV3{ + ExecutionResults: []*block.ExecutionResult{ + { + BaseExecutionResult: &block.BaseExecutionResult{ + HeaderHash: executionResultHeaderHash, + }, + }, + }, + } + + body := &block.Body{} + headerHash := []byte("headerHash") + err = repo.RecordBlock(headerHash, header, body, nil, nil, nil, nil) + require.NotNil(t, err) + require.ErrorContains(t, err, process.ErrMissingHeader.Error()) + }) + + t.Run("record block v3 should error because logs were not found in dataPool", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + args.DataPool = dataRetrieverMock.NewPoolsHolderMock() + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + executionResultHeaderHash := []byte("executionResultHeaderHash") + header := &block.HeaderV3{ + ExecutionResults: []*block.ExecutionResult{ + { + BaseExecutionResult: &block.BaseExecutionResult{ + HeaderHash: executionResultHeaderHash, + }, + }, + }, + } + + cachedIntermediateTxsMap := map[block.Type]map[string]data.TransactionHandler{} + // add the header hash + args.DataPool.PostProcessTransactions().Put(executionResultHeaderHash, cachedIntermediateTxsMap, 1) + + body := &block.Body{} + headerHash := []byte("headerHash") + err = repo.RecordBlock(headerHash, header, body, nil, nil, nil, nil) + require.NotNil(t, err) + require.ErrorContains(t, err, process.ErrMissingHeader.Error()) + }) + + t.Run("record block v3 should error because mini blocks were not cached", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + args.DataPool = dataRetrieverMock.NewPoolsHolderMock() + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + executionResultHeaderHash := []byte("executionResultHeaderHash") + header := &block.HeaderV3{ + ExecutionResults: []*block.ExecutionResult{ + { + BaseExecutionResult: &block.BaseExecutionResult{ + HeaderHash: executionResultHeaderHash, + }, + MiniBlockHeaders: []block.MiniBlockHeader{ + { + Hash: []byte("mbHash"), + }, + }, + }, + }, + } + + cachedIntermediateTxsMap := map[block.Type]map[string]data.TransactionHandler{} + // add the header hash + args.DataPool.PostProcessTransactions().Put(executionResultHeaderHash, cachedIntermediateTxsMap, 1) + + expectedLogs := []*data.LogData{ + { + LogHandler: &transaction.Log{}, + TxHash: "t1", + }, + } + logsKey := common.PrepareLogEventsKey(executionResultHeaderHash) + // add the logs + args.DataPool.PostProcessTransactions().Put(logsKey, expectedLogs, 1) + + body := &block.Body{} + headerHash := []byte("headerHash") + err = repo.RecordBlock(headerHash, header, body, nil, nil, nil, nil) + require.NotNil(t, err) + require.ErrorContains(t, err, process.ErrMissingMiniBlock.Error()) + }) + + t.Run("record block v3 should error because intra mini blocks were not found", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + args.DataPool = dataRetrieverMock.NewPoolsHolderMock() + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + executionResultHeaderHash := []byte("executionResultHeaderHash") + mb := &block.MiniBlock{SenderShardID: 0} + mbHash1, _ := repo.computeMiniblockHash(mb) + header := &block.HeaderV3{ + ExecutionResults: []*block.ExecutionResult{ + { + BaseExecutionResult: &block.BaseExecutionResult{ + HeaderHash: executionResultHeaderHash, + }, + MiniBlockHeaders: []block.MiniBlockHeader{ + { + Hash: mbHash1, + }, + }, + }, + }, + } + + mbBytes, _ := repo.marshalizer.Marshal(mb) + // add the mini blocks + args.DataPool.ExecutedMiniBlocks().Put(mbHash1, mbBytes, 1) + + cachedIntermediateTxsMap := map[block.Type]map[string]data.TransactionHandler{} + // add the header hash + args.DataPool.PostProcessTransactions().Put(executionResultHeaderHash, cachedIntermediateTxsMap, 1) + + expectedLogs := []*data.LogData{ + { + LogHandler: &transaction.Log{}, + TxHash: "t1", + }, + } + logsKey := common.PrepareLogEventsKey(executionResultHeaderHash) + // add the logs + args.DataPool.PostProcessTransactions().Put(logsKey, expectedLogs, 1) + + body := &block.Body{} + headerHash := []byte("headerHash") + err = repo.RecordBlock(headerHash, header, body, nil, nil, nil, nil) + require.NotNil(t, err) + require.ErrorContains(t, err, process.ErrMissingHeader.Error()) + }) + + t.Run("record block v3 should error because of Marshal on recordBlock", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + + expectedError := errors.New("expected error") + args.Marshalizer = &marshallerMock.MarshalizerStub{MarshalCalled: func(obj interface{}) ([]byte, error) { + return nil, expectedError + }} + + args.DataPool = dataRetrieverMock.NewPoolsHolderMock() + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + header := &block.HeaderV3{} + body := &block.Body{} + + headerHash := []byte("headerHash") + + err = repo.RecordBlock(headerHash, header, body, nil, nil, nil, nil) + require.ErrorContains(t, err, expectedError.Error()) + }) +} + +func TestHistoryRepository_GetResultsHashesByTxHashShouldError(t *testing.T) { + t.Parallel() + + t.Run("should error ErrNotFoundInStorage", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + + repo, err := NewHistoryRepository(args) + require.NoError(t, err) + + results, err := repo.GetResultsHashesByTxHash([]byte("txHash1"), 42) + require.Nil(t, results) + require.ErrorContains(t, err, ErrNotFoundInStorage.Error()) + }) +} + +func TestHistoryRepository_RevertBlockShouldError(t *testing.T) { + t.Parallel() + + t.Run("should return nil because of nil body", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + repo, err := NewHistoryRepository(args) + require.NoError(t, err) + + err = repo.RevertBlock(&block.Header{}, nil) + require.NoError(t, err) + }) + + t.Run("should return nil because of nil header", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + repo, err := NewHistoryRepository(args) + require.NoError(t, err) + + err = repo.RevertBlock(nil, &block.Body{}) + require.NoError(t, err) + }) + + t.Run("should error because of unmarshal", func(t *testing.T) { + t.Parallel() + + sp, _ := esdtSupply.NewSuppliesProcessor(&mock.MarshalizerMock{ + Fail: true, + }, &storageStubs.StorerStub{ + GetCalled: func(key []byte) ([]byte, error) { + return nil, storage.ErrKeyNotFound + }, + }, &storageStubs.StorerStub{}) + + args := createMockHistoryRepoArgs(42) + args.ESDTSuppliesHandler = sp + + repo, err := NewHistoryRepository(args) + require.NoError(t, err) + + err = repo.RevertBlock(&block.Header{}, &block.Body{ + MiniBlocks: []*block.MiniBlock{ + { + TxHashes: [][]byte{[]byte("txHash1")}, + }, + }, + }) + require.Equal(t, mock.ErrMockMarshalizer, err) + }) +} + +func TestHistoryRepository_GetESDTSupply(t *testing.T) { + t.Parallel() + + t.Run("should return error", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + sp, _ := esdtSupply.NewSuppliesProcessor(&mock.MarshalizerMock{}, &storageStubs.StorerStub{ + GetCalled: func(key []byte) ([]byte, error) { + return nil, expectedError + }, + }, &storageStubs.StorerStub{}) + + args.ESDTSuppliesHandler = sp + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + res, err := repo.GetESDTSupply("token1") + require.Nil(t, res) + require.Equal(t, expectedError, err) + }) + + t.Run("should return SupplyESDTZero because of ErrKeyNotFound", func(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + res, err := repo.GetESDTSupply("token1") + require.Nil(t, err) + + require.Equal(t, big.NewInt(0), res.Supply) + require.Equal(t, big.NewInt(0), res.Burned) + require.Equal(t, big.NewInt(0), res.Minted) + }) +} + +func TestHistoryRepository_IsEnabled(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + require.True(t, repo.IsEnabled()) +} + +func TestHistoryRepository_IsInterfaceNil(t *testing.T) { + t.Parallel() + + args := createMockHistoryRepoArgs(42) + repo, err := NewHistoryRepository(args) + require.Nil(t, err) + + require.False(t, repo.IsInterfaceNil()) + + var nilRepo *historyRepository + require.True(t, nilRepo.IsInterfaceNil()) }