From e66a20a8bf2fc5b126b763f8757a0e39adccca3b Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 14 Jan 2025 12:57:04 +0200 Subject: [PATCH] fixed the computed fee for outport for relayed v3 --- .../transactionAPI/gasUsedAndFeeProcessor.go | 8 +- .../transactionsfee/transactionChecker.go | 17 +++- .../transactionsFeeProcessor.go | 19 +++-- .../transactionsFeeProcessor_test.go | 77 +++++++++++++++++++ 4 files changed, 108 insertions(+), 13 deletions(-) diff --git a/node/external/transactionAPI/gasUsedAndFeeProcessor.go b/node/external/transactionAPI/gasUsedAndFeeProcessor.go index c5aa49e05c1..1e50b551d14 100644 --- a/node/external/transactionAPI/gasUsedAndFeeProcessor.go +++ b/node/external/transactionAPI/gasUsedAndFeeProcessor.go @@ -58,9 +58,7 @@ func (gfp *gasUsedAndFeeProcessor) computeAndAttachGasUsedAndFee(tx *transaction tx.GasUsed = big.NewInt(0).Div(initialTotalFee, big.NewInt(0).SetUint64(tx.GasPrice)).Uint64() } - hasValidRelayer := len(tx.RelayerAddress) == len(tx.Sender) && len(tx.RelayerAddress) > 0 - hasValidRelayerSignature := len(tx.RelayerSignature) == len(tx.Signature) && len(tx.RelayerSignature) > 0 - isRelayedV3 := hasValidRelayer && hasValidRelayerSignature + isRelayedV3 := common.IsValidRelayedTxV3(tx.Tx) hasRefundForSender := false for _, scr := range tx.SmartContractResults { if !scr.IsRefund { @@ -86,9 +84,7 @@ func (gfp *gasUsedAndFeeProcessor) getFeeOfRelayedV1V2(tx *transaction.ApiTransa return nil, nil, false } - hasValidRelayer := len(tx.RelayerAddress) == len(tx.Sender) && len(tx.RelayerAddress) > 0 - hasValidRelayerSignature := len(tx.RelayerSignature) == len(tx.Signature) && len(tx.RelayerSignature) > 0 - isRelayedV3 := hasValidRelayer && hasValidRelayerSignature + isRelayedV3 := common.IsValidRelayedTxV3(tx.Tx) if isRelayedV3 { return nil, nil, false } diff --git a/outport/process/transactionsfee/transactionChecker.go b/outport/process/transactionsfee/transactionChecker.go index 546fdd9f432..28c2658a9a4 100644 --- a/outport/process/transactionsfee/transactionChecker.go +++ b/outport/process/transactionsfee/transactionChecker.go @@ -9,6 +9,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/smartContractResult" + "github.com/multiversx/mx-chain-go/common" vmcommon "github.com/multiversx/mx-chain-vm-common-go" ) @@ -47,11 +48,25 @@ func isSCRForSenderWithRefund(scr *smartContractResult.SmartContractResult, txHa } func isRefundForRelayed(dbScResult *smartContractResult.SmartContractResult, tx data.TransactionHandler) bool { + isRelayedV3 := common.IsRelayedTxV3(tx) isForRelayed := string(dbScResult.ReturnMessage) == core.GasRefundForRelayerMessage isForSender := bytes.Equal(dbScResult.RcvAddr, tx.GetSndAddr()) + isForRelayerV3 := isForRelayerOfV3(dbScResult, tx) differentHash := !bytes.Equal(dbScResult.OriginalTxHash, dbScResult.PrevTxHash) - return isForRelayed && isForSender && differentHash + isRefundForRelayedV1V2 := isForRelayed && isForSender && differentHash && !isRelayedV3 + isRefundForRelayedV3 := isForRelayed && isForRelayerV3 && isRelayedV3 + + return isRefundForRelayedV1V2 || isRefundForRelayedV3 +} + +func isForRelayerOfV3(scr *smartContractResult.SmartContractResult, tx data.TransactionHandler) bool { + relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler) + if !isRelayedV3 { + return false + } + + return bytes.Equal(relayedTx.GetRelayerAddr(), scr.RcvAddr) } func isDataOk(data []byte) bool { diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index 1d184f28152..e7aeece280e 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -136,13 +136,12 @@ func (tep *transactionsFeeProcessor) prepareNormalTxs(transactionsAndScrs *trans feeInfo.SetFee(initialPaidFee) } - userTx, totalFee, isRelayed := tep.getFeeOfRelayed(txWithResult) - isRelayedAfterFix := isRelayed && isFeeFixActive + userTx, totalFee, isRelayedV1V2 := tep.getFeeOfRelayedV1V2(txWithResult) + isRelayedAfterFix := isRelayedV1V2 && isFeeFixActive if isRelayedAfterFix { feeInfo.SetFee(totalFee) feeInfo.SetInitialPaidFee(totalFee) feeInfo.SetGasUsed(big.NewInt(0).Div(totalFee, big.NewInt(0).SetUint64(txHandler.GetGasPrice())).Uint64()) - } tep.prepareTxWithResults(txHashHex, txWithResult, userTx, epoch) @@ -172,7 +171,11 @@ func (tep *transactionsFeeProcessor) prepareTxWithResults( tep.prepareTxWithResultsBasedOnLogs(txHashHex, txWithResults, userTx, hasRefund, epoch) } -func (tep *transactionsFeeProcessor) getFeeOfRelayed(tx *transactionWithResults) (data.TransactionHandler, *big.Int, bool) { +func (tep *transactionsFeeProcessor) getFeeOfRelayedV1V2(tx *transactionWithResults) (data.TransactionHandler, *big.Int, bool) { + if common.IsValidRelayedTxV3(tx.GetTxHandler()) { + return nil, nil, false + } + if len(tx.GetTxHandler().GetData()) == 0 { return nil, nil, false } @@ -272,7 +275,7 @@ func (tep *transactionsFeeProcessor) setGasUsedAndFeeBasedOnRefundValue( epoch uint32, ) { isValidUserTxAfterBaseCostActivation := !check.IfNil(userTx) && tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) - if isValidUserTxAfterBaseCostActivation && !common.IsRelayedTxV3(txWithResults.GetTxHandler()) { + if isValidUserTxAfterBaseCostActivation && !common.IsValidRelayedTxV3(txWithResults.GetTxHandler()) { gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(userTx, refund) tx := txWithResults.GetTxHandler() @@ -312,8 +315,12 @@ func (tep *transactionsFeeProcessor) prepareScrsNoTx(transactionsAndScrs *transa continue } + isRelayedV3 := common.IsValidRelayedTxV3(txFromStorage) isForInitialTxSender := bytes.Equal(scr.RcvAddr, txFromStorage.SndAddr) - if !isForInitialTxSender { + isForRelayerV3 := bytes.Equal(scr.RcvAddr, txFromStorage.RelayerAddr) + shouldSkipRelayedV3 := isRelayedV3 && !isForRelayerV3 + shouldSkipTx := !isRelayedV3 && !isForInitialTxSender || shouldSkipRelayedV3 + if shouldSkipTx { continue } diff --git a/outport/process/transactionsfee/transactionsFeeProcessor_test.go b/outport/process/transactionsfee/transactionsFeeProcessor_test.go index 6f0e0f94c35..9e2d45e6b30 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor_test.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor_test.go @@ -10,10 +10,13 @@ import ( outportcore "github.com/multiversx/mx-chain-core-go/data/outport" "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/outport/mock" "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/process/economics" "github.com/multiversx/mx-chain-go/testscommon" "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" + "github.com/multiversx/mx-chain-go/testscommon/epochNotifier" "github.com/multiversx/mx-chain-go/testscommon/genericMocks" "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" logger "github.com/multiversx/mx-chain-logger-go" @@ -22,6 +25,18 @@ import ( var pubKeyConverter, _ = pubkeyConverter.NewBech32PubkeyConverter(32, "erd") +func createEconomicsData(enableEpochsHandler common.EnableEpochsHandler) process.EconomicsDataHandler { + economicsConfig := testscommon.GetEconomicsConfig() + economicsData, _ := economics.NewEconomicsData(economics.ArgsNewEconomicsData{ + Economics: &economicsConfig, + EnableEpochsHandler: enableEpochsHandler, + TxVersionChecker: &testscommon.TxVersionCheckerStub{}, + EpochNotifier: &epochNotifier.EpochNotifierStub{}, + }) + + return economicsData +} + func prepareMockArg() ArgTransactionsFeeProcessor { return ArgTransactionsFeeProcessor{ Marshaller: marshallerMock.MarshalizerMock{}, @@ -597,3 +612,65 @@ func TestMoveBalanceWithSignalError(t *testing.T) { require.Nil(t, err) require.Equal(t, uint64(225_500), initialTx.GetFeeInfo().GetGasUsed()) } + +func TestPutFeeAndGasUsedRelayedTxV3(t *testing.T) { + t.Parallel() + + txHash := []byte("relayedTxV3") + scrWithRefund := []byte("scrWithRefund") + refundValueBig, _ := big.NewInt(0).SetString("37105580000000", 10) + initialTx := &outportcore.TxInfo{ + Transaction: &transaction.Transaction{ + Nonce: 9, + SndAddr: []byte("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"), + RcvAddr: []byte("erd1qqqqqqqqqqqqqpgq2nfn5uxjjkjlrzad3jrak8p3p30v79pseddsm73zpw"), + RelayerAddr: []byte("erd1at9keal0jfhamc67ulq4csmchh33eek87yf5hhzcvlw8e5qlx8zq5hjwjl"), + GasLimit: 5000000, + GasPrice: 1000000000, + Data: []byte("add@01"), + Value: big.NewInt(0), + }, + FeeInfo: &outportcore.FeeInfo{Fee: big.NewInt(0)}, + } + + pool := &outportcore.TransactionPool{ + Transactions: map[string]*outportcore.TxInfo{ + hex.EncodeToString(txHash): initialTx, + }, + SmartContractResults: map[string]*outportcore.SCRInfo{ + hex.EncodeToString(scrWithRefund): { + SmartContractResult: &smartContractResult.SmartContractResult{ + Nonce: 10, + GasPrice: 1000000000, + GasLimit: 0, + Value: refundValueBig, + SndAddr: []byte("erd1qqqqqqqqqqqqqpgq2nfn5uxjjkjlrzad3jrak8p3p30v79pseddsm73zpw"), + RcvAddr: []byte("erd1at9keal0jfhamc67ulq4csmchh33eek87yf5hhzcvlw8e5qlx8zq5hjwjl"), + Data: []byte(""), + PrevTxHash: txHash, + OriginalTxHash: txHash, + ReturnMessage: []byte("gas refund for relayer"), + }, + FeeInfo: &outportcore.FeeInfo{ + Fee: big.NewInt(0), + }, + }, + }, + } + + arg := prepareMockArg() + arg.TxFeeCalculator = createEconomicsData(&enableEpochsHandlerMock.EnableEpochsHandlerStub{ + IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { + return true + }, + }) + txsFeeProc, err := NewTransactionsFeeProcessor(arg) + require.NotNil(t, txsFeeProc) + require.Nil(t, err) + + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) + require.Nil(t, err) + require.Equal(t, big.NewInt(120804420000000), initialTx.GetFeeInfo().GetFee()) + require.Equal(t, uint64(1289442), initialTx.GetFeeInfo().GetGasUsed()) + require.Equal(t, "157910000000000", initialTx.GetFeeInfo().GetInitialPaidFee().String()) +}