Skip to content

Commit

Permalink
Merge pull request #368 from multiversx/fix-cost-api-route
Browse files Browse the repository at this point in the history
TX cost api route fixes
  • Loading branch information
miiu96 authored Jul 3, 2023
2 parents 5c93c27 + cb501b7 commit 26fc411
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 8 deletions.
1 change: 1 addition & 0 deletions data/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ type TxCostResponseData struct {
TxCost uint64 `json:"txGasUnits"`
RetMessage string `json:"returnMessage"`
ScResults map[string]*ExtendedApiSmartContractResult `json:"smartContractResults"`
Logs *transaction.ApiLogs `json:"logs,omitempty"`
}

// ExtendedApiSmartContractResult extends the structure transaction.ApiSmartContractResult with an extra field
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjW
github.com/multiversx/mx-chain-core-go v1.1.30/go.mod h1:8gGEQv6BWuuJwhd25qqhCOZbBSv9mk+hLeKvinSaSMk=
github.com/multiversx/mx-chain-core-go v1.1.32 h1:7Es5r4go0jJt3eBuPGv4RnYeHX/GkISET32SO8xJF+w=
github.com/multiversx/mx-chain-core-go v1.1.32/go.mod h1:8gGEQv6BWuuJwhd25qqhCOZbBSv9mk+hLeKvinSaSMk=
github.com/multiversx/mx-chain-core-go v1.2.8 h1:G5gva3AcPO1K1yeks7o16Da80V43b4eI9JcB6RgZzFM=
github.com/multiversx/mx-chain-core-go v1.2.8/go.mod h1:jzYFSiYBuO0dGpGFXnZWSwcwcKP7Flyn/X41y4zIQrQ=
github.com/multiversx/mx-chain-crypto-go v1.2.5 h1:tuq3BUNMhKud5DQbZi9DiVAAHUXypizy8zPH0NpTGZk=
github.com/multiversx/mx-chain-crypto-go v1.2.5/go.mod h1:teqhNyWEqfMPgNn8sgWXlgtJ1a36jGCnhs/tRpXW6r4=
github.com/multiversx/mx-chain-es-indexer-go v1.3.7 h1:R0hbySmg9QIfEyn1eFlYqtVP7kYjmw5FRNlYv4C2Ajw=
Expand Down
6 changes: 4 additions & 2 deletions process/txcost/gasUsed.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ func (tcp *transactionCostProcessor) computeResponsesGasUsed(extra int, res *dat
return
}

gasUsed += tcp.responses[idx+extra].Data.TxCost - tcp.txsFromSCR[idx].GasLimit
diff := tcp.responses[idx+extra].Data.TxCost - tcp.txsFromSCR[idx].GasLimit
gasUsed += diff
}

gasUsed += tcp.responses[numResponses-1].Data.TxCost
gasForLastResponse := tcp.responses[numResponses-1].Data.TxCost
gasUsed += gasForLastResponse
res.TxCost = gasUsed
}
4 changes: 3 additions & 1 deletion process/txcost/gasUsed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ func TestTransactionCostProcessor_PrepareGasUsedShouldWork(t *testing.T) {
res := &data.TxCostResponseData{
TxCost: 500,
}

expectedGas := uint64(1300)
newTxCostProcessor.prepareGasUsed(0, 0, res)
require.Equal(t, uint64(1300), res.TxCost)
require.Equal(t, expectedGas, res.TxCost)
require.Equal(t, "", res.RetMessage)
}
68 changes: 64 additions & 4 deletions process/txcost/transactionCostProcessor.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package txcost

import (
"bytes"
"net/http"

"github.com/multiversx/mx-chain-core-go/core"
Expand All @@ -11,8 +12,12 @@ import (
"github.com/multiversx/mx-chain-proxy-go/process"
)

// TransactionCostPath defines the transaction's cost path of the node
const TransactionCostPath = "/transaction/cost"
const (
// TransactionCostPath defines the transaction's cost path of the node
TransactionCostPath = "/transaction/cost"

tooMuchGasProvidedMessage = "@too much gas provided"
)

var log = logger.GetOrCreate("process/txcost")

Expand All @@ -21,6 +26,7 @@ type transactionCostProcessor struct {
pubKeyConverter core.PubkeyConverter
responses []*data.ResponseTxCost
txsFromSCR []*data.Transaction
hasExecutedSCR bool
}

// NewTransactionCostProcessor will create a new instance of the transactionCostProcessor
Expand Down Expand Up @@ -57,10 +63,16 @@ func (tcp *transactionCostProcessor) ResolveCostRequest(tx *data.Transaction) (*

shouldReturn := len(tcp.responses) == 1 || (len(tcp.responses) == 2 && senderShardID != receiverShardID)
if shouldReturn {
return res, nil
return tcp.extractCorrectResponse(tx.Sender, res), nil
}

for _, currentRes := range tcp.responses {
hasUnsupportedOperations := doEventsContainTopic(&currentRes.Data, tooMuchGasProvidedMessage) || hasSCRWithRefundForSender(tx.Sender, &currentRes.Data)
shouldReturn = hasUnsupportedOperations && !tcp.hasExecutedSCR
if shouldReturn {
return &currentRes.Data, nil
}

if currentRes.Data.RetMessage == "" {
continue
}
Expand Down Expand Up @@ -180,10 +192,12 @@ func (tcp *transactionCostProcessor) processScResult(
return nil, err
}

// TODO check if this condition is enough
ignoreSCRWithESDTTransferNoSCCall := scr.Function == "" && len(scr.Tokens) > 0

shouldIgnoreSCR := receiverShardID == scrReceiverShardID
shouldIgnoreSCR = shouldIgnoreSCR || (scrReceiverShardID == senderShardID && scr.CallType == vm.DirectCall)
shouldIgnoreSCR = shouldIgnoreSCR || scrSenderShardID == core.MetachainShardId
shouldIgnoreSCR = shouldIgnoreSCR || ignoreSCRWithESDTTransferNoSCCall
if shouldIgnoreSCR {
return nil, nil
}
Expand All @@ -201,5 +215,51 @@ func (tcp *transactionCostProcessor) processScResult(
return nil, err
}

tcp.hasExecutedSCR = true

return res, nil
}

func (tcp *transactionCostProcessor) extractCorrectResponse(txSender string, currentRes *data.TxCostResponseData) *data.TxCostResponseData {
if len(tcp.responses) == 1 {
return currentRes
}

for _, res := range tcp.responses {
if doEventsContainTopic(&res.Data, tooMuchGasProvidedMessage) || hasSCRWithRefundForSender(txSender, &res.Data) {
return &res.Data
}
}

return currentRes
}

func doEventsContainTopic(res *data.TxCostResponseData, providedTopic string) bool {
if res.Logs == nil {
return false
}

for _, event := range res.Logs.Events {
if event.Identifier != core.WriteLogIdentifier {
continue
}

for _, topic := range event.Topics {
if bytes.Contains(topic, []byte(providedTopic)) {
return true
}
}
}

return false
}

func hasSCRWithRefundForSender(txSender string, res *data.TxCostResponseData) bool {
for _, scr := range res.ScResults {
if scr.IsRefund && scr.RcvAddr == txSender {
return true
}
}

return false
}
3 changes: 2 additions & 1 deletion process/txcost/transactionCostProcessor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ func TestTransactionCostProcessor_RezolveCostRequestWith3LevelsOfAsyncCalls(t *t
Receiver: rcvTx,
}

expectedGas := uint64(14000)
res, err := newTxCostProcessor.ResolveCostRequest(tx)
require.Nil(t, err)
require.NotNil(t, res)
require.Equal(t, uint64(14000), res.TxCost)
require.Equal(t, expectedGas, res.TxCost)
}

0 comments on commit 26fc411

Please sign in to comment.