From 3e4d8321ff2e0f583b0d73828ca6c201f1ef33db Mon Sep 17 00:00:00 2001 From: Iuga Mihai Date: Wed, 9 Dec 2020 14:06:33 +0200 Subject: [PATCH 1/5] fix api route /address/:addr/transactions --- process/database/elasticSearchConnector.go | 29 ++++++++++++++++++++-- process/database/queries.go | 26 ------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/process/database/elasticSearchConnector.go b/process/database/elasticSearchConnector.go index 172d540d..709c9b83 100644 --- a/process/database/elasticSearchConnector.go +++ b/process/database/elasticSearchConnector.go @@ -37,8 +37,7 @@ func NewElasticSearchConnector(url, username, password string) (*elasticSearchCo // GetTransactionsByAddress gets transactions TO or FROM the specified address func (esc *elasticSearchConnector) GetTransactionsByAddress(address string) ([]data.DatabaseTransaction, error) { - query := txsByAddrQuery(address) - decodedBody, err := esc.doSearchRequest(query, "transactions", numTopTransactions) + decodedBody, err := esc.doSearchRequestTx(address, "transactions", numTopTransactions) if err != nil { return nil, err } @@ -151,6 +150,32 @@ func (esc *elasticSearchConnector) doSearchRequest(query object, index string, s return decodedBody, nil } +func (esc *elasticSearchConnector) doSearchRequestTx(address string, index string, size int) (object, error) { + res, err := esc.client.Search( + esc.client.Search.WithIndex(index), + esc.client.Search.WithSize(size), + esc.client.Search.WithQuery("sender%"+address+"+receiver%"+address), + esc.client.Search.WithSort("timestamp:desc"), + ) + if err != nil { + return nil, fmt.Errorf("cannot get data from database: %w", err) + } + + defer func() { + _ = res.Body.Close() + }() + if res.IsError() { + return nil, fmt.Errorf("cannot get data from database: %v", res) + } + + var decodedBody map[string]interface{} + if err := json.NewDecoder(res.Body).Decode(&decodedBody); err != nil { + return nil, err + } + + return decodedBody, nil +} + // IsInterfaceNil returns true if there is no value under the interface func (esc *elasticSearchConnector) IsInterfaceNil() bool { return esc == nil diff --git a/process/database/queries.go b/process/database/queries.go index 2ecb06ee..5219ed09 100644 --- a/process/database/queries.go +++ b/process/database/queries.go @@ -17,32 +17,6 @@ func encodeQuery(query object) (bytes.Buffer, error) { return buff, nil } -func txsByAddrQuery(addr string) object { - return object{ - "query": object{ - "bool": object{ - "should": []interface{}{ - object{ - "match": object{ - "sender": addr, - }, - }, - object{ - "match": object{ - "receiver": addr, - }, - }, - }, - }, - }, - "sort": object{ - "timestamp": object{ - "order": "desc", - }, - }, - } -} - func blockByNonceAndShardIDQuery(nonce uint64, shardID uint32) object { return object{ "query": object{ From b5a847446c0a07ba5f734cc287a3970879595779 Mon Sep 17 00:00:00 2001 From: Iuga Mihai Date: Wed, 9 Dec 2020 14:53:41 +0200 Subject: [PATCH 2/5] fix after review --- process/database/elasticSearchConnector.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/process/database/elasticSearchConnector.go b/process/database/elasticSearchConnector.go index 709c9b83..54d4a6de 100644 --- a/process/database/elasticSearchConnector.go +++ b/process/database/elasticSearchConnector.go @@ -151,10 +151,11 @@ func (esc *elasticSearchConnector) doSearchRequest(query object, index string, s } func (esc *elasticSearchConnector) doSearchRequestTx(address string, index string, size int) (object, error) { + query := fmt.Sprintf("sender:%s OR receiver:%s", address, address) res, err := esc.client.Search( esc.client.Search.WithIndex(index), esc.client.Search.WithSize(size), - esc.client.Search.WithQuery("sender%"+address+"+receiver%"+address), + esc.client.Search.WithQuery(query), esc.client.Search.WithSort("timestamp:desc"), ) if err != nil { From 1a49220880ec15d658340e6e33d5fb416180d356 Mon Sep 17 00:00:00 2001 From: Iuga Mihai Date: Wed, 9 Dec 2020 15:12:37 +0200 Subject: [PATCH 3/5] check for address --- process/accountProcessor.go | 4 ++++ process/accountProcessor_test.go | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/process/accountProcessor.go b/process/accountProcessor.go index 7917fd79..e2d28bce 100644 --- a/process/accountProcessor.go +++ b/process/accountProcessor.go @@ -102,6 +102,10 @@ func (ap *AccountProcessor) GetValueForKey(address string, key string) (string, // GetTransactions resolves the request and returns a slice of transaction for the specific address func (ap *AccountProcessor) GetTransactions(address string) ([]data.DatabaseTransaction, error) { + if _, err := ap.pubKeyConverter.Decode(address); err != nil { + return nil, ErrInvalidAddress + } + return ap.connector.GetTransactionsByAddress(address) } diff --git a/process/accountProcessor_test.go b/process/accountProcessor_test.go index 5c98f4e3..ad279c0a 100644 --- a/process/accountProcessor_test.go +++ b/process/accountProcessor_test.go @@ -2,6 +2,8 @@ package process_test import ( "errors" + "github.com/ElrondNetwork/elrond-go/config" + "github.com/ElrondNetwork/elrond-go/data/state/factory" "testing" "github.com/ElrondNetwork/elrond-go/core/pubkeyConverter" @@ -281,3 +283,23 @@ func TestAccountProcessor_GetShardIDForAddressShouldError(t *testing.T) { assert.Equal(t, uint32(0), shardID) assert.Equal(t, expectedError, err) } + +func TestAccountProcessor_GetTransactionsInvalidAddrShouldErr(t *testing.T) { + t.Parallel() + + converter, _ := factory.NewPubkeyConverter(config.PubkeyConfig{ + Length: 32, + Type: "bech32", + }) + ap, _ := process.NewAccountProcessor( + &mock.ProcessorStub{}, + converter, + database.NewDisabledElasticSearchConnector(), + ) + + _, err := ap.GetTransactions("invalidAddress") + assert.Equal(t, process.ErrInvalidAddress, err) + + _, err = ap.GetTransactions("") + assert.Equal(t, process.ErrInvalidAddress, err) +} From 45ffaadbdcd06f2be7b15806a90289275e1a5f4f Mon Sep 17 00:00:00 2001 From: Iuga Mihai Date: Wed, 9 Dec 2020 15:17:05 +0200 Subject: [PATCH 4/5] wrap error --- process/accountProcessor.go | 3 ++- process/accountProcessor_test.go | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/process/accountProcessor.go b/process/accountProcessor.go index e2d28bce..9b89e2ec 100644 --- a/process/accountProcessor.go +++ b/process/accountProcessor.go @@ -2,6 +2,7 @@ package process import ( "errors" + "fmt" "net/http" "github.com/ElrondNetwork/elrond-go/core" @@ -103,7 +104,7 @@ func (ap *AccountProcessor) GetValueForKey(address string, key string) (string, // GetTransactions resolves the request and returns a slice of transaction for the specific address func (ap *AccountProcessor) GetTransactions(address string) ([]data.DatabaseTransaction, error) { if _, err := ap.pubKeyConverter.Decode(address); err != nil { - return nil, ErrInvalidAddress + return nil, fmt.Errorf("%w, %v", ErrInvalidAddress, err) } return ap.connector.GetTransactionsByAddress(address) diff --git a/process/accountProcessor_test.go b/process/accountProcessor_test.go index ad279c0a..49a209d9 100644 --- a/process/accountProcessor_test.go +++ b/process/accountProcessor_test.go @@ -2,11 +2,11 @@ package process_test import ( "errors" - "github.com/ElrondNetwork/elrond-go/config" - "github.com/ElrondNetwork/elrond-go/data/state/factory" "testing" + "github.com/ElrondNetwork/elrond-go/config" "github.com/ElrondNetwork/elrond-go/core/pubkeyConverter" + "github.com/ElrondNetwork/elrond-go/data/state/factory" "github.com/ElrondNetwork/elrond-go/sharding" "github.com/ElrondNetwork/elrond-proxy-go/data" "github.com/ElrondNetwork/elrond-proxy-go/process" @@ -298,8 +298,8 @@ func TestAccountProcessor_GetTransactionsInvalidAddrShouldErr(t *testing.T) { ) _, err := ap.GetTransactions("invalidAddress") - assert.Equal(t, process.ErrInvalidAddress, err) + assert.True(t, errors.Is(err, process.ErrInvalidAddress)) _, err = ap.GetTransactions("") - assert.Equal(t, process.ErrInvalidAddress, err) + assert.True(t, errors.Is(err, process.ErrInvalidAddress)) } From 6852fc36cd496399cc1ec2014fef41b0fa34c30a Mon Sep 17 00:00:00 2001 From: Iuga Mihai Date: Wed, 9 Dec 2020 15:53:29 +0200 Subject: [PATCH 5/5] positive test --- process/accountProcessor_test.go | 7 +++++-- process/mock/elasticSearchConnectorMock.go | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 process/mock/elasticSearchConnectorMock.go diff --git a/process/accountProcessor_test.go b/process/accountProcessor_test.go index 49a209d9..7117bbd9 100644 --- a/process/accountProcessor_test.go +++ b/process/accountProcessor_test.go @@ -284,7 +284,7 @@ func TestAccountProcessor_GetShardIDForAddressShouldError(t *testing.T) { assert.Equal(t, expectedError, err) } -func TestAccountProcessor_GetTransactionsInvalidAddrShouldErr(t *testing.T) { +func TestAccountProcessor_GetTransactions(t *testing.T) { t.Parallel() converter, _ := factory.NewPubkeyConverter(config.PubkeyConfig{ @@ -294,7 +294,7 @@ func TestAccountProcessor_GetTransactionsInvalidAddrShouldErr(t *testing.T) { ap, _ := process.NewAccountProcessor( &mock.ProcessorStub{}, converter, - database.NewDisabledElasticSearchConnector(), + &mock.ElasticSearchConnectorMock{}, ) _, err := ap.GetTransactions("invalidAddress") @@ -302,4 +302,7 @@ func TestAccountProcessor_GetTransactionsInvalidAddrShouldErr(t *testing.T) { _, err = ap.GetTransactions("") assert.True(t, errors.Is(err, process.ErrInvalidAddress)) + + _, err = ap.GetTransactions("erd1ycega644rvjtgtyd8hfzt6hl5ymaa8ml2nhhs5cv045cz5vxm00q022myr") + assert.Nil(t, err) } diff --git a/process/mock/elasticSearchConnectorMock.go b/process/mock/elasticSearchConnectorMock.go new file mode 100644 index 00000000..8aaf292a --- /dev/null +++ b/process/mock/elasticSearchConnectorMock.go @@ -0,0 +1,21 @@ +package mock + +import "github.com/ElrondNetwork/elrond-proxy-go/data" + +type ElasticSearchConnectorMock struct { +} + +// GetTransactionsByAddress - +func (escm *ElasticSearchConnectorMock) GetTransactionsByAddress(_ string) ([]data.DatabaseTransaction, error) { + return nil, nil +} + +// GetAtlasBlockByShardIDAndNonce - +func (escm *ElasticSearchConnectorMock) GetAtlasBlockByShardIDAndNonce(_ uint32, _ uint64) (data.AtlasBlock, error) { + return data.AtlasBlock{}, nil +} + +// IsInterfaceNil - +func (escm *ElasticSearchConnectorMock) IsInterfaceNil() bool { + return escm == nil +}