diff --git a/factory/api/apiResolverFactory.go b/factory/api/apiResolverFactory.go index dfefa56ff94..399ee4b1533 100644 --- a/factory/api/apiResolverFactory.go +++ b/factory/api/apiResolverFactory.go @@ -244,6 +244,8 @@ func CreateApiResolver(args *ApiResolverArgs) (facade.ApiResolver, error) { TxTypeHandler: txTypeHandler, LogsFacade: logsFacade, DataFieldParser: dataFieldParser, + TxMarshaller: args.CoreComponents.TxMarshalizer(), + EnableEpochsHandler: args.CoreComponents.EnableEpochsHandler(), } apiTransactionProcessor, err := transactionAPI.NewAPITransactionProcessor(argsAPITransactionProc) if err != nil { diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index 8b5a5b9e525..97a815549c3 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -30,6 +30,7 @@ const ( minGasLimit = 50_000 guardAccountCost = 250_000 extraGasLimitForGuarded = minGasLimit + gasPerDataByte = 1_500 txVersion = 2 mockTxSignature = "sig" maxNumOfBlocksToGenerateWhenExecutingTx = 10 @@ -177,16 +178,7 @@ func TestRelayedTransactionInMultiShardEnvironmentWithChainSimulatorScCalls(t *t require.Nil(t, err) ownerNonce := uint64(0) - scCode := wasm.GetSCCode("testData/adder.wasm") - params := []string{scCode, wasm.VMTypeHex, wasm.DummyCodeMetadataHex, "00"} - txDataDeploy := strings.Join(params, "@") - deployTx := generateTransaction(owner.Bytes, ownerNonce, make([]byte, 32), big.NewInt(0), txDataDeploy, 100000000) - - result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(deployTx, maxNumOfBlocksToGenerateWhenExecutingTx) - require.NoError(t, err) - - scAddress := result.Logs.Events[0].Address - scAddressBytes, _ := pkConv.Decode(scAddress) + scAddressBytes := deployAdder(t, cs, owner, ownerNonce) scShard := shardC.ComputeId(scAddressBytes) scShardNodeHandler := cs.GetNodeHandler(scShard) @@ -235,7 +227,7 @@ func TestRelayedTransactionInMultiShardEnvironmentWithChainSimulatorScCalls(t *t relayedTx := generateTransaction(relayer.Bytes, 0, relayer.Bytes, big.NewInt(0), "", relayedTxGasLimit) relayedTx.InnerTransactions = innerTxs - result, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) require.NoError(t, err) checkSum(t, scShardNodeHandler, scAddressBytes, owner.Bytes, 4) @@ -365,8 +357,6 @@ func testFixRelayedMoveBalanceWithChainSimulatorScCall( cs := startChainSimulator(t, alterConfigsFunc) defer cs.Close() - pkConv := cs.GetNodeHandler(0).GetCoreComponents().AddressPubKeyConverter() - initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) relayer, err := cs.GenerateAndMintWalletAddress(0, initialBalance) require.NoError(t, err) @@ -379,16 +369,8 @@ func testFixRelayedMoveBalanceWithChainSimulatorScCall( err = cs.GenerateBlocks(1) require.NoError(t, err) - scCode := wasm.GetSCCode("testData/adder.wasm") - params := []string{scCode, wasm.VMTypeHex, wasm.DummyCodeMetadataHex, "00"} - txDataDeploy := strings.Join(params, "@") - deployTx := generateTransaction(owner.Bytes, 0, make([]byte, 32), big.NewInt(0), txDataDeploy, 100000000) - - result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(deployTx, maxNumOfBlocksToGenerateWhenExecutingTx) - require.NoError(t, err) - - scAddress := result.Logs.Events[0].Address - scAddressBytes, _ := pkConv.Decode(scAddress) + ownerNonce := uint64(0) + scAddressBytes := deployAdder(t, cs, owner, ownerNonce) // fast-forward until epoch 4 err = cs.GenerateBlocksUntilEpochIsReached(int32(4)) @@ -651,6 +633,67 @@ func TestRelayedTransactionInMultiShardEnvironmentWithChainSimulatorInnerNotExec checkBalance(t, cs, receiver, oneEGLD) } +func TestRelayedTransactionFeeField(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + cs := startChainSimulator(t, func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.RelayedTransactionsEnableEpoch = 1 + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV2EnableEpoch = 1 + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = 1 + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = 1 + }) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + receiver, err := cs.GenerateAndMintWalletAddress(0, big.NewInt(0)) + require.NoError(t, err) + + err = cs.GenerateBlocks(1) + require.Nil(t, err) + + t.Run("relayed v1", func(t *testing.T) { + innerTx := generateTransaction(sender.Bytes, 0, receiver.Bytes, oneEGLD, "", minGasLimit) + buff, err := json.Marshal(innerTx) + require.NoError(t, err) + + txData := []byte("relayedTx@" + hex.EncodeToString(buff)) + gasLimit := minGasLimit + len(txData)*gasPerDataByte + int(innerTx.GasLimit) + relayedTx := generateTransaction(relayer.Bytes, 0, sender.Bytes, big.NewInt(0), string(txData), uint64(gasLimit)) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + expectedFee := core.SafeMul(uint64(gasLimit), minGasPrice) + require.Equal(t, expectedFee.String(), result.Fee) + require.Equal(t, expectedFee.String(), result.InitiallyPaidFee) + require.Equal(t, uint64(gasLimit), result.GasUsed) + }) + t.Run("relayed v3", func(t *testing.T) { + innerTx := generateTransaction(sender.Bytes, 1, receiver.Bytes, oneEGLD, "", minGasLimit) + innerTx.RelayerAddr = relayer.Bytes + + gasLimit := minGasLimit + int(innerTx.GasLimit) + relayedTx := generateTransaction(relayer.Bytes, 1, relayer.Bytes, big.NewInt(0), "", uint64(gasLimit)) + relayedTx.InnerTransactions = []*transaction.Transaction{innerTx} + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + expectedFee := core.SafeMul(uint64(gasLimit), minGasPrice) + require.Equal(t, expectedFee.String(), result.Fee) + require.Equal(t, expectedFee.String(), result.InitiallyPaidFee) + require.Equal(t, uint64(gasLimit), result.GasUsed) + }) +} + func startChainSimulator( t *testing.T, alterConfigsFunction func(cfg *config.Configs), @@ -775,3 +818,28 @@ func checkBalance( balance := getBalance(t, cs, address) require.Equal(t, expectedBalance.String(), balance.String()) } + +func deployAdder( + t *testing.T, + cs testsChainSimulator.ChainSimulator, + owner dtos.WalletAddress, + ownerNonce uint64, +) []byte { + pkConv := cs.GetNodeHandler(0).GetCoreComponents().AddressPubKeyConverter() + + err := cs.GenerateBlocks(1) + require.Nil(t, err) + + scCode := wasm.GetSCCode("testData/adder.wasm") + params := []string{scCode, wasm.VMTypeHex, wasm.DummyCodeMetadataHex, "00"} + txDataDeploy := strings.Join(params, "@") + deployTx := generateTransaction(owner.Bytes, ownerNonce, make([]byte, 32), big.NewInt(0), txDataDeploy, 100000000) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(deployTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + scAddress := result.Logs.Events[0].Address + scAddressBytes, _ := pkConv.Decode(scAddress) + + return scAddressBytes +} diff --git a/integrationTests/testProcessorNodeWithTestWebServer.go b/integrationTests/testProcessorNodeWithTestWebServer.go index b380a643660..d533f4c75b1 100644 --- a/integrationTests/testProcessorNodeWithTestWebServer.go +++ b/integrationTests/testProcessorNodeWithTestWebServer.go @@ -24,6 +24,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon" "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/genesisMocks" + "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" "github.com/multiversx/mx-chain-go/testscommon/state" "github.com/multiversx/mx-chain-go/vm/systemSmartContracts/defaults" "github.com/multiversx/mx-chain-vm-common-go/parsers" @@ -236,6 +237,8 @@ func createFacadeComponents(tpn *TestProcessorNode) nodeFacade.ApiResolver { TxTypeHandler: txTypeHandler, LogsFacade: logsFacade, DataFieldParser: dataFieldParser, + TxMarshaller: &marshallerMock.MarshalizerMock{}, + EnableEpochsHandler: tpn.EnableEpochsHandler, } apiTransactionHandler, err := transactionAPI.NewAPITransactionProcessor(argsApiTransactionProc) log.LogIfError(err) diff --git a/node/external/transactionAPI/apiTransactionArgs.go b/node/external/transactionAPI/apiTransactionArgs.go index bb1aa10a659..1e4099390fd 100644 --- a/node/external/transactionAPI/apiTransactionArgs.go +++ b/node/external/transactionAPI/apiTransactionArgs.go @@ -6,6 +6,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data/typeConverters" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/dblookupext" "github.com/multiversx/mx-chain-go/process" @@ -27,4 +28,6 @@ type ArgAPITransactionProcessor struct { TxTypeHandler process.TxTypeHandler LogsFacade LogsFacade DataFieldParser DataFieldParser + TxMarshaller marshal.Marshalizer + EnableEpochsHandler common.EnableEpochsHandler } diff --git a/node/external/transactionAPI/apiTransactionProcessor.go b/node/external/transactionAPI/apiTransactionProcessor.go index c87cbea5d9e..c4e75bc29b9 100644 --- a/node/external/transactionAPI/apiTransactionProcessor.go +++ b/node/external/transactionAPI/apiTransactionProcessor.go @@ -20,6 +20,7 @@ import ( "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/dblookupext" "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/process/smartContract" "github.com/multiversx/mx-chain-go/process/txstatus" "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/storage/txcache" @@ -44,6 +45,7 @@ type apiTransactionProcessor struct { transactionResultsProcessor *apiTransactionResultsProcessor refundDetector *refundDetector gasUsedAndFeeProcessor *gasUsedAndFeeProcessor + enableEpochsHandler common.EnableEpochsHandler } // NewAPITransactionProcessor will create a new instance of apiTransactionProcessor @@ -66,7 +68,13 @@ func NewAPITransactionProcessor(args *ArgAPITransactionProcessor) (*apiTransacti ) refundDetectorInstance := NewRefundDetector() - gasUsedAndFeeProc := newGasUsedAndFeeProcessor(args.FeeComputer, args.AddressPubKeyConverter) + gasUsedAndFeeProc := newGasUsedAndFeeProcessor( + args.FeeComputer, + args.AddressPubKeyConverter, + smartContract.NewArgumentParser(), + args.TxMarshaller, + args.EnableEpochsHandler, + ) return &apiTransactionProcessor{ roundDuration: args.RoundDuration, @@ -84,6 +92,7 @@ func NewAPITransactionProcessor(args *ArgAPITransactionProcessor) (*apiTransacti transactionResultsProcessor: txResultsProc, refundDetector: refundDetectorInstance, gasUsedAndFeeProcessor: gasUsedAndFeeProc, + enableEpochsHandler: args.EnableEpochsHandler, }, nil } @@ -188,6 +197,13 @@ func (atp *apiTransactionProcessor) populateComputedFieldInitiallyPaidFee(tx *tr fee := atp.feeComputer.ComputeTransactionFee(tx) // For user-initiated transactions, we can assume the fee is always strictly positive (note: BigInt(0) is stringified as ""). tx.InitiallyPaidFee = fee.String() + + isFeeFixActive := atp.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, tx.Epoch) + isRelayedAfterFix := tx.IsRelayed && isFeeFixActive + if isRelayedAfterFix { + fee, _ = atp.gasUsedAndFeeProcessor.getFeeOfRelayed(tx) + tx.InitiallyPaidFee = fee.String() + } } func (atp *apiTransactionProcessor) populateComputedFieldIsRefund(tx *transaction.ApiTransactionResult) { diff --git a/node/external/transactionAPI/apiTransactionProcessor_test.go b/node/external/transactionAPI/apiTransactionProcessor_test.go index 3101cf763f4..e6a7040fe87 100644 --- a/node/external/transactionAPI/apiTransactionProcessor_test.go +++ b/node/external/transactionAPI/apiTransactionProcessor_test.go @@ -32,7 +32,9 @@ import ( "github.com/multiversx/mx-chain-go/testscommon" dataRetrieverMock "github.com/multiversx/mx-chain-go/testscommon/dataRetriever" dblookupextMock "github.com/multiversx/mx-chain-go/testscommon/dblookupext" + "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/genericMocks" + "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" storageStubs "github.com/multiversx/mx-chain-go/testscommon/storage" "github.com/multiversx/mx-chain-go/testscommon/txcachemocks" datafield "github.com/multiversx/mx-chain-vm-common-go/parsers/dataField" @@ -59,6 +61,8 @@ func createMockArgAPITransactionProcessor() *ArgAPITransactionProcessor { return &datafield.ResponseParseData{} }, }, + TxMarshaller: &marshallerMock.MarshalizerMock{}, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), } } @@ -181,6 +185,24 @@ func TestNewAPITransactionProcessor(t *testing.T) { _, err := NewAPITransactionProcessor(arguments) require.Equal(t, ErrNilDataFieldParser, err) }) + t.Run("NilTxMarshaller", func(t *testing.T) { + t.Parallel() + + arguments := createMockArgAPITransactionProcessor() + arguments.TxMarshaller = nil + + _, err := NewAPITransactionProcessor(arguments) + require.True(t, strings.Contains(err.Error(), process.ErrNilMarshalizer.Error())) + }) + t.Run("NilEnableEpochsHandler", func(t *testing.T) { + t.Parallel() + + arguments := createMockArgAPITransactionProcessor() + arguments.EnableEpochsHandler = nil + + _, err := NewAPITransactionProcessor(arguments) + require.Equal(t, process.ErrNilEnableEpochsHandler, err) + }) } func TestNode_GetTransactionInvalidHashShouldErr(t *testing.T) { @@ -338,6 +360,8 @@ func TestNode_GetSCRs(t *testing.T) { return &datafield.ResponseParseData{} }, }, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), + TxMarshaller: &mock.MarshalizerFake{}, } apiTransactionProc, _ := NewAPITransactionProcessor(args) @@ -546,6 +570,8 @@ func TestNode_GetTransactionWithResultsFromStorage(t *testing.T) { return &datafield.ResponseParseData{} }, }, + TxMarshaller: &marshallerMock.MarshalizerMock{}, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), } apiTransactionProc, _ := NewAPITransactionProcessor(args) @@ -1114,6 +1140,8 @@ func createAPITransactionProc(t *testing.T, epoch uint32, withDbLookupExt bool) TxTypeHandler: &testscommon.TxTypeHandlerMock{}, LogsFacade: &testscommon.LogsFacadeStub{}, DataFieldParser: dataFieldParser, + TxMarshaller: &marshallerMock.MarshalizerMock{}, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), } apiTransactionProc, err := NewAPITransactionProcessor(args) require.Nil(t, err) diff --git a/node/external/transactionAPI/check.go b/node/external/transactionAPI/check.go index 0959ba6c5db..012aae77618 100644 --- a/node/external/transactionAPI/check.go +++ b/node/external/transactionAPI/check.go @@ -1,6 +1,8 @@ package transactionAPI import ( + "fmt" + "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-go/process" ) @@ -42,6 +44,12 @@ func checkNilArgs(arg *ArgAPITransactionProcessor) error { if check.IfNilReflect(arg.DataFieldParser) { return ErrNilDataFieldParser } + if check.IfNil(arg.TxMarshaller) { + return fmt.Errorf("%w for tx marshaller", process.ErrNilMarshalizer) + } + if check.IfNil(arg.EnableEpochsHandler) { + return process.ErrNilEnableEpochsHandler + } return nil } diff --git a/node/external/transactionAPI/gasUsedAndFeeProcessor.go b/node/external/transactionAPI/gasUsedAndFeeProcessor.go index f0036bc136b..8951149c983 100644 --- a/node/external/transactionAPI/gasUsedAndFeeProcessor.go +++ b/node/external/transactionAPI/gasUsedAndFeeProcessor.go @@ -5,18 +5,33 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/common" + "github.com/multiversx/mx-chain-go/process" datafield "github.com/multiversx/mx-chain-vm-common-go/parsers/dataField" ) type gasUsedAndFeeProcessor struct { - feeComputer feeComputer - pubKeyConverter core.PubkeyConverter + feeComputer feeComputer + pubKeyConverter core.PubkeyConverter + argsParser process.ArgumentsParser + marshaller marshal.Marshalizer + enableEpochsHandler common.EnableEpochsHandler } -func newGasUsedAndFeeProcessor(txFeeCalculator feeComputer, pubKeyConverter core.PubkeyConverter) *gasUsedAndFeeProcessor { +func newGasUsedAndFeeProcessor( + txFeeCalculator feeComputer, + pubKeyConverter core.PubkeyConverter, + argsParser process.ArgumentsParser, + marshaller marshal.Marshalizer, + enableEpochsHandler common.EnableEpochsHandler, +) *gasUsedAndFeeProcessor { return &gasUsedAndFeeProcessor{ - feeComputer: txFeeCalculator, - pubKeyConverter: pubKeyConverter, + feeComputer: txFeeCalculator, + pubKeyConverter: pubKeyConverter, + argsParser: argsParser, + marshaller: marshaller, + enableEpochsHandler: enableEpochsHandler, } } @@ -27,11 +42,22 @@ func (gfp *gasUsedAndFeeProcessor) computeAndAttachGasUsedAndFee(tx *transaction tx.GasUsed = gasUsed tx.Fee = fee.String() - if tx.IsRelayed || gfp.isESDTOperationWithSCCall(tx) { + isFeeFixActive := gfp.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, tx.Epoch) + isRelayedBeforeFix := tx.IsRelayed && !isFeeFixActive + if isRelayedBeforeFix || gfp.isESDTOperationWithSCCall(tx) { tx.GasUsed = tx.GasLimit tx.Fee = tx.InitiallyPaidFee } + if tx.IsRelayed && isFeeFixActive { + totalFee, isRelayed := gfp.getFeeOfRelayed(tx) + if isRelayed { + tx.Fee = totalFee.String() + tx.InitiallyPaidFee = totalFee.String() + tx.GasUsed = big.NewInt(0).Div(totalFee, big.NewInt(0).SetUint64(tx.GasPrice)).Uint64() + } + } + hasRefundForSender := false for _, scr := range tx.SmartContractResults { if !scr.IsRefund || scr.RcvAddr != tx.Sender { @@ -49,6 +75,77 @@ func (gfp *gasUsedAndFeeProcessor) computeAndAttachGasUsedAndFee(tx *transaction gfp.prepareTxWithResultsBasedOnLogs(tx, hasRefundForSender) } +func (gfp *gasUsedAndFeeProcessor) getFeeOfRelayed(tx *transaction.ApiTransactionResult) (*big.Int, bool) { + if !tx.IsRelayed { + return nil, false + } + + if len(tx.InnerTransactions) > 0 { + return gfp.feeComputer.ComputeTransactionFee(tx), true + } + + if len(tx.Data) == 0 { + return nil, false + } + + funcName, args, err := gfp.argsParser.ParseCallData(string(tx.Data)) + if err != nil { + return nil, false + } + + if funcName == core.RelayedTransaction { + return gfp.handleRelayedV1(args, tx) + } + + if funcName == core.RelayedTransactionV2 { + return gfp.handleRelayedV2(args, tx) + } + + return nil, false +} + +func (gfp *gasUsedAndFeeProcessor) handleRelayedV1(args [][]byte, tx *transaction.ApiTransactionResult) (*big.Int, bool) { + if len(args) != 1 { + return nil, false + } + + innerTx := &transaction.Transaction{} + err := gfp.marshaller.Unmarshal(innerTx, args[0]) + if err != nil { + return nil, false + } + + gasUsed := gfp.feeComputer.ComputeGasLimit(tx) + fee := gfp.feeComputer.ComputeTxFeeBasedOnGasUsed(tx, gasUsed) + + innerFee := gfp.feeComputer.ComputeTransactionFee(&transaction.ApiTransactionResult{ + Tx: innerTx, + }) + + return big.NewInt(0).Add(fee, innerFee), true +} + +func (gfp *gasUsedAndFeeProcessor) handleRelayedV2(args [][]byte, tx *transaction.ApiTransactionResult) (*big.Int, bool) { + innerTx := &transaction.Transaction{} + innerTx.RcvAddr = args[0] + innerTx.Nonce = big.NewInt(0).SetBytes(args[1]).Uint64() + innerTx.Data = args[2] + innerTx.Signature = args[3] + innerTx.Value = big.NewInt(0) + innerTx.GasPrice = tx.GasPrice + innerTx.GasLimit = tx.GasLimit - gfp.feeComputer.ComputeGasLimit(tx) + innerTx.SndAddr = tx.Tx.GetRcvAddr() + + gasUsed := gfp.feeComputer.ComputeGasLimit(tx) + fee := gfp.feeComputer.ComputeTxFeeBasedOnGasUsed(tx, gasUsed) + + innerFee := gfp.feeComputer.ComputeTransactionFee(&transaction.ApiTransactionResult{ + Tx: innerTx, + }) + + return big.NewInt(0).Add(fee, innerFee), true +} + func (gfp *gasUsedAndFeeProcessor) prepareTxWithResultsBasedOnLogs( tx *transaction.ApiTransactionResult, hasRefund bool, diff --git a/node/external/transactionAPI/gasUsedAndFeeProcessor_test.go b/node/external/transactionAPI/gasUsedAndFeeProcessor_test.go index 99541bfef5d..d5340e7903c 100644 --- a/node/external/transactionAPI/gasUsedAndFeeProcessor_test.go +++ b/node/external/transactionAPI/gasUsedAndFeeProcessor_test.go @@ -38,7 +38,13 @@ func TestComputeTransactionGasUsedAndFeeMoveBalance(t *testing.T) { feeComp, _ := fee.NewFeeComputer(createEconomicsData(&enableEpochsHandlerMock.EnableEpochsHandlerStub{})) computer := fee.NewTestFeeComputer(feeComp) - gasUsedAndFeeProc := newGasUsedAndFeeProcessor(computer, pubKeyConverter) + gasUsedAndFeeProc := newGasUsedAndFeeProcessor( + computer, + pubKeyConverter, + &testscommon.ArgumentParserMock{}, + &testscommon.MarshallerStub{}, + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), + ) sender := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" receiver := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" @@ -68,7 +74,13 @@ func TestComputeTransactionGasUsedAndFeeLogWithError(t *testing.T) { })) computer := fee.NewTestFeeComputer(feeComp) - gasUsedAndFeeProc := newGasUsedAndFeeProcessor(computer, pubKeyConverter) + gasUsedAndFeeProc := newGasUsedAndFeeProcessor( + computer, + pubKeyConverter, + &testscommon.ArgumentParserMock{}, + &testscommon.MarshallerStub{}, + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), + ) sender := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" receiver := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" @@ -111,7 +123,13 @@ func TestComputeTransactionGasUsedAndFeeRelayedTxWithWriteLog(t *testing.T) { })) computer := fee.NewTestFeeComputer(feeComp) - gasUsedAndFeeProc := newGasUsedAndFeeProcessor(computer, pubKeyConverter) + gasUsedAndFeeProc := newGasUsedAndFeeProcessor( + computer, + pubKeyConverter, + &testscommon.ArgumentParserMock{}, + &testscommon.MarshallerStub{}, + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), + ) sender := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" receiver := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" @@ -149,7 +167,13 @@ func TestComputeTransactionGasUsedAndFeeTransactionWithScrWithRefund(t *testing. })) computer := fee.NewTestFeeComputer(feeComp) - gasUsedAndFeeProc := newGasUsedAndFeeProcessor(computer, pubKeyConverter) + gasUsedAndFeeProc := newGasUsedAndFeeProcessor( + computer, + pubKeyConverter, + &testscommon.ArgumentParserMock{}, + &testscommon.MarshallerStub{}, + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), + ) sender := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" receiver := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" @@ -197,7 +221,13 @@ func TestNFTTransferWithScCall(t *testing.T) { computer := fee.NewTestFeeComputer(feeComp) req.Nil(err) - gasUsedAndFeeProc := newGasUsedAndFeeProcessor(computer, pubKeyConverter) + gasUsedAndFeeProc := newGasUsedAndFeeProcessor( + computer, + pubKeyConverter, + &testscommon.ArgumentParserMock{}, + &testscommon.MarshallerStub{}, + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), + ) sender := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" receiver := "erd1wc3uh22g2aved3qeehkz9kzgrjwxhg9mkkxp2ee7jj7ph34p2csq0n2y5x" diff --git a/outport/process/factory/outportDataProviderFactory.go b/outport/process/factory/outportDataProviderFactory.go index 68546df1c50..5bb2c698136 100644 --- a/outport/process/factory/outportDataProviderFactory.go +++ b/outport/process/factory/outportDataProviderFactory.go @@ -11,6 +11,7 @@ import ( "github.com/multiversx/mx-chain-go/outport/process/disabled" "github.com/multiversx/mx-chain-go/outport/process/transactionsfee" processTxs "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/process/smartContract" "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/sharding/nodesCoordinator" "github.com/multiversx/mx-chain-go/state" @@ -60,11 +61,13 @@ func CreateOutportDataProvider(arg ArgOutportDataProviderFactory) (outport.DataP } transactionsFeeProc, err := transactionsfee.NewTransactionsFeeProcessor(transactionsfee.ArgTransactionsFeeProcessor{ - Marshaller: arg.Marshaller, - TransactionsStorer: arg.TransactionsStorer, - ShardCoordinator: arg.ShardCoordinator, - TxFeeCalculator: arg.EconomicsData, - PubKeyConverter: arg.AddressConverter, + Marshaller: arg.Marshaller, + TransactionsStorer: arg.TransactionsStorer, + ShardCoordinator: arg.ShardCoordinator, + TxFeeCalculator: arg.EconomicsData, + PubKeyConverter: arg.AddressConverter, + ArgsParser: smartContract.NewArgumentParser(), + EnableEpochsHandler: arg.EnableEpochsHandler, }) if err != nil { return nil, err diff --git a/outport/process/interface.go b/outport/process/interface.go index 5fcb19020f3..bec97f362b3 100644 --- a/outport/process/interface.go +++ b/outport/process/interface.go @@ -17,7 +17,7 @@ type AlteredAccountsProviderHandler interface { // TransactionsFeeHandler defines the functionality needed for computation of the transaction fee and gas used type TransactionsFeeHandler interface { - PutFeeAndGasUsed(pool *outport.TransactionPool) error + PutFeeAndGasUsed(pool *outport.TransactionPool, epoch uint32) error IsInterfaceNil() bool } diff --git a/outport/process/outportDataProvider.go b/outport/process/outportDataProvider.go index a99e0bc4827..aec1f15df8b 100644 --- a/outport/process/outportDataProvider.go +++ b/outport/process/outportDataProvider.go @@ -100,7 +100,7 @@ func (odp *outportDataProvider) PrepareOutportSaveBlockData(arg ArgPrepareOutpor return nil, err } - err = odp.transactionsFeeProcessor.PutFeeAndGasUsed(pool) + err = odp.transactionsFeeProcessor.PutFeeAndGasUsed(pool, arg.Header.GetEpoch()) if err != nil { return nil, fmt.Errorf("transactionsFeeProcessor.PutFeeAndGasUsed %w", err) } diff --git a/outport/process/outportDataProvider_test.go b/outport/process/outportDataProvider_test.go index c240fe50ab7..ef1422d230a 100644 --- a/outport/process/outportDataProvider_test.go +++ b/outport/process/outportDataProvider_test.go @@ -16,6 +16,7 @@ import ( "github.com/multiversx/mx-chain-go/outport/process/transactionsfee" "github.com/multiversx/mx-chain-go/testscommon" commonMocks "github.com/multiversx/mx-chain-go/testscommon/common" + "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/genericMocks" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" @@ -25,10 +26,12 @@ import ( func createArgOutportDataProvider() ArgOutportDataProvider { txsFeeProc, _ := transactionsfee.NewTransactionsFeeProcessor(transactionsfee.ArgTransactionsFeeProcessor{ - Marshaller: &marshallerMock.MarshalizerMock{}, - TransactionsStorer: &genericMocks.StorerMock{}, - ShardCoordinator: &testscommon.ShardsCoordinatorMock{}, - TxFeeCalculator: &mock.EconomicsHandlerMock{}, + Marshaller: &marshallerMock.MarshalizerMock{}, + TransactionsStorer: &genericMocks.StorerMock{}, + ShardCoordinator: &testscommon.ShardsCoordinatorMock{}, + TxFeeCalculator: &mock.EconomicsHandlerMock{}, + ArgsParser: &testscommon.ArgumentParserMock{}, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), }) return ArgOutportDataProvider{ diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index 6520db7635d..ffad67ee22f 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -8,7 +8,10 @@ import ( "github.com/multiversx/mx-chain-core-go/core/check" 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-core-go/marshal" + "github.com/multiversx/mx-chain-go/common" + "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/storage" logger "github.com/multiversx/mx-chain-logger-go" @@ -19,19 +22,24 @@ const loggerName = "outport/process/transactionsfee" // ArgTransactionsFeeProcessor holds the arguments needed for creating a new instance of transactionsFeeProcessor type ArgTransactionsFeeProcessor struct { - Marshaller marshal.Marshalizer - TransactionsStorer storage.Storer - ShardCoordinator sharding.Coordinator - TxFeeCalculator FeesProcessorHandler - PubKeyConverter core.PubkeyConverter + Marshaller marshal.Marshalizer + TransactionsStorer storage.Storer + ShardCoordinator sharding.Coordinator + TxFeeCalculator FeesProcessorHandler + PubKeyConverter core.PubkeyConverter + ArgsParser process.ArgumentsParser + EnableEpochsHandler common.EnableEpochsHandler } type transactionsFeeProcessor struct { - txGetter transactionGetter - txFeeCalculator FeesProcessorHandler - shardCoordinator sharding.Coordinator - dataFieldParser dataFieldParser - log logger.Logger + txGetter transactionGetter + txFeeCalculator FeesProcessorHandler + shardCoordinator sharding.Coordinator + dataFieldParser dataFieldParser + log logger.Logger + marshaller marshal.Marshalizer + argsParser process.ArgumentsParser + enableEpochsHandler common.EnableEpochsHandler } // NewTransactionsFeeProcessor will create a new instance of transactionsFeeProcessor @@ -50,11 +58,14 @@ func NewTransactionsFeeProcessor(arg ArgTransactionsFeeProcessor) (*transactions } return &transactionsFeeProcessor{ - txFeeCalculator: arg.TxFeeCalculator, - shardCoordinator: arg.ShardCoordinator, - txGetter: newTxGetter(arg.TransactionsStorer, arg.Marshaller), - log: logger.GetOrCreate(loggerName), - dataFieldParser: parser, + txFeeCalculator: arg.TxFeeCalculator, + shardCoordinator: arg.ShardCoordinator, + txGetter: newTxGetter(arg.TransactionsStorer, arg.Marshaller), + log: logger.GetOrCreate(loggerName), + dataFieldParser: parser, + marshaller: arg.Marshaller, + argsParser: arg.ArgsParser, + enableEpochsHandler: arg.EnableEpochsHandler, }, nil } @@ -74,16 +85,22 @@ func checkArg(arg ArgTransactionsFeeProcessor) error { if check.IfNil(arg.PubKeyConverter) { return core.ErrNilPubkeyConverter } + if check.IfNil(arg.ArgsParser) { + return process.ErrNilArgumentParser + } + if check.IfNil(arg.EnableEpochsHandler) { + return process.ErrNilEnableEpochsHandler + } return nil } // PutFeeAndGasUsed will compute and set in transactions pool fee and gas used -func (tep *transactionsFeeProcessor) PutFeeAndGasUsed(pool *outportcore.TransactionPool) error { +func (tep *transactionsFeeProcessor) PutFeeAndGasUsed(pool *outportcore.TransactionPool, epoch uint32) error { tep.prepareInvalidTxs(pool) txsWithResultsMap := prepareTransactionsAndScrs(pool) - tep.prepareNormalTxs(txsWithResultsMap) + tep.prepareNormalTxs(txsWithResultsMap, epoch) return tep.prepareScrsNoTx(txsWithResultsMap) } @@ -97,7 +114,7 @@ func (tep *transactionsFeeProcessor) prepareInvalidTxs(pool *outportcore.Transac } } -func (tep *transactionsFeeProcessor) prepareNormalTxs(transactionsAndScrs *transactionsAndScrsHolder) { +func (tep *transactionsFeeProcessor) prepareNormalTxs(transactionsAndScrs *transactionsAndScrsHolder, epoch uint32) { for txHashHex, txWithResult := range transactionsAndScrs.txsWithResults { txHandler := txWithResult.GetTxHandler() @@ -110,7 +127,10 @@ func (tep *transactionsFeeProcessor) prepareNormalTxs(transactionsAndScrs *trans feeInfo.SetFee(fee) feeInfo.SetInitialPaidFee(initialPaidFee) - if isRelayedTx(txWithResult) || tep.isESDTOperationWithSCCall(txHandler) { + isRelayed := isRelayedTx(txWithResult) + isFeeFixActive := tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) + isRelayedBeforeFix := isRelayed && !isFeeFixActive + if isRelayedBeforeFix || tep.isESDTOperationWithSCCall(txHandler) { feeInfo.SetGasUsed(txWithResult.GetTxHandler().GetGasLimit()) feeInfo.SetFee(initialPaidFee) } @@ -120,6 +140,15 @@ func (tep *transactionsFeeProcessor) prepareNormalTxs(transactionsAndScrs *trans continue } + if isRelayedTx(txWithResult) && isFeeFixActive { + totalFee, isRelayed := tep.getFeeOfRelayed(txWithResult) + if isRelayed { + feeInfo.SetFee(totalFee) + feeInfo.SetInitialPaidFee(totalFee) + feeInfo.SetGasUsed(big.NewInt(0).Div(totalFee, big.NewInt(0).SetUint64(txHandler.GetGasPrice())).Uint64()) + } + } + tep.prepareTxWithResults(txHashHex, txWithResult) } } @@ -146,6 +175,68 @@ func (tep *transactionsFeeProcessor) prepareTxWithResults(txHashHex string, txWi } +func (tep *transactionsFeeProcessor) getFeeOfRelayed(tx *transactionWithResults) (*big.Int, bool) { + if len(tx.GetTxHandler().GetData()) == 0 { + return nil, false + } + + funcName, args, err := tep.argsParser.ParseCallData(string(tx.GetTxHandler().GetData())) + if err != nil { + return nil, false + } + + if funcName == core.RelayedTransaction { + return tep.handleRelayedV1(args, tx) + } + + if funcName == core.RelayedTransactionV2 { + return tep.handleRelayedV2(args, tx) + } + + return nil, false +} + +func (tep *transactionsFeeProcessor) handleRelayedV1(args [][]byte, tx *transactionWithResults) (*big.Int, bool) { + if len(args) != 1 { + return nil, false + } + + innerTx := &transaction.Transaction{} + err := tep.marshaller.Unmarshal(innerTx, args[0]) + if err != nil { + return nil, false + } + + txHandler := tx.GetTxHandler() + gasUsed := tep.txFeeCalculator.ComputeGasLimit(txHandler) + fee := tep.txFeeCalculator.ComputeTxFeeBasedOnGasUsed(txHandler, gasUsed) + + innerFee := tep.txFeeCalculator.ComputeTxFee(innerTx) + + return big.NewInt(0).Add(fee, innerFee), true +} + +func (tep *transactionsFeeProcessor) handleRelayedV2(args [][]byte, tx *transactionWithResults) (*big.Int, bool) { + txHandler := tx.GetTxHandler() + + innerTx := &transaction.Transaction{} + innerTx.RcvAddr = args[0] + innerTx.Nonce = big.NewInt(0).SetBytes(args[1]).Uint64() + innerTx.Data = args[2] + innerTx.Signature = args[3] + innerTx.Value = big.NewInt(0) + innerTx.GasPrice = txHandler.GetGasPrice() + innerTx.GasLimit = txHandler.GetGasLimit() - tep.txFeeCalculator.ComputeGasLimit(txHandler) + innerTx.SndAddr = txHandler.GetRcvAddr() + + gasUsed := tep.txFeeCalculator.ComputeGasLimit(txHandler) + fee := tep.txFeeCalculator.ComputeTxFeeBasedOnGasUsed(txHandler, gasUsed) + + innerFee := tep.txFeeCalculator.ComputeTxFee(innerTx) + + return big.NewInt(0).Add(fee, innerFee), true +} + func (tep *transactionsFeeProcessor) prepareRelayedTxV3WithResults(txHashHex string, txWithResults *transactionWithResults) { refundsValue := big.NewInt(0) for _, scrHandler := range txWithResults.scrs { diff --git a/outport/process/transactionsfee/transactionsFeeProcessor_test.go b/outport/process/transactionsfee/transactionsFeeProcessor_test.go index 8ff4cf14501..6f0e0f94c35 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor_test.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor_test.go @@ -11,7 +11,9 @@ import ( "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/transaction" "github.com/multiversx/mx-chain-go/outport/mock" + "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/testscommon" + "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "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,11 +24,13 @@ var pubKeyConverter, _ = pubkeyConverter.NewBech32PubkeyConverter(32, "erd") func prepareMockArg() ArgTransactionsFeeProcessor { return ArgTransactionsFeeProcessor{ - Marshaller: marshallerMock.MarshalizerMock{}, - TransactionsStorer: genericMocks.NewStorerMock(), - ShardCoordinator: &testscommon.ShardsCoordinatorMock{}, - TxFeeCalculator: &mock.EconomicsHandlerMock{}, - PubKeyConverter: pubKeyConverter, + Marshaller: marshallerMock.MarshalizerMock{}, + TransactionsStorer: genericMocks.NewStorerMock(), + ShardCoordinator: &testscommon.ShardsCoordinatorMock{}, + TxFeeCalculator: &mock.EconomicsHandlerMock{}, + PubKeyConverter: pubKeyConverter, + ArgsParser: &testscommon.ArgumentParserMock{}, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), } } @@ -53,6 +57,16 @@ func TestNewTransactionFeeProcessor(t *testing.T) { _, err = NewTransactionsFeeProcessor(arg) require.Equal(t, ErrNilTransactionFeeCalculator, err) + arg = prepareMockArg() + arg.ArgsParser = nil + _, err = NewTransactionsFeeProcessor(arg) + require.Equal(t, process.ErrNilArgumentParser, err) + + arg = prepareMockArg() + arg.EnableEpochsHandler = nil + _, err = NewTransactionsFeeProcessor(arg) + require.Equal(t, process.ErrNilEnableEpochsHandler, err) + arg = prepareMockArg() txsFeeProc, err := NewTransactionsFeeProcessor(arg) require.NotNil(t, txsFeeProc) @@ -125,7 +139,7 @@ func TestPutFeeAndGasUsedTx1(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, big.NewInt(1673728170000000), initialTx.GetFeeInfo().GetFee()) require.Equal(t, uint64(7982817), initialTx.GetFeeInfo().GetGasUsed()) @@ -175,7 +189,7 @@ func TestPutFeeAndGasUsedScrNoTx(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, big.NewInt(123001460000000), scr.GetFeeInfo().GetFee()) require.Equal(t, uint64(7350146), scr.GetFeeInfo().GetGasUsed()) @@ -203,7 +217,7 @@ func TestPutFeeAndGasUsedInvalidTxs(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, big.NewInt(349500000000000), tx.GetFeeInfo().GetFee()) require.Equal(t, tx.GetTxHandler().GetGasLimit(), tx.GetFeeInfo().GetGasUsed()) @@ -284,7 +298,7 @@ func TestPutFeeAndGasUsedLogWithErrorAndInformative(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, tx1.GetTxHandler().GetGasLimit(), tx1.GetFeeInfo().GetGasUsed()) @@ -335,7 +349,7 @@ func TestPutFeeAndGasUsedWrongRelayedTx(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, big.NewInt(6103405000000000), initialTx.GetFeeInfo().GetFee()) require.Equal(t, uint64(550000000), initialTx.GetFeeInfo().GetGasUsed()) @@ -370,7 +384,7 @@ func TestPutFeeAndGasUsedESDTWithScCall(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, big.NewInt(820765000000000), tx.GetFeeInfo().GetFee()) require.Equal(t, uint64(55_000_000), tx.GetFeeInfo().GetGasUsed()) @@ -425,7 +439,7 @@ func TestPutFeeAndGasUsedScrWithRefundNoTx(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, big.NewInt(0), scr.GetFeeInfo().GetFee()) require.Equal(t, uint64(0), scr.GetFeeInfo().GetGasUsed()) @@ -474,7 +488,7 @@ func TestPutFeeAndGasUsedScrWithRefundNotForInitialSender(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, big.NewInt(0), scr.GetFeeInfo().GetFee()) require.Equal(t, uint64(0), scr.GetFeeInfo().GetGasUsed()) @@ -522,7 +536,7 @@ func TestPutFeeAndGasUsedScrWithRefund(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, big.NewInt(552865000000000), initialTx.GetFeeInfo().GetFee()) require.Equal(t, uint64(50_336_500), initialTx.GetFeeInfo().GetGasUsed()) @@ -579,7 +593,7 @@ func TestMoveBalanceWithSignalError(t *testing.T) { require.NotNil(t, txsFeeProc) require.Nil(t, err) - err = txsFeeProc.PutFeeAndGasUsed(pool) + err = txsFeeProc.PutFeeAndGasUsed(pool, 0) require.Nil(t, err) require.Equal(t, uint64(225_500), initialTx.GetFeeInfo().GetGasUsed()) } diff --git a/testscommon/economicsmocks/economicsDataHandlerStub.go b/testscommon/economicsmocks/economicsDataHandlerStub.go index bb59020bc27..c76ce6c59a2 100644 --- a/testscommon/economicsmocks/economicsDataHandlerStub.go +++ b/testscommon/economicsmocks/economicsDataHandlerStub.go @@ -49,6 +49,7 @@ type EconomicsHandlerStub struct { ComputeTxFeeBasedOnGasUsedInEpochCalled func(tx data.TransactionWithFeeHandler, gasUsed uint64, epoch uint32) *big.Int ComputeRelayedTxFeesCalled func(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) SetTxTypeHandlerCalled func(txTypeHandler process.TxTypeHandler) error + ComputeMoveBalanceFeeInEpochCalled func(tx data.TransactionWithFeeHandler, epoch uint32) *big.Int } // ComputeFeeForProcessing - @@ -228,6 +229,14 @@ func (e *EconomicsHandlerStub) ComputeMoveBalanceFee(tx data.TransactionWithFeeH return big.NewInt(0) } +// ComputeMoveBalanceFeeInEpoch - +func (e *EconomicsHandlerStub) ComputeMoveBalanceFeeInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) *big.Int { + if e.ComputeMoveBalanceFeeInEpochCalled != nil { + return e.ComputeMoveBalanceFeeInEpochCalled(tx, epoch) + } + return big.NewInt(0) +} + // ComputeTxFee - func (e *EconomicsHandlerStub) ComputeTxFee(tx data.TransactionWithFeeHandler) *big.Int { if e.ComputeTxFeeCalled != nil { diff --git a/testscommon/economicsmocks/economicsHandlerMock.go b/testscommon/economicsmocks/economicsHandlerMock.go index 3506d2ba9a7..0c92fff0238 100644 --- a/testscommon/economicsmocks/economicsHandlerMock.go +++ b/testscommon/economicsmocks/economicsHandlerMock.go @@ -27,6 +27,7 @@ type EconomicsHandlerMock struct { ComputeFeeCalled func(tx data.TransactionWithFeeHandler) *big.Int CheckValidityTxValuesCalled func(tx data.TransactionWithFeeHandler) error ComputeMoveBalanceFeeCalled func(tx data.TransactionWithFeeHandler) *big.Int + ComputeMoveBalanceFeeInEpochCalled func(tx data.TransactionWithFeeHandler, epoch uint32) *big.Int ComputeTxFeeCalled func(tx data.TransactionWithFeeHandler) *big.Int DeveloperPercentageCalled func() float64 MinGasPriceCalled func() uint64 @@ -199,7 +200,14 @@ func (ehm *EconomicsHandlerMock) ComputeMoveBalanceFee(tx data.TransactionWithFe return ehm.ComputeMoveBalanceFeeCalled(tx) } return big.NewInt(0) +} +// ComputeMoveBalanceFeeInEpoch - +func (ehm *EconomicsHandlerMock) ComputeMoveBalanceFeeInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) *big.Int { + if ehm.ComputeMoveBalanceFeeInEpochCalled != nil { + return ehm.ComputeMoveBalanceFeeInEpochCalled(tx, epoch) + } + return big.NewInt(0) } // ComputeGasLimitBasedOnBalance - diff --git a/testscommon/feeComputerStub.go b/testscommon/feeComputerStub.go index 33dcfbb4e4b..884351576d9 100644 --- a/testscommon/feeComputerStub.go +++ b/testscommon/feeComputerStub.go @@ -12,6 +12,7 @@ type FeeComputerStub struct { ComputeGasUsedAndFeeBasedOnRefundValueCalled func(tx *transaction.ApiTransactionResult, refundValue *big.Int) (uint64, *big.Int) ComputeTxFeeBasedOnGasUsedCalled func(tx *transaction.ApiTransactionResult, gasUsed uint64) *big.Int ComputeGasLimitCalled func(tx *transaction.ApiTransactionResult) uint64 + ComputeMoveBalanceFeeCalled func(tx *transaction.ApiTransactionResult) *big.Int } // ComputeTransactionFee - @@ -49,6 +50,15 @@ func (stub *FeeComputerStub) ComputeGasLimit(tx *transaction.ApiTransactionResul return 0 } +// ComputeMoveBalanceFee - +func (stub *FeeComputerStub) ComputeMoveBalanceFee(tx *transaction.ApiTransactionResult) *big.Int { + if stub.ComputeMoveBalanceFeeCalled != nil { + return stub.ComputeMoveBalanceFeeCalled(tx) + } + + return big.NewInt(0) +} + // IsInterfaceNil returns true if there is no value under the interface func (stub *FeeComputerStub) IsInterfaceNil() bool { return false