Skip to content

Commit

Permalink
Merge pull request #433 from multiversx/error_details_on_process_stat…
Browse files Browse the repository at this point in the history
…us_endpoint

added error details on /process-status
  • Loading branch information
sstanculeanu authored Mar 14, 2024
2 parents 62c486f + 6dc38f3 commit b1862c3
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 82 deletions.
2 changes: 1 addition & 1 deletion api/groups/baseTransactionGroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func (group *transactionGroup) getProcessedTransactionStatus(c *gin.Context) {
return
}

shared.RespondWith(c, http.StatusOK, gin.H{"status": status}, "", data.ReturnCodeSuccess)
shared.RespondWith(c, http.StatusOK, gin.H{"status": status.Status, "reason": status.Reason}, "", data.ReturnCodeSuccess)
}

func getTransactionByHashAndSenderAddress(c *gin.Context, ef TransactionFacadeHandler, txHash string, sndAddr string, withEvents bool) {
Expand Down
15 changes: 10 additions & 5 deletions api/groups/baseTransactionGroup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ type txProcessedStatusResp struct {
GeneralResponse
Data struct {
Status string `json:"status"`
Reason string `json:"reason"`
} `json:"data"`
}

Expand Down Expand Up @@ -776,9 +777,9 @@ func TestTransactionGroup_getProcessedTransactionStatus(t *testing.T) {
t.Parallel()

facade := &mock.FacadeStub{
GetProcessedTransactionStatusHandler: func(txHash string) (string, error) {
GetProcessedTransactionStatusHandler: func(txHash string) (*data.ProcessStatusResponse, error) {
assert.Equal(t, hash, txHash)
return "", expectedErr
return &data.ProcessStatusResponse{}, expectedErr
},
}
transactionsGroup, err := groups.NewTransactionGroup(facade)
Expand All @@ -799,9 +800,12 @@ func TestTransactionGroup_getProcessedTransactionStatus(t *testing.T) {
t.Run("should work", func(t *testing.T) {
t.Parallel()

status := "status"
status := &data.ProcessStatusResponse{
Status: "status",
Reason: "some error",
}
facade := &mock.FacadeStub{
GetProcessedTransactionStatusHandler: func(txHash string) (string, error) {
GetProcessedTransactionStatusHandler: func(txHash string) (*data.ProcessStatusResponse, error) {
assert.Equal(t, hash, txHash)
return status, nil
},
Expand All @@ -820,6 +824,7 @@ func TestTransactionGroup_getProcessedTransactionStatus(t *testing.T) {

assert.Equal(t, http.StatusOK, resp.Code)
assert.Empty(t, response.Error)
assert.Equal(t, status, response.Data.Status)
assert.Equal(t, status.Status, response.Data.Status)
assert.Equal(t, status.Reason, response.Data.Reason)
})
}
2 changes: 1 addition & 1 deletion api/groups/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ type TransactionFacadeHandler interface {
SendUserFunds(receiver string, value *big.Int) error
TransactionCostRequest(tx *data.Transaction) (*data.TxCostResponseData, error)
GetTransactionStatus(txHash string, sender string) (string, error)
GetProcessedTransactionStatus(txHash string) (string, error)
GetProcessedTransactionStatus(txHash string) (*data.ProcessStatusResponse, error)
GetTransaction(txHash string, withResults bool) (*transaction.ApiTransactionResult, error)
GetTransactionByHashAndSenderAddress(txHash string, sndAddr string, withEvents bool) (*transaction.ApiTransactionResult, int, error)
GetTransactionsPool(fields string) (*data.TransactionsPool, error)
Expand Down
4 changes: 2 additions & 2 deletions api/mock/facadeStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type FacadeStub struct {
AuctionListHandler func() ([]*data.AuctionListValidatorAPIResponse, error)
TransactionCostRequestHandler func(tx *data.Transaction) (*data.TxCostResponseData, error)
GetTransactionStatusHandler func(txHash string, sender string) (string, error)
GetProcessedTransactionStatusHandler func(txHash string) (string, error)
GetProcessedTransactionStatusHandler func(txHash string) (*data.ProcessStatusResponse, error)
GetConfigMetricsHandler func() (*data.GenericAPIResponse, error)
GetNetworkMetricsHandler func(shardID uint32) (*data.GenericAPIResponse, error)
GetAllIssuedESDTsHandler func(tokenType string) (*data.GenericAPIResponse, error)
Expand Down Expand Up @@ -424,7 +424,7 @@ func (f *FacadeStub) GetTransactionStatus(txHash string, sender string) (string,
}

// GetProcessedTransactionStatus -
func (f *FacadeStub) GetProcessedTransactionStatus(txHash string) (string, error) {
func (f *FacadeStub) GetProcessedTransactionStatus(txHash string) (*data.ProcessStatusResponse, error) {
return f.GetProcessedTransactionStatusHandler(txHash)
}

Expand Down
6 changes: 6 additions & 0 deletions data/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,9 @@ type TransactionsPoolNonceGapsForSenderApiResponse struct {
Error string `json:"error"`
Code string `json:"code"`
}

// ProcessStatusResponse represents a structure that holds the process status of a transaction
type ProcessStatusResponse struct {
Status string `json:"status"`
Reason string `json:"reason"`
}
2 changes: 1 addition & 1 deletion facade/baseFacade.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (pf *ProxyFacade) GetTransactionStatus(txHash string, sender string) (strin
}

// GetProcessedTransactionStatus should return transaction status after internal processing of the transaction results
func (pf *ProxyFacade) GetProcessedTransactionStatus(txHash string) (string, error) {
func (pf *ProxyFacade) GetProcessedTransactionStatus(txHash string) (*data.ProcessStatusResponse, error) {
return pf.txProc.GetProcessedTransactionStatus(txHash)
}

Expand Down
2 changes: 1 addition & 1 deletion facade/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type TransactionProcessor interface {
TransactionCostRequest(tx *data.Transaction) (*data.TxCostResponseData, error)
GetTransactionStatus(txHash string, sender string) (string, error)
GetTransaction(txHash string, withEvents bool) (*transaction.ApiTransactionResult, error)
GetProcessedTransactionStatus(txHash string) (string, error)
GetProcessedTransactionStatus(txHash string) (*data.ProcessStatusResponse, error)
GetTransactionByHashAndSenderAddress(txHash string, sndAddr string, withEvents bool) (*transaction.ApiTransactionResult, int, error)
ComputeTransactionHash(tx *data.Transaction) (string, error)
GetTransactionsPool(fields string) (*data.TransactionsPool, error)
Expand Down
6 changes: 3 additions & 3 deletions facade/mock/transactionProcessorStub.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type TransactionProcessorStub struct {
SendUserFundsCalled func(receiver string, value *big.Int) error
TransactionCostRequestCalled func(tx *data.Transaction) (*data.TxCostResponseData, error)
GetTransactionStatusCalled func(txHash string, sender string) (string, error)
GetProcessedTransactionStatusCalled func(txHash string) (string, error)
GetProcessedTransactionStatusCalled func(txHash string) (*data.ProcessStatusResponse, error)
GetTransactionCalled func(txHash string, withEvents bool) (*transaction.ApiTransactionResult, error)
GetTransactionByHashAndSenderAddressCalled func(txHash string, sndAddr string, withEvents bool) (*transaction.ApiTransactionResult, int, error)
ComputeTransactionHashCalled func(tx *data.Transaction) (string, error)
Expand Down Expand Up @@ -84,12 +84,12 @@ func (tps *TransactionProcessorStub) GetTransactionStatus(txHash string, sender
}

// GetProcessedTransactionStatus -
func (tps *TransactionProcessorStub) GetProcessedTransactionStatus(txHash string) (string, error) {
func (tps *TransactionProcessorStub) GetProcessedTransactionStatus(txHash string) (*data.ProcessStatusResponse, error) {
if tps.GetProcessedTransactionStatusCalled != nil {
return tps.GetProcessedTransactionStatusCalled(txHash)
}

return "", errNotImplemented
return &data.ProcessStatusResponse{}, errNotImplemented
}

// GetTransaction -
Expand Down
7 changes: 6 additions & 1 deletion process/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ func GetShortHashSize() int {
}

// ComputeTransactionStatus -
func (tp *TransactionProcessor) ComputeTransactionStatus(tx *transaction.ApiTransactionResult, withResults bool) transaction.TxStatus {
func (tp *TransactionProcessor) ComputeTransactionStatus(tx *transaction.ApiTransactionResult, withResults bool) *proxyData.ProcessStatusResponse {
return tp.computeTransactionStatus(tx, withResults)
}

// CheckIfFailed -
func CheckIfFailed(logs []*transaction.ApiLogs) (bool, string) {
return checkIfFailed(logs)
}
97 changes: 65 additions & 32 deletions process/transactionProcessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const (
relayedTxV1DataMarker = "relayedTx@"
relayedTxV2DataMarker = "relayedTxV2"
argumentsSeparator = "@"
emptyDataStr = ""
)

type requestType int
Expand Down Expand Up @@ -417,76 +418,108 @@ func (tp *TransactionProcessor) getTransaction(txHash string, sender string, wit
}

// GetProcessedTransactionStatus returns the status of a transaction after local processing
func (tp *TransactionProcessor) GetProcessedTransactionStatus(txHash string) (string, error) {
func (tp *TransactionProcessor) GetProcessedTransactionStatus(txHash string) (*data.ProcessStatusResponse, error) {
const withResults = true
tx, err := tp.getTxFromObservers(txHash, requestTypeObservers, withResults)
if err != nil {
return string(data.TxStatusUnknown), err
return &data.ProcessStatusResponse{
Status: string(data.TxStatusUnknown),
}, err
}

return string(tp.computeTransactionStatus(tx, withResults)), nil
return tp.computeTransactionStatus(tx, withResults), nil
}

func (tp *TransactionProcessor) computeTransactionStatus(tx *transaction.ApiTransactionResult, withResults bool) transaction.TxStatus {
func (tp *TransactionProcessor) computeTransactionStatus(tx *transaction.ApiTransactionResult, withResults bool) *data.ProcessStatusResponse {
if !withResults {
return data.TxStatusUnknown
return &data.ProcessStatusResponse{
Status: string(data.TxStatusUnknown),
}
}

if tx.Status == transaction.TxStatusInvalid {
return transaction.TxStatusFail
return &data.ProcessStatusResponse{
Status: string(transaction.TxStatusFail),
}
}
if tx.Status != transaction.TxStatusSuccess {
return tx.Status
return &data.ProcessStatusResponse{
Status: string(tx.Status),
}
}

if checkIfMoveBalanceNotarized(tx) {
return tx.Status
return &data.ProcessStatusResponse{
Status: string(tx.Status),
}
}

txLogsOnFirstLevel := []*transaction.ApiLogs{tx.Logs}
if checkIfFailed(txLogsOnFirstLevel) {
return transaction.TxStatusFail
failed, reason := checkIfFailed(txLogsOnFirstLevel)
if failed {
return &data.ProcessStatusResponse{
Status: string(transaction.TxStatusFail),
Reason: reason,
}
}

allLogs, allScrs, err := tp.gatherAllLogsAndScrs(tx)
if err != nil {
log.Warn("error in TransactionProcessor.computeTransactionStatus", "error", err)
return data.TxStatusUnknown
return &data.ProcessStatusResponse{
Status: string(data.TxStatusUnknown),
}
}

allLogs, err = tp.addMissingLogsOnProcessingExceptions(tx, allLogs, allScrs)
if err != nil {
log.Warn("error in TransactionProcessor.computeTransactionStatus on addMissingLogsOnProcessingExceptions call", "error", err)
return data.TxStatusUnknown
return &data.ProcessStatusResponse{
Status: string(data.TxStatusUnknown),
}
}

if checkIfFailed(allLogs) {
return transaction.TxStatusFail
failed, reason = checkIfFailed(allLogs)
if failed {
return &data.ProcessStatusResponse{
Status: string(transaction.TxStatusFail),
Reason: reason,
}
}

if checkIfCompleted(allLogs) {
return transaction.TxStatusSuccess
return &data.ProcessStatusResponse{
Status: string(transaction.TxStatusSuccess),
}
}

return transaction.TxStatusPending
return &data.ProcessStatusResponse{
Status: string(transaction.TxStatusPending),
}
}

func checkIfFailed(logs []*transaction.ApiLogs) bool {
if findIdentifierInLogs(logs, internalVMErrorsEventIdentifier) ||
findIdentifierInLogs(logs, core.SignalErrorOperation) {
return true
func checkIfFailed(logs []*transaction.ApiLogs) (bool, string) {
found, reason := findIdentifierInLogs(logs, internalVMErrorsEventIdentifier)
if found {
return true, reason
}

return false
found, reason = findIdentifierInLogs(logs, core.SignalErrorOperation)
if found {
return true, reason
}

return false, emptyDataStr
}

func checkIfCompleted(logs []*transaction.ApiLogs) bool {
if findIdentifierInLogs(logs, core.CompletedTxEventIdentifier) ||
findIdentifierInLogs(logs, core.SCDeployIdentifier) {
found, _ := findIdentifierInLogs(logs, core.CompletedTxEventIdentifier)
if found {
return true
}

return false
found, _ = findIdentifierInLogs(logs, core.SCDeployIdentifier)
return found
}

func checkIfMoveBalanceNotarized(tx *transaction.ApiTransactionResult) bool {
Expand Down Expand Up @@ -641,33 +674,33 @@ func (tp *TransactionProcessor) isSameShardSenderReceiverOfInnerTxV2(
return tp.proc.GetShardCoordinator().SameShard(relayedSender, receiver), nil
}

func findIdentifierInLogs(logs []*transaction.ApiLogs, identifier string) bool {
func findIdentifierInLogs(logs []*transaction.ApiLogs, identifier string) (bool, string) {
if len(logs) == 0 {
return false
return false, emptyDataStr
}

for _, logInstance := range logs {
if logInstance == nil {
continue
}

found := findIdentifierInSingleLog(logInstance, identifier)
found, reason := findIdentifierInSingleLog(logInstance, identifier)
if found {
return true
return true, string(reason)
}
}

return false
return false, emptyDataStr
}

func findIdentifierInSingleLog(log *transaction.ApiLogs, identifier string) bool {
func findIdentifierInSingleLog(log *transaction.ApiLogs, identifier string) (bool, []byte) {
for _, event := range log.Events {
if event.Identifier == identifier {
return true
return true, event.Data
}
}

return false
return false, []byte(emptyDataStr)
}

func (tp *TransactionProcessor) gatherAllLogsAndScrs(tx *transaction.ApiTransactionResult) ([]*transaction.ApiLogs, []*transaction.ApiTransactionResult, error) {
Expand Down
Loading

0 comments on commit b1862c3

Please sign in to comment.