From 57301ae3f6e49f1dbc7aedbce879f5e275468f48 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 29 Oct 2024 16:01:40 +0200 Subject: [PATCH 01/74] new relayed v3 --- api/groups/transactionGroup.go | 32 +- cmd/node/config/enableEpochs.toml | 3 + common/constants.go | 4 + common/enablers/enableEpochsHandler.go | 6 + common/enablers/enableEpochsHandler_test.go | 2 + config/epochConfig.go | 1 + config/tomlConfig_test.go | 4 + go.mod | 2 +- go.sum | 4 +- .../relayedTx/relayedTx_test.go | 548 +++++++++++++++++- .../multiShard/relayedTx/common.go | 57 ++ .../multiShard/relayedTx/relayedTx_test.go | 6 + integrationTests/testProcessorNode.go | 37 +- node/external/dtos.go | 32 +- .../transactionAPI/apiTransactionProcessor.go | 13 +- node/external/transactionAPI/fieldsHandler.go | 2 + .../transactionAPI/gasUsedAndFeeProcessor.go | 29 +- node/external/transactionAPI/unmarshaller.go | 18 +- node/metrics/metrics.go | 1 + node/metrics/metrics_test.go | 2 + node/node.go | 20 + .../transactionsFeeProcessor.go | 10 +- process/constants.go | 4 + process/coordinator/transactionType.go | 10 + process/coordinator/transactionType_test.go | 28 + process/dataValidators/txValidator.go | 38 +- process/dataValidators/txValidator_test.go | 114 +++- process/economics/economicsData.go | 15 +- process/errors.go | 6 + process/transaction/baseProcess.go | 27 +- process/transaction/export_test.go | 2 + process/transaction/interceptedTransaction.go | 60 +- .../interceptedTransaction_test.go | 41 ++ process/transaction/shardProcess.go | 78 ++- process/transaction/shardProcess_test.go | 165 +++++- statusHandler/statusMetricsProvider.go | 1 + statusHandler/statusMetricsProvider_test.go | 2 + 37 files changed, 1299 insertions(+), 125 deletions(-) diff --git a/api/groups/transactionGroup.go b/api/groups/transactionGroup.go index f35969ed701..86f04dfca22 100644 --- a/api/groups/transactionGroup.go +++ b/api/groups/transactionGroup.go @@ -720,21 +720,23 @@ func (tg *transactionGroup) getTransactionsPoolNonceGapsForSender(sender string, func (tg *transactionGroup) createTransaction(receivedTx *transaction.FrontendTransaction) (*transaction.Transaction, []byte, error) { txArgs := &external.ArgsCreateTransaction{ - Nonce: receivedTx.Nonce, - Value: receivedTx.Value, - Receiver: receivedTx.Receiver, - ReceiverUsername: receivedTx.ReceiverUsername, - Sender: receivedTx.Sender, - SenderUsername: receivedTx.SenderUsername, - GasPrice: receivedTx.GasPrice, - GasLimit: receivedTx.GasLimit, - DataField: receivedTx.Data, - SignatureHex: receivedTx.Signature, - ChainID: receivedTx.ChainID, - Version: receivedTx.Version, - Options: receivedTx.Options, - Guardian: receivedTx.GuardianAddr, - GuardianSigHex: receivedTx.GuardianSignature, + Nonce: receivedTx.Nonce, + Value: receivedTx.Value, + Receiver: receivedTx.Receiver, + ReceiverUsername: receivedTx.ReceiverUsername, + Sender: receivedTx.Sender, + SenderUsername: receivedTx.SenderUsername, + GasPrice: receivedTx.GasPrice, + GasLimit: receivedTx.GasLimit, + DataField: receivedTx.Data, + SignatureHex: receivedTx.Signature, + ChainID: receivedTx.ChainID, + Version: receivedTx.Version, + Options: receivedTx.Options, + Guardian: receivedTx.GuardianAddr, + GuardianSigHex: receivedTx.GuardianSignature, + Relayer: receivedTx.RelayerAddr, + RelayerSignatureHex: receivedTx.RelayerSignature, } start := time.Now() tx, txHash, err := tg.getFacade().CreateTransaction(txArgs) diff --git a/cmd/node/config/enableEpochs.toml b/cmd/node/config/enableEpochs.toml index 9ca2083a352..0b45c059ef1 100644 --- a/cmd/node/config/enableEpochs.toml +++ b/cmd/node/config/enableEpochs.toml @@ -333,6 +333,9 @@ # FixRelayedMoveBalanceToNonPayableSCEnableEpoch represents the epoch when the fix for relayed move balance to non payable sc will be enabled FixRelayedMoveBalanceToNonPayableSCEnableEpoch = 4 + # RelayedTransactionsV3 represents the epoch when the relayed transactions v3 will be enabled + RelayedTransactionsV3 = 5 + # BLSMultiSignerEnableEpoch represents the activation epoch for different types of BLS multi-signers BLSMultiSignerEnableEpoch = [ { EnableEpoch = 0, Type = "no-KOSK" }, diff --git a/common/constants.go b/common/constants.go index 2b56d2f388b..67725bdb0b3 100644 --- a/common/constants.go +++ b/common/constants.go @@ -737,6 +737,9 @@ const ( // MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch represents the epoch when the fix for relayed move balance to non-payable sc is enabled MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch = "erd_fix_relayed_move_balance_to_non_payable_sc_enable_epoch" + // MetricRelayedTransactionsV3EnableEpoch represents the epoch when the relayed transactions v3 are enabled + MetricRelayedTransactionsV3EnableEpoch = "erd_relayed_transactions_v3_enable_epoch" + // MetricMaxNodesChangeEnableEpoch holds configuration for changing the maximum number of nodes and the enabling epoch MetricMaxNodesChangeEnableEpoch = "erd_max_nodes_change_enable_epoch" @@ -1234,5 +1237,6 @@ const ( FixRelayedBaseCostFlag core.EnableEpochFlag = "FixRelayedBaseCostFlag" MultiESDTNFTTransferAndExecuteByUserFlag core.EnableEpochFlag = "MultiESDTNFTTransferAndExecuteByUserFlag" FixRelayedMoveBalanceToNonPayableSCFlag core.EnableEpochFlag = "FixRelayedMoveBalanceToNonPayableSCFlag" + RelayedTransactionsV3Flag core.EnableEpochFlag = "RelayedTransactionsV3Flag" // all new flags must be added to createAllFlagsMap method, as part of enableEpochsHandler allFlagsDefined ) diff --git a/common/enablers/enableEpochsHandler.go b/common/enablers/enableEpochsHandler.go index 65cc7762796..cf31b3ab310 100644 --- a/common/enablers/enableEpochsHandler.go +++ b/common/enablers/enableEpochsHandler.go @@ -780,6 +780,12 @@ func (handler *enableEpochsHandler) createAllFlagsMap() { }, activationEpoch: handler.enableEpochsConfig.FixRelayedMoveBalanceToNonPayableSCEnableEpoch, }, + common.RelayedTransactionsV3Flag: { + isActiveInEpoch: func(epoch uint32) bool { + return epoch >= handler.enableEpochsConfig.RelayedTransactionsV3EnableEpoch + }, + activationEpoch: handler.enableEpochsConfig.RelayedTransactionsV3EnableEpoch, + }, } } diff --git a/common/enablers/enableEpochsHandler_test.go b/common/enablers/enableEpochsHandler_test.go index d0f9191055e..a5fce844f1b 100644 --- a/common/enablers/enableEpochsHandler_test.go +++ b/common/enablers/enableEpochsHandler_test.go @@ -123,6 +123,7 @@ func createEnableEpochsConfig() config.EnableEpochs { MultiESDTNFTTransferAndExecuteByUserEnableEpoch: 106, FixRelayedMoveBalanceToNonPayableSCEnableEpoch: 107, UseGasBoundedShouldFailExecutionEnableEpoch: 108, + RelayedTransactionsV3EnableEpoch: 109, } } @@ -448,6 +449,7 @@ func TestEnableEpochsHandler_GetActivationEpoch(t *testing.T) { require.Equal(t, cfg.FixRelayedBaseCostEnableEpoch, handler.GetActivationEpoch(common.FixRelayedBaseCostFlag)) require.Equal(t, cfg.MultiESDTNFTTransferAndExecuteByUserEnableEpoch, handler.GetActivationEpoch(common.MultiESDTNFTTransferAndExecuteByUserFlag)) require.Equal(t, cfg.FixRelayedMoveBalanceToNonPayableSCEnableEpoch, handler.GetActivationEpoch(common.FixRelayedMoveBalanceToNonPayableSCFlag)) + require.Equal(t, cfg.RelayedTransactionsV3EnableEpoch, handler.GetActivationEpoch(common.RelayedTransactionsV3Flag)) } func TestEnableEpochsHandler_IsInterfaceNil(t *testing.T) { diff --git a/config/epochConfig.go b/config/epochConfig.go index a7fd67c680a..9a76744dbf4 100644 --- a/config/epochConfig.go +++ b/config/epochConfig.go @@ -122,6 +122,7 @@ type EnableEpochs struct { FixRelayedBaseCostEnableEpoch uint32 MultiESDTNFTTransferAndExecuteByUserEnableEpoch uint32 FixRelayedMoveBalanceToNonPayableSCEnableEpoch uint32 + RelayedTransactionsV3EnableEpoch uint32 BLSMultiSignerEnableEpoch []MultiSignerConfig } diff --git a/config/tomlConfig_test.go b/config/tomlConfig_test.go index 39a582b1ef2..767e37e3950 100644 --- a/config/tomlConfig_test.go +++ b/config/tomlConfig_test.go @@ -884,6 +884,9 @@ func TestEnableEpochConfig(t *testing.T) { # FixRelayedMoveBalanceToNonPayableSCEnableEpoch represents the epoch when the fix for relayed move balance to non payable sc will be enabled FixRelayedMoveBalanceToNonPayableSCEnableEpoch = 102 + # RelayedTransactionsV3EnableEpoch represents the epoch when the relayed transactions v3 will be enabled + RelayedTransactionsV3EnableEpoch = 103 + # MaxNodesChangeEnableEpoch holds configuration for changing the maximum number of nodes and the enabling epoch MaxNodesChangeEnableEpoch = [ { EpochEnable = 44, MaxNumNodes = 2169, NodesToShufflePerShard = 80 }, @@ -1004,6 +1007,7 @@ func TestEnableEpochConfig(t *testing.T) { FixRelayedBaseCostEnableEpoch: 100, MultiESDTNFTTransferAndExecuteByUserEnableEpoch: 101, FixRelayedMoveBalanceToNonPayableSCEnableEpoch: 102, + RelayedTransactionsV3EnableEpoch: 103, MaxNodesChangeEnableEpoch: []MaxNodesChangeConfig{ { EpochEnable: 44, diff --git a/go.mod b/go.mod index b1eb1aa4ddb..36b4f177b4b 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.0 - github.com/multiversx/mx-chain-core-go v1.2.23-0.20241018134424-75bab2a9058c + github.com/multiversx/mx-chain-core-go v1.2.23-0.20241024081246-bbc08e634e51 github.com/multiversx/mx-chain-crypto-go v1.2.12 github.com/multiversx/mx-chain-es-indexer-go v1.7.10-0.20241018130218-f48c7282690b github.com/multiversx/mx-chain-logger-go v1.0.15 diff --git a/go.sum b/go.sum index 32ad88ef7af..a6dfb332f3c 100644 --- a/go.sum +++ b/go.sum @@ -387,8 +387,8 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.0 h1:J7bX6HoN3HiHY7cUeEjG8AJWgQDDPcY+OPDOsSUOkRE= github.com/multiversx/mx-chain-communication-go v1.1.0/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.23-0.20241018134424-75bab2a9058c h1:hPCfMSj2vd9xNkARNxB1b3b9k8taFb+Xfja+WK97jno= -github.com/multiversx/mx-chain-core-go v1.2.23-0.20241018134424-75bab2a9058c/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.23-0.20241024081246-bbc08e634e51 h1:oQPa+bF311LKiCKWrWcDb8cxNAnz/EcuRIV45rCj6Rg= +github.com/multiversx/mx-chain-core-go v1.2.23-0.20241024081246-bbc08e634e51/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= github.com/multiversx/mx-chain-es-indexer-go v1.7.10-0.20241018130218-f48c7282690b h1:GYvm0yGkdQ3OCfNqnyIQNzAzydN3cES8noJZ3eZHN1A= diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index f7c0f74649b..7021133fddd 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "encoding/json" "math/big" + "strconv" "strings" "testing" "time" @@ -17,6 +18,8 @@ import ( "github.com/multiversx/mx-chain-go/node/chainSimulator/components/api" "github.com/multiversx/mx-chain-go/node/chainSimulator/configs" "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" + chainSimulatorProcess "github.com/multiversx/mx-chain-go/node/chainSimulator/process" + "github.com/multiversx/mx-chain-go/process" "github.com/stretchr/testify/require" ) @@ -25,8 +28,10 @@ const ( minGasPrice = 1_000_000_000 minGasLimit = 50_000 gasPerDataByte = 1_500 + deductionFactor = 100 txVersion = 2 - mockTxSignature = "sig" + mockTxSignature = "ssig" + mockRelayerTxSignature = "rsig" maxNumOfBlocksToGenerateWhenExecutingTx = 10 roundsPerEpoch = 30 ) @@ -35,17 +40,448 @@ var ( oneEGLD = big.NewInt(1000000000000000000) ) +func TestRelayedV3WithChainSimulator(t *testing.T) { + t.Run("successful intra shard move balance with exact gas", testRelayedV3MoveBalance(0, 0, false)) + t.Run("successful intra shard move balance with extra gas", testRelayedV3MoveBalance(0, 0, true)) + t.Run("successful cross shard move balance with exact gas", testRelayedV3MoveBalance(0, 1, false)) + t.Run("successful cross shard move balance with extra gas", testRelayedV3MoveBalance(0, 1, true)) + t.Run("intra shard move balance, lower nonce", testRelayedV3MoveBalanceLowerNonce(0, 0)) + t.Run("cross shard move balance, lower nonce", testRelayedV3MoveBalanceLowerNonce(0, 1)) + t.Run("intra shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 0)) + t.Run("cross shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 1)) + + t.Run("successful intra shard sc call with refunds", testRelayedV3ScCall(0, 0)) + t.Run("successful cross shard sc call with refunds", testRelayedV3ScCall(0, 1)) + t.Run("intra shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 0)) + t.Run("cross shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 1)) + t.Run("intra shard sc call, invalid method", testRelayedV3ScCallInvalidMethod(0, 0)) + t.Run("cross shard sc call, invalid method", testRelayedV3ScCallInvalidMethod(0, 1)) +} + +func testRelayedV3MoveBalance( + relayerShard uint32, + destinationShard uint32, + extraGas bool, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + receiver, err := cs.GenerateAndMintWalletAddress(destinationShard, big.NewInt(0)) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + gasLimit := minGasLimit * 2 + extraGasLimit := 0 + if extraGas { + extraGasLimit = minGasLimit + } + relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, receiver.Bytes, relayer.Bytes, oneEGLD, "", uint64(gasLimit+extraGasLimit)) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // check fee fields + initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, big.NewInt(0), true) + require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) + require.Equal(t, fee.String(), result.Fee) + require.Equal(t, gasUsed, result.GasUsed) + + // check relayer balance + relayerBalanceAfter := getBalance(t, cs, relayer) + relayerFee := big.NewInt(0).Sub(initialBalance, relayerBalanceAfter) + require.Equal(t, fee.String(), relayerFee.String()) + + // check sender balance + senderBalanceAfter := getBalance(t, cs, sender) + senderBalanceDiff := big.NewInt(0).Sub(initialBalance, senderBalanceAfter) + require.Equal(t, oneEGLD.String(), senderBalanceDiff.String()) + + // check receiver balance + receiverBalanceAfter := getBalance(t, cs, receiver) + require.Equal(t, oneEGLD.String(), receiverBalanceAfter.String()) + + // check scr + require.Equal(t, 1, len(result.SmartContractResults)) + require.Equal(t, relayer.Bech32, result.SmartContractResults[0].RelayerAddr) + require.Equal(t, sender.Bech32, result.SmartContractResults[0].SndAddr) + require.Equal(t, receiver.Bech32, result.SmartContractResults[0].RcvAddr) + require.Equal(t, relayedTx.Value, result.SmartContractResults[0].Value) + + // check intra shard logs, should be none + require.Nil(t, result.Logs) + + // check cross shard log, should be one completedTxEvent + if relayerShard == destinationShard { + return + } + scrResult, err := cs.GetNodeHandler(destinationShard).GetFacadeHandler().GetTransaction(result.SmartContractResults[0].Hash, true) + require.NoError(t, err) + require.NotNil(t, scrResult.Logs) + require.Equal(t, 1, len(scrResult.Logs.Events)) + require.Contains(t, scrResult.Logs.Events[0].Identifier, core.CompletedTxEventIdentifier) + } +} + +func testRelayedV3MoveBalanceLowerNonce( + relayerShard uint32, + receiverShard uint32, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + receiver, err := cs.GenerateAndMintWalletAddress(receiverShard, big.NewInt(0)) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + gasLimit := minGasLimit * 2 + relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, receiver.Bytes, relayer.Bytes, oneEGLD, "", uint64(gasLimit)) + + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // send same tx again, lower nonce + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.Contains(t, err.Error(), process.ErrWrongTransaction.Error()) + require.Nil(t, result) + } +} + +func testRelayedV3MoveInvalidGasLimit( + relayerShard uint32, + receiverShard uint32, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + receiver, err := cs.GenerateAndMintWalletAddress(receiverShard, big.NewInt(0)) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + gasLimit := minGasLimit + relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, receiver.Bytes, relayer.Bytes, oneEGLD, "", uint64(gasLimit)) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.Contains(t, err.Error(), process.ErrInsufficientGasLimitInTx.Error()) + require.Nil(t, result) + } +} + +func testRelayedV3ScCall( + relayerShard uint32, + ownerShard uint32, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + owner, err := cs.GenerateAndMintWalletAddress(ownerShard, initialBalance) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + resultDeploy, scAddressBytes := deployAdder(t, cs, owner, 0) + refundDeploy := getRefundValue(resultDeploy.SmartContractResults) + + // send relayed tx + txDataAdd := "add@" + hex.EncodeToString(big.NewInt(1).Bytes()) + gasLimit := uint64(3000000) + relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, scAddressBytes, relayer.Bytes, big.NewInt(0), txDataAdd, gasLimit) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // if cross shard, generate few more blocks for eventual refunds to be executed + if relayerShard != ownerShard { + require.NoError(t, cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx)) + } + + checkSum(t, cs.GetNodeHandler(ownerShard), scAddressBytes, owner.Bytes, 1) + + refundValue := getRefundValue(result.SmartContractResults) + require.NotZero(t, refundValue.Uint64()) + + // check fee fields + initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, refundValue, false) + require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) + require.Equal(t, fee.String(), result.Fee) + require.Equal(t, gasUsed, result.GasUsed) + + // check relayer balance + relayerBalanceAfter := getBalance(t, cs, relayer) + relayerFee := big.NewInt(0).Sub(initialBalance, relayerBalanceAfter) + require.Equal(t, fee.String(), relayerFee.String()) + + // check sender balance + senderBalanceAfter := getBalance(t, cs, sender) + require.Equal(t, initialBalance.String(), senderBalanceAfter.String()) + + // check owner balance + _, feeDeploy, _ := computeTxGasAndFeeBasedOnRefund(resultDeploy, refundDeploy, false) + ownerBalanceAfter := getBalance(t, cs, owner) + ownerFee := big.NewInt(0).Sub(initialBalance, ownerBalanceAfter) + require.Equal(t, feeDeploy.String(), ownerFee.String()) + + // check scrs + require.Equal(t, 2, len(result.SmartContractResults)) + for _, scr := range result.SmartContractResults { + checkSCRSucceeded(t, cs, scr) + } + } +} + +func testRelayedV3ScCallInvalidGasLimit( + relayerShard uint32, + ownerShard uint32, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + owner, err := cs.GenerateAndMintWalletAddress(ownerShard, initialBalance) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + _, scAddressBytes := deployAdder(t, cs, owner, 0) + + // send relayed tx with less gas limit + txDataAdd := "add@" + hex.EncodeToString(big.NewInt(1).Bytes()) + gasLimit := gasPerDataByte*len(txDataAdd) + minGasLimit + minGasLimit + relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, scAddressBytes, relayer.Bytes, big.NewInt(0), txDataAdd, uint64(gasLimit)) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + logs := result.Logs + // if cross shard, generate few more blocks for cross shard scrs + if relayerShard != ownerShard { + require.NoError(t, cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx)) + logs = result.SmartContractResults[0].Logs + } + + require.NotNil(t, logs) + require.Equal(t, 2, len(logs.Events)) + for _, event := range logs.Events { + if event.Identifier == core.SignalErrorOperation { + continue + } + + require.Equal(t, 1, len(event.AdditionalData)) + require.Contains(t, string(event.AdditionalData[0]), "[not enough gas]") + } + + refundValue := getRefundValue(result.SmartContractResults) + require.Zero(t, refundValue.Uint64()) + + // check fee fields, should consume full gas + initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, refundValue, false) + require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) + require.Equal(t, fee.String(), result.Fee) + require.Equal(t, result.InitiallyPaidFee, result.Fee) + require.Equal(t, gasUsed, result.GasUsed) + require.Equal(t, relayedTx.GasLimit, result.GasUsed) + + // check relayer balance + relayerBalanceAfter := getBalance(t, cs, relayer) + relayerFee := big.NewInt(0).Sub(initialBalance, relayerBalanceAfter) + require.Equal(t, fee.String(), relayerFee.String()) + + // check sender balance + senderBalanceAfter := getBalance(t, cs, sender) + require.Equal(t, initialBalance.String(), senderBalanceAfter.String()) + } +} + +func testRelayedV3ScCallInvalidMethod( + relayerShard uint32, + ownerShard uint32, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + owner, err := cs.GenerateAndMintWalletAddress(ownerShard, initialBalance) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + _, scAddressBytes := deployAdder(t, cs, owner, 0) + + // send relayed tx with invalid value + txDataAdd := "invalid" + gasLimit := uint64(3000000) + relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, scAddressBytes, relayer.Bytes, big.NewInt(0), txDataAdd, uint64(gasLimit)) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + logs := result.Logs + // if cross shard, generate few more blocks for cross shard scrs + if relayerShard != ownerShard { + require.NoError(t, cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx)) + logs = result.SmartContractResults[0].Logs + } + + require.NotNil(t, logs) + require.Equal(t, 2, len(logs.Events)) + for _, event := range logs.Events { + if event.Identifier == core.SignalErrorOperation { + continue + } + + require.Equal(t, 1, len(event.AdditionalData)) + require.Contains(t, string(event.AdditionalData[0]), "[invalid function (not found)]") + } + + refundValue := getRefundValue(result.SmartContractResults) + require.Zero(t, refundValue.Uint64()) // no refund, tx failed + + // check fee fields, should consume full gas + initiallyPaidFee, fee, _ := computeTxGasAndFeeBasedOnRefund(result, refundValue, false) + require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) + + // check relayer balance + relayerBalanceAfter := getBalance(t, cs, relayer) + relayerFee := big.NewInt(0).Sub(initialBalance, relayerBalanceAfter) + require.Equal(t, fee.String(), relayerFee.String()) + + // check sender balance + senderBalanceAfter := getBalance(t, cs, sender) + require.Equal(t, initialBalance.String(), senderBalanceAfter.String()) + } +} + func TestFixRelayedMoveBalanceWithChainSimulator(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") } - expectedFeeScCallBefore := "815294920000000" - expectedFeeScCallAfter := "873704920000000" + expectedFeeScCallBefore := "827294920000000" + expectedFeeScCallAfter := "885704920000000" t.Run("sc call", testFixRelayedMoveBalanceWithChainSimulatorScCall(expectedFeeScCallBefore, expectedFeeScCallAfter)) - expectedFeeMoveBalanceBefore := "797500000000000" // 498 * 1500 + 50000 + 5000 - expectedFeeMoveBalanceAfter := "847000000000000" // 498 * 1500 + 50000 + 50000 + expectedFeeMoveBalanceBefore := "809500000000000" // 506 * 1500 + 50000 + 500 + expectedFeeMoveBalanceAfter := "859000000000000" // 506 * 1500 + 50000 + 50000 t.Run("move balance", testFixRelayedMoveBalanceWithChainSimulatorMoveBalance(expectedFeeMoveBalanceBefore, expectedFeeMoveBalanceAfter)) } @@ -76,7 +512,7 @@ func testFixRelayedMoveBalanceWithChainSimulatorScCall( require.NoError(t, err) ownerNonce := uint64(0) - scAddressBytes := deployAdder(t, cs, owner, ownerNonce) + _, scAddressBytes := deployAdder(t, cs, owner, ownerNonce) // fast-forward until epoch 4 err = cs.GenerateBlocksUntilEpochIsReached(int32(4)) @@ -291,6 +727,13 @@ func startChainSimulator( return cs } +func generateRelayedV3Transaction(sender []byte, nonce uint64, receiver []byte, relayer []byte, value *big.Int, data string, gasLimit uint64) *transaction.Transaction { + tx := generateTransaction(sender, nonce, receiver, value, data, gasLimit) + tx.RelayerSignature = []byte(mockRelayerTxSignature) + tx.RelayerAddr = relayer + return tx +} + func generateTransaction(sender []byte, nonce uint64, receiver []byte, value *big.Int, data string, gasLimit uint64) *transaction.Transaction { return &transaction.Transaction{ Nonce: nonce, @@ -325,7 +768,7 @@ func deployAdder( cs testsChainSimulator.ChainSimulator, owner dtos.WalletAddress, ownerNonce uint64, -) []byte { +) (*transaction.ApiTransactionResult, []byte) { pkConv := cs.GetNodeHandler(0).GetCoreComponents().AddressPubKeyConverter() err := cs.GenerateBlocks(1) @@ -342,5 +785,94 @@ func deployAdder( scAddress := result.Logs.Events[0].Address scAddressBytes, _ := pkConv.Decode(scAddress) - return scAddressBytes + return result, scAddressBytes +} + +func checkSum( + t *testing.T, + nodeHandler chainSimulatorProcess.NodeHandler, + scAddress []byte, + callerAddress []byte, + expectedSum int, +) { + scQuery := &process.SCQuery{ + ScAddress: scAddress, + FuncName: "getSum", + CallerAddr: callerAddress, + CallValue: big.NewInt(0), + } + result, _, err := nodeHandler.GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "ok", result.ReturnCode) + + sum, err := strconv.Atoi(hex.EncodeToString(result.ReturnData[0])) + require.NoError(t, err) + + require.Equal(t, expectedSum, sum) +} + +func getRefundValue(scrs []*transaction.ApiSmartContractResult) *big.Int { + for _, scr := range scrs { + if scr.IsRefund { + return scr.Value + } + } + + return big.NewInt(0) +} + +func computeTxGasAndFeeBasedOnRefund( + result *transaction.ApiTransactionResult, + refund *big.Int, + isMoveBalance bool, +) (*big.Int, *big.Int, uint64) { + deductedGasPrice := uint64(minGasPrice / deductionFactor) + + initialTx := result.Tx + gasForFullPrice := uint64(minGasLimit + gasPerDataByte*len(initialTx.GetData())) + if result.ProcessingTypeOnSource == process.RelayedTxV3.String() { + gasForFullPrice += uint64(minGasLimit) // relayer fee + } + gasForDeductedPrice := initialTx.GetGasLimit() - gasForFullPrice + + initialFee := gasForFullPrice*minGasPrice + gasForDeductedPrice*deductedGasPrice + finalFee := initialFee - refund.Uint64() + + gasRefunded := refund.Uint64() / deductedGasPrice + gasConsumed := gasForFullPrice + gasForDeductedPrice - gasRefunded + + if isMoveBalance { + return big.NewInt(0).SetUint64(initialFee), big.NewInt(0).SetUint64(gasForFullPrice * minGasPrice), gasForFullPrice + } + + return big.NewInt(0).SetUint64(initialFee), big.NewInt(0).SetUint64(finalFee), gasConsumed +} + +func checkSCRSucceeded( + t *testing.T, + cs testsChainSimulator.ChainSimulator, + scr *transaction.ApiSmartContractResult, +) { + pkConv := cs.GetNodeHandler(0).GetCoreComponents().AddressPubKeyConverter() + shardC := cs.GetNodeHandler(0).GetShardCoordinator() + addr, err := pkConv.Decode(scr.RcvAddr) + require.NoError(t, err) + + senderShard := shardC.ComputeId(addr) + tx, err := cs.GetNodeHandler(senderShard).GetFacadeHandler().GetTransaction(scr.Hash, true) + require.NoError(t, err) + require.Equal(t, transaction.TxStatusSuccess, tx.Status) + + if tx.ReturnMessage == core.GasRefundForRelayerMessage { + return + } + + require.GreaterOrEqual(t, len(tx.Logs.Events), 1) + for _, event := range tx.Logs.Events { + if event.Identifier == core.WriteLogIdentifier { + continue + } + + require.Equal(t, core.CompletedTxEventIdentifier, event.Identifier) + } } diff --git a/integrationTests/multiShard/relayedTx/common.go b/integrationTests/multiShard/relayedTx/common.go index a9098c6c668..b50874f8763 100644 --- a/integrationTests/multiShard/relayedTx/common.go +++ b/integrationTests/multiShard/relayedTx/common.go @@ -123,6 +123,28 @@ func CreateAndSendRelayedAndUserTxV2( return relayedTx, userTx } +// CreateAndSendRelayedAndUserTxV3 will create and send a relayed user transaction v3 +func CreateAndSendRelayedAndUserTxV3( + nodes []*integrationTests.TestProcessorNode, + relayer *integrationTests.TestWalletAccount, + player *integrationTests.TestWalletAccount, + rcvAddr []byte, + value *big.Int, + gasLimit uint64, + txData []byte, +) (*transaction.Transaction, *transaction.Transaction) { + txDispatcherNode := getNodeWithinSameShardAsPlayer(nodes, relayer.Address) + + relayedTx := createRelayedTxV3(txDispatcherNode.EconomicsData, relayer, player, rcvAddr, value, gasLimit, txData) + + _, err := txDispatcherNode.SendTransaction(relayedTx) + if err != nil { + fmt.Println(err.Error()) + } + + return relayedTx, relayedTx +} + func createUserTx( player *integrationTests.TestWalletAccount, rcvAddr []byte, @@ -212,6 +234,41 @@ func createRelayedTxV2( return tx } +func createRelayedTxV3( + economicsFee process.FeeHandler, + relayer *integrationTests.TestWalletAccount, + player *integrationTests.TestWalletAccount, + rcvAddr []byte, + value *big.Int, + gasLimit uint64, + txData []byte, +) *transaction.Transaction { + tx := &transaction.Transaction{ + Nonce: player.Nonce, + Value: big.NewInt(0).Set(value), + RcvAddr: rcvAddr, + SndAddr: player.Address, + GasPrice: integrationTests.MinTxGasPrice, + GasLimit: gasLimit + integrationTests.MinTxGasLimit, + Data: txData, + ChainID: integrationTests.ChainID, + Version: integrationTests.MinTransactionVersion, + RelayerAddr: relayer.Address, + } + txBuff, _ := tx.GetDataForSigning(integrationTests.TestAddressPubkeyConverter, integrationTests.TestTxSignMarshalizer, integrationTests.TestTxSignHasher) + tx.Signature, _ = player.SingleSigner.Sign(player.SkTxSign, txBuff) + tx.RelayerSignature, _ = relayer.SingleSigner.Sign(relayer.SkTxSign, txBuff) + + player.Nonce++ + player.Balance.Sub(player.Balance, value) + + relayer.Nonce++ + txFee := economicsFee.ComputeTxFee(tx) + relayer.Balance.Sub(relayer.Balance, txFee) + + return tx +} + func createAndSendSimpleTransaction( nodes []*integrationTests.TestProcessorNode, player *integrationTests.TestWalletAccount, diff --git a/integrationTests/multiShard/relayedTx/relayedTx_test.go b/integrationTests/multiShard/relayedTx/relayedTx_test.go index 41ece5b81eb..5d54e2133cc 100644 --- a/integrationTests/multiShard/relayedTx/relayedTx_test.go +++ b/integrationTests/multiShard/relayedTx/relayedTx_test.go @@ -33,20 +33,24 @@ type createAndSendRelayedAndUserTxFuncType = func( func TestRelayedTransactionInMultiShardEnvironmentWithNormalTx(t *testing.T) { t.Run("relayed v1", testRelayedTransactionInMultiShardEnvironmentWithNormalTx(CreateAndSendRelayedAndUserTx, false)) + t.Run("relayed v3", testRelayedTransactionInMultiShardEnvironmentWithNormalTx(CreateAndSendRelayedAndUserTxV3, true)) } func TestRelayedTransactionInMultiShardEnvironmentWithSmartContractTX(t *testing.T) { t.Run("relayed v1", testRelayedTransactionInMultiShardEnvironmentWithSmartContractTX(CreateAndSendRelayedAndUserTx, false)) t.Run("relayed v2", testRelayedTransactionInMultiShardEnvironmentWithSmartContractTX(CreateAndSendRelayedAndUserTxV2, false)) + t.Run("relayed v3", testRelayedTransactionInMultiShardEnvironmentWithSmartContractTX(CreateAndSendRelayedAndUserTxV3, true)) } func TestRelayedTransactionInMultiShardEnvironmentWithESDTTX(t *testing.T) { t.Run("relayed v1", testRelayedTransactionInMultiShardEnvironmentWithESDTTX(CreateAndSendRelayedAndUserTx, false)) t.Run("relayed v2", testRelayedTransactionInMultiShardEnvironmentWithESDTTX(CreateAndSendRelayedAndUserTxV2, false)) + t.Run("relayed v3", testRelayedTransactionInMultiShardEnvironmentWithESDTTX(CreateAndSendRelayedAndUserTxV3, true)) } func TestRelayedTransactionInMultiShardEnvironmentWithAttestationContract(t *testing.T) { t.Run("relayed v1", testRelayedTransactionInMultiShardEnvironmentWithAttestationContract(CreateAndSendRelayedAndUserTx, false)) + t.Run("relayed v3", testRelayedTransactionInMultiShardEnvironmentWithAttestationContract(CreateAndSendRelayedAndUserTxV3, true)) } func testRelayedTransactionInMultiShardEnvironmentWithNormalTx( @@ -138,6 +142,8 @@ func testRelayedTransactionInMultiShardEnvironmentWithSmartContractTX( receiverAddress1 := []byte("12345678901234567890123456789012") receiverAddress2 := []byte("12345678901234567890123456789011") + integrationTests.MintAllPlayers(nodes, players, big.NewInt(1)) + ownerNode := nodes[0] initialSupply := "00" + hex.EncodeToString(big.NewInt(100000000000).Bytes()) scCode := wasm.GetSCCode("../../vm/wasm/testdata/erc20-c-03/wrc20_wasm.wasm") diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index dc828291384..80e8b5f0767 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -2592,22 +2592,29 @@ func (tpn *TestProcessorNode) SendTransaction(tx *dataTransaction.Transaction) ( if len(tx.GuardianAddr) == TestAddressPubkeyConverter.Len() { guardianAddress = TestAddressPubkeyConverter.SilentEncode(tx.GuardianAddr, log) } + + relayerAddress := "" + if len(tx.RelayerAddr) == TestAddressPubkeyConverter.Len() { + relayerAddress = TestAddressPubkeyConverter.SilentEncode(tx.RelayerAddr, log) + } createTxArgs := &external.ArgsCreateTransaction{ - Nonce: tx.Nonce, - Value: tx.Value.String(), - Receiver: encodedRcvAddr, - ReceiverUsername: nil, - Sender: encodedSndAddr, - SenderUsername: nil, - GasPrice: tx.GasPrice, - GasLimit: tx.GasLimit, - DataField: tx.Data, - SignatureHex: hex.EncodeToString(tx.Signature), - ChainID: string(tx.ChainID), - Version: tx.Version, - Options: tx.Options, - Guardian: guardianAddress, - GuardianSigHex: hex.EncodeToString(tx.GuardianSignature), + Nonce: tx.Nonce, + Value: tx.Value.String(), + Receiver: encodedRcvAddr, + ReceiverUsername: nil, + Sender: encodedSndAddr, + SenderUsername: nil, + GasPrice: tx.GasPrice, + GasLimit: tx.GasLimit, + DataField: tx.Data, + SignatureHex: hex.EncodeToString(tx.Signature), + ChainID: string(tx.ChainID), + Version: tx.Version, + Options: tx.Options, + Guardian: guardianAddress, + GuardianSigHex: hex.EncodeToString(tx.GuardianSignature), + Relayer: relayerAddress, + RelayerSignatureHex: hex.EncodeToString(tx.RelayerSignature), } tx, txHash, err := tpn.Node.CreateTransaction(createTxArgs) if err != nil { diff --git a/node/external/dtos.go b/node/external/dtos.go index f884d8d32c9..b1789054f5e 100644 --- a/node/external/dtos.go +++ b/node/external/dtos.go @@ -2,19 +2,21 @@ package external // ArgsCreateTransaction defines arguments for creating a transaction type ArgsCreateTransaction struct { - Nonce uint64 - Value string - Receiver string - ReceiverUsername []byte - Sender string - SenderUsername []byte - GasPrice uint64 - GasLimit uint64 - DataField []byte - SignatureHex string - ChainID string - Version uint32 - Options uint32 - Guardian string - GuardianSigHex string + Nonce uint64 + Value string + Receiver string + ReceiverUsername []byte + Sender string + SenderUsername []byte + GasPrice uint64 + GasLimit uint64 + DataField []byte + SignatureHex string + ChainID string + Version uint32 + Options uint32 + Guardian string + GuardianSigHex string + Relayer string + RelayerSignatureHex string } diff --git a/node/external/transactionAPI/apiTransactionProcessor.go b/node/external/transactionAPI/apiTransactionProcessor.go index c67ad1cb445..c6c568d46bf 100644 --- a/node/external/transactionAPI/apiTransactionProcessor.go +++ b/node/external/transactionAPI/apiTransactionProcessor.go @@ -199,9 +199,9 @@ func (atp *apiTransactionProcessor) populateComputedFieldInitiallyPaidFee(tx *tr tx.InitiallyPaidFee = fee.String() isFeeFixActive := atp.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, tx.Epoch) - isRelayedAfterFix := tx.IsRelayed && isFeeFixActive + _, fee, isRelayedV1V2 := atp.gasUsedAndFeeProcessor.getFeeOfRelayedV1V2(tx) + isRelayedAfterFix := tx.IsRelayed && isFeeFixActive && isRelayedV1V2 if isRelayedAfterFix { - _, fee, _ = atp.gasUsedAndFeeProcessor.getFeeOfRelayed(tx) tx.InitiallyPaidFee = fee.String() } } @@ -399,12 +399,19 @@ func (atp *apiTransactionProcessor) getFieldGettersForTx(wrappedTx *txcache.Wrap } guardedTx, isGuardedTx := wrappedTx.Tx.(data.GuardedTransactionHandler) - if isGuardedTx { + if isGuardedTx && len(guardedTx.GetGuardianAddr()) > 0 { fieldGetters[signatureField] = hex.EncodeToString(guardedTx.GetSignature()) fieldGetters[guardianField] = atp.addressPubKeyConverter.SilentEncode(guardedTx.GetGuardianAddr(), log) fieldGetters[guardianSignatureField] = hex.EncodeToString(guardedTx.GetGuardianSignature()) } + relayedTx, ok := wrappedTx.Tx.(data.RelayedTransactionHandler) + if ok && len(relayedTx.GetRelayerAddr()) > 0 { + fieldGetters[signatureField] = hex.EncodeToString(relayedTx.GetSignature()) + fieldGetters[relayerField] = atp.addressPubKeyConverter.SilentEncode(relayedTx.GetRelayerAddr(), log) + fieldGetters[relayerSignatureField] = hex.EncodeToString(relayedTx.GetRelayerSignature()) + } + return fieldGetters } diff --git a/node/external/transactionAPI/fieldsHandler.go b/node/external/transactionAPI/fieldsHandler.go index 4f837968cb7..8debf6f6ceb 100644 --- a/node/external/transactionAPI/fieldsHandler.go +++ b/node/external/transactionAPI/fieldsHandler.go @@ -19,6 +19,8 @@ const ( guardianSignatureField = "guardiansignature" senderShardID = "sendershard" receiverShardID = "receivershard" + relayerField = "relayer" + relayerSignatureField = "relayersignature" wildCard = "*" separator = "," diff --git a/node/external/transactionAPI/gasUsedAndFeeProcessor.go b/node/external/transactionAPI/gasUsedAndFeeProcessor.go index c4cd9578394..c5aa49e05c1 100644 --- a/node/external/transactionAPI/gasUsedAndFeeProcessor.go +++ b/node/external/transactionAPI/gasUsedAndFeeProcessor.go @@ -50,17 +50,26 @@ func (gfp *gasUsedAndFeeProcessor) computeAndAttachGasUsedAndFee(tx *transaction tx.Fee = tx.InitiallyPaidFee } - userTx, initialTotalFee, isRelayed := gfp.getFeeOfRelayed(tx) - isRelayedAfterFix := isRelayed && isFeeFixActive + userTx, initialTotalFee, isRelayedV1V2 := gfp.getFeeOfRelayedV1V2(tx) + isRelayedAfterFix := isRelayedV1V2 && isFeeFixActive if isRelayedAfterFix { tx.InitiallyPaidFee = initialTotalFee.String() tx.Fee = initialTotalFee.String() 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 hasRefundForSender := false for _, scr := range tx.SmartContractResults { - if !scr.IsRefund || scr.RcvAddr != tx.Sender { + if !scr.IsRefund { + continue + } + if !isRelayedV3 && scr.RcvAddr != tx.Sender { + continue + } + if isRelayedV3 && scr.RcvAddr != tx.RelayerAddress { continue } @@ -72,11 +81,18 @@ func (gfp *gasUsedAndFeeProcessor) computeAndAttachGasUsedAndFee(tx *transaction gfp.prepareTxWithResultsBasedOnLogs(tx, userTx, hasRefundForSender) } -func (gfp *gasUsedAndFeeProcessor) getFeeOfRelayed(tx *transaction.ApiTransactionResult) (*transaction.ApiTransactionResult, *big.Int, bool) { +func (gfp *gasUsedAndFeeProcessor) getFeeOfRelayedV1V2(tx *transaction.ApiTransactionResult) (*transaction.ApiTransactionResult, *big.Int, bool) { if !tx.IsRelayed { 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 + if isRelayedV3 { + return nil, nil, false + } + if len(tx.Data) == 0 { return nil, nil, false } @@ -173,7 +189,10 @@ func (gfp *gasUsedAndFeeProcessor) setGasUsedAndFeeBaseOnRefundValue( userTx *transaction.ApiTransactionResult, refund *big.Int, ) { - if !check.IfNilReflect(userTx) && gfp.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, tx.Epoch) { + isRelayedV3 := len(tx.RelayerAddress) == len(tx.Sender) && + len(tx.RelayerSignature) == len(tx.Signature) + isValidUserTxAfterBaseCostActivation := !check.IfNilReflect(userTx) && gfp.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, tx.Epoch) + if isValidUserTxAfterBaseCostActivation && !isRelayedV3 { gasUsed, fee := gfp.feeComputer.ComputeGasUsedAndFeeBasedOnRefundValue(userTx, refund) gasUsedRelayedTx := gfp.feeComputer.ComputeGasLimit(tx) feeRelayedTx := gfp.feeComputer.ComputeTxFeeBasedOnGasUsed(tx, gasUsedRelayedTx) diff --git a/node/external/transactionAPI/unmarshaller.go b/node/external/transactionAPI/unmarshaller.go index c9526217f4f..24d8961885b 100644 --- a/node/external/transactionAPI/unmarshaller.go +++ b/node/external/transactionAPI/unmarshaller.go @@ -101,7 +101,11 @@ func (tu *txUnmarshaller) unmarshalTransaction(txBytes []byte, txType transactio } apiTx.ReceiversShardIDs = res.ReceiversShardID - apiTx.IsRelayed = res.IsRelayed + + hasValidRelayer := len(apiTx.RelayerAddress) == len(apiTx.Sender) && len(apiTx.RelayerAddress) > 0 + hasValidRelayerSignature := len(apiTx.RelayerSignature) == len(apiTx.Signature) && len(apiTx.RelayerSignature) > 0 + isRelayedV3 := hasValidRelayer && hasValidRelayerSignature + apiTx.IsRelayed = res.IsRelayed || isRelayedV3 return apiTx, nil } @@ -132,6 +136,12 @@ func (tu *txUnmarshaller) prepareNormalTx(tx *transaction.Transaction) *transact apiTx.GuardianAddr = tu.addressPubKeyConverter.SilentEncode(tx.GuardianAddr, log) apiTx.GuardianSignature = hex.EncodeToString(tx.GuardianSignature) } + if len(tx.RelayerAddr) > 0 { + apiTx.RelayerAddress = tu.addressPubKeyConverter.SilentEncode(tx.RelayerAddr, log) + } + if len(tx.RelayerSignature) > 0 { + apiTx.RelayerSignature = hex.EncodeToString(tx.RelayerSignature) + } return apiTx } @@ -162,6 +172,12 @@ func (tu *txUnmarshaller) prepareInvalidTx(tx *transaction.Transaction) *transac apiTx.GuardianAddr = tu.addressPubKeyConverter.SilentEncode(tx.GuardianAddr, log) apiTx.GuardianSignature = hex.EncodeToString(tx.GuardianSignature) } + if len(tx.RelayerAddr) > 0 { + apiTx.RelayerAddress = tu.addressPubKeyConverter.SilentEncode(tx.RelayerAddr, log) + } + if len(tx.RelayerSignature) > 0 { + apiTx.RelayerSignature = hex.EncodeToString(tx.RelayerSignature) + } return apiTx } diff --git a/node/metrics/metrics.go b/node/metrics/metrics.go index 7d828d26394..5c74f42eacd 100644 --- a/node/metrics/metrics.go +++ b/node/metrics/metrics.go @@ -202,6 +202,7 @@ func InitConfigMetrics( appStatusHandler.SetUInt64Value(common.MetricCryptoOpcodesV2EnableEpoch, uint64(enableEpochs.CryptoOpcodesV2EnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch, uint64(enableEpochs.MultiESDTNFTTransferAndExecuteByUserEnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch, uint64(enableEpochs.FixRelayedMoveBalanceToNonPayableSCEnableEpoch)) + appStatusHandler.SetUInt64Value(common.MetricRelayedTransactionsV3EnableEpoch, uint64(enableEpochs.RelayedTransactionsV3EnableEpoch)) for i, nodesChangeConfig := range enableEpochs.MaxNodesChangeEnableEpoch { epochEnable := fmt.Sprintf("%s%d%s", common.MetricMaxNodesChangeEnableEpoch, i, common.EpochEnableSuffix) diff --git a/node/metrics/metrics_test.go b/node/metrics/metrics_test.go index 1aa3bd7be2e..3ffe2cf7a5a 100644 --- a/node/metrics/metrics_test.go +++ b/node/metrics/metrics_test.go @@ -211,6 +211,7 @@ func TestInitConfigMetrics(t *testing.T) { FixRelayedBaseCostEnableEpoch: 104, MultiESDTNFTTransferAndExecuteByUserEnableEpoch: 105, FixRelayedMoveBalanceToNonPayableSCEnableEpoch: 106, + RelayedTransactionsV3EnableEpoch: 107, MaxNodesChangeEnableEpoch: []config.MaxNodesChangeConfig{ { EpochEnable: 0, @@ -332,6 +333,7 @@ func TestInitConfigMetrics(t *testing.T) { "erd_fix_relayed_base_cost_enable_epoch": uint32(104), "erd_multi_esdt_transfer_execute_by_user_enable_epoch": uint32(105), "erd_fix_relayed_move_balance_to_non_payable_sc_enable_epoch": uint32(106), + "erd_relayed_transactions_v3_enable_epoch": uint32(107), "erd_max_nodes_change_enable_epoch": nil, "erd_total_supply": "12345", "erd_hysteresis": "0.100000", diff --git a/node/node.go b/node/node.go index a652e80be60..ca07f4a0acf 100644 --- a/node/node.go +++ b/node/node.go @@ -846,6 +846,9 @@ func (n *Node) CreateTransaction(txArgs *external.ArgsCreateTransaction) (*trans if len(txArgs.GuardianSigHex) > n.addressSignatureHexSize { return nil, nil, fmt.Errorf("%w for guardian signature", ErrInvalidSignatureLength) } + if len(txArgs.RelayerSignatureHex) > n.addressSignatureHexSize { + return nil, nil, fmt.Errorf("%w for relayer signature", ErrInvalidSignatureLength) + } if uint32(len(txArgs.Receiver)) > n.coreComponents.EncodedAddressLen() { return nil, nil, fmt.Errorf("%w for receiver", ErrInvalidAddressLength) @@ -856,6 +859,9 @@ func (n *Node) CreateTransaction(txArgs *external.ArgsCreateTransaction) (*trans if uint32(len(txArgs.Guardian)) > n.coreComponents.EncodedAddressLen() { return nil, nil, fmt.Errorf("%w for guardian", ErrInvalidAddressLength) } + if uint32(len(txArgs.Relayer)) > n.coreComponents.EncodedAddressLen() { + return nil, nil, fmt.Errorf("%w for relayer", ErrInvalidAddressLength) + } if len(txArgs.SenderUsername) > core.MaxUserNameLength { return nil, nil, ErrInvalidSenderUsernameLength } @@ -912,6 +918,20 @@ func (n *Node) CreateTransaction(txArgs *external.ArgsCreateTransaction) (*trans return nil, nil, err } } + if len(txArgs.Relayer) > 0 { + relayerAddress, errDecode := addrPubKeyConverter.Decode(txArgs.Relayer) + if errDecode != nil { + return nil, nil, fmt.Errorf("%w while decoding relayer address", errDecode) + } + tx.RelayerAddr = relayerAddress + } + if len(txArgs.RelayerSignatureHex) > 0 { + relayerSigBytes, errDecodeString := hex.DecodeString(txArgs.RelayerSignatureHex) + if errDecodeString != nil { + return nil, nil, fmt.Errorf("%w while decoding relayer signature", errDecodeString) + } + tx.RelayerSignature = relayerSigBytes + } var txHash []byte txHash, err = core.CalculateHash(n.coreComponents.InternalMarshalizer(), n.coreComponents.Hasher(), tx) diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index 30bcf0fca76..8dfaa1bf338 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -271,7 +271,15 @@ func (tep *transactionsFeeProcessor) setGasUsedAndFeeBasedOnRefundValue( refund *big.Int, epoch uint32, ) { - if !check.IfNil(userTx) && tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) { + tx := txWithResults.GetTxHandler() + relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler) + if isRelayedV3 { + hasValidRelayer := len(relayedTx.GetRelayerAddr()) == len(tx.GetSndAddr()) && len(relayedTx.GetRelayerAddr()) > 0 + hasValidRelayerSignature := len(relayedTx.GetRelayerSignature()) == len(relayedTx.GetSignature()) && len(relayedTx.GetRelayerSignature()) > 0 + isRelayedV3 = hasValidRelayer && hasValidRelayerSignature + } + isValidUserTxAfterBaseCostActivation := !check.IfNilReflect(userTx) && tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) + if isValidUserTxAfterBaseCostActivation && !isRelayedV3 { gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(userTx, refund) tx := txWithResults.GetTxHandler() diff --git a/process/constants.go b/process/constants.go index f75e7b882ee..5d7960c70c8 100644 --- a/process/constants.go +++ b/process/constants.go @@ -36,6 +36,8 @@ const ( RelayedTx // RelayedTxV2 defines the ID of a slim relayed transaction version RelayedTxV2 + // RelayedTxV3 defines the ID of a relayed transaction v3 + RelayedTxV3 // RewardTx defines ID of a reward transaction RewardTx // InvalidTransaction defines unknown transaction type @@ -56,6 +58,8 @@ func (transactionType TransactionType) String() string { return "RelayedTx" case RelayedTxV2: return "RelayedTxV2" + case RelayedTxV3: + return "RelayedTxV3" case RewardTx: return "RewardTx" case InvalidTransaction: diff --git a/process/coordinator/transactionType.go b/process/coordinator/transactionType.go index 32081a1ac0e..dd648a4dd54 100644 --- a/process/coordinator/transactionType.go +++ b/process/coordinator/transactionType.go @@ -83,6 +83,16 @@ func (tth *txTypeHandler) ComputeTransactionType(tx data.TransactionHandler) (pr return process.InvalidTransaction, process.InvalidTransaction } + relayedTxV3, ok := tx.(data.RelayedTransactionHandler) + if ok { + hasValidRelayer := len(relayedTxV3.GetRelayerAddr()) == len(tx.GetSndAddr()) && len(relayedTxV3.GetRelayerAddr()) > 0 + hasValidRelayerSignature := len(relayedTxV3.GetRelayerSignature()) == len(relayedTxV3.GetSignature()) && len(relayedTxV3.GetRelayerSignature()) > 0 + isRelayedV3 := hasValidRelayer && hasValidRelayerSignature + if isRelayedV3 { + return process.RelayedTxV3, process.RelayedTxV3 + } + } + isEmptyAddress := tth.isDestAddressEmpty(tx) if isEmptyAddress { if len(tx.GetData()) > 0 { diff --git a/process/coordinator/transactionType_test.go b/process/coordinator/transactionType_test.go index 918b6069212..705b45c78e8 100644 --- a/process/coordinator/transactionType_test.go +++ b/process/coordinator/transactionType_test.go @@ -466,6 +466,34 @@ func TestTxTypeHandler_ComputeTransactionTypeRelayedV2Func(t *testing.T) { assert.Equal(t, process.RelayedTxV2, txTypeCross) } +func TestTxTypeHandler_ComputeTransactionTypeRelayedV3(t *testing.T) { + t.Parallel() + + tx := &transaction.Transaction{} + tx.Nonce = 0 + tx.SndAddr = []byte("000") + tx.RcvAddr = []byte("001") + tx.Value = big.NewInt(45) + tx.RelayerAddr = []byte("002") + tx.Signature = []byte("ssig") + tx.RelayerSignature = []byte("rsig") + + arg := createMockArguments() + arg.PubkeyConverter = &testscommon.PubkeyConverterStub{ + LenCalled: func() int { + return len(tx.RcvAddr) + }, + } + tth, err := NewTxTypeHandler(arg) + + assert.NotNil(t, tth) + assert.Nil(t, err) + + txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + assert.Equal(t, process.RelayedTxV3, txTypeIn) + assert.Equal(t, process.RelayedTxV3, txTypeCross) +} + func TestTxTypeHandler_ComputeTransactionTypeForSCRCallBack(t *testing.T) { t.Parallel() diff --git a/process/dataValidators/txValidator.go b/process/dataValidators/txValidator.go index 9c72be1d89a..b95c1bca2b7 100644 --- a/process/dataValidators/txValidator.go +++ b/process/dataValidators/txValidator.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/check" + "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/state" @@ -91,24 +92,46 @@ func (txv *txValidator) checkAccount( return err } - account, err := txv.getSenderUserAccount(interceptedTx, accountHandler) + feePayerAccount, err := txv.getFeePayerAccount(interceptedTx, accountHandler) if err != nil { return err } - return txv.checkBalance(interceptedTx, account) + return txv.checkBalance(interceptedTx, feePayerAccount) } -func (txv *txValidator) getSenderUserAccount( +func (txv *txValidator) getFeePayerAccount( interceptedTx process.InterceptedTransactionHandler, accountHandler vmcommon.AccountHandler, ) (state.UserAccountHandler, error) { - senderAddress := interceptedTx.SenderAddress() - account, ok := accountHandler.(state.UserAccountHandler) + payerAddress := interceptedTx.SenderAddress() + payerAccount := accountHandler + + tx := interceptedTx.Transaction() + relayedTx, ok := tx.(data.RelayedTransactionHandler) + if ok { + hasValidRelayer := len(relayedTx.GetRelayerAddr()) == len(tx.GetSndAddr()) && len(relayedTx.GetRelayerAddr()) > 0 + hasValidRelayerSignature := len(relayedTx.GetRelayerSignature()) == len(relayedTx.GetSignature()) && len(relayedTx.GetRelayerSignature()) > 0 + isRelayedV3 := hasValidRelayer && hasValidRelayerSignature + if isRelayedV3 { + payerAddress = relayedTx.GetRelayerAddr() + relayerAccount, err := txv.accounts.GetExistingAccount(payerAddress) + if err != nil { + return nil, fmt.Errorf("%w for address %s and shard %d, err: %s", + process.ErrAccountNotFound, + txv.pubKeyConverter.SilentEncode(payerAddress, log), + txv.shardCoordinator.SelfId(), + err.Error(), + ) + } + payerAccount = relayerAccount + } + } + account, ok := payerAccount.(state.UserAccountHandler) if !ok { return nil, fmt.Errorf("%w, account is not of type *state.Account, address: %s", process.ErrWrongTypeAssertion, - txv.pubKeyConverter.SilentEncode(senderAddress, log), + txv.pubKeyConverter.SilentEncode(payerAddress, log), ) } return account, nil @@ -118,10 +141,9 @@ func (txv *txValidator) checkBalance(interceptedTx process.InterceptedTransactio accountBalance := account.GetBalance() txFee := interceptedTx.Fee() if accountBalance.Cmp(txFee) < 0 { - senderAddress := interceptedTx.SenderAddress() return fmt.Errorf("%w, for address: %s, wanted %v, have %v", process.ErrInsufficientFunds, - txv.pubKeyConverter.SilentEncode(senderAddress, log), + txv.pubKeyConverter.SilentEncode(account.AddressBytes(), log), txFee, accountBalance, ) diff --git a/process/dataValidators/txValidator_test.go b/process/dataValidators/txValidator_test.go index 551b18928d1..a45acf2b434 100644 --- a/process/dataValidators/txValidator_test.go +++ b/process/dataValidators/txValidator_test.go @@ -1,6 +1,7 @@ package dataValidators_test import ( + "bytes" "errors" "math/big" "strconv" @@ -269,31 +270,100 @@ func TestTxValidator_CheckTxValidityTxNonceIsTooHigh(t *testing.T) { func TestTxValidator_CheckTxValidityAccountBalanceIsLessThanTxTotalValueShouldReturnFalse(t *testing.T) { t.Parallel() - accountNonce := uint64(0) - txNonce := uint64(1) - fee := big.NewInt(1000) - accountBalance := big.NewInt(10) + t.Run("normal tx should return false for sender", func(t *testing.T) { + t.Parallel() - adb := getAccAdapter(accountNonce, accountBalance) - shardCoordinator := createMockCoordinator("_", 0) - maxNonceDeltaAllowed := 100 - txValidator, err := dataValidators.NewTxValidator( - adb, - shardCoordinator, - &testscommon.WhiteListHandlerStub{}, - testscommon.NewPubkeyConverterMock(32), - &testscommon.TxVersionCheckerStub{}, - maxNonceDeltaAllowed, - ) - assert.Nil(t, err) + accountNonce := uint64(0) + txNonce := uint64(1) + fee := big.NewInt(1000) + accountBalance := big.NewInt(10) - addressMock := []byte("address") - currentShard := uint32(0) - txValidatorHandler := getInterceptedTxHandler(currentShard, currentShard, txNonce, addressMock, fee) + providedSenderAddress := []byte("address") + adb := &stateMock.AccountsStub{} + adb.GetExistingAccountCalled = func(address []byte) (handler vmcommon.AccountHandler, e error) { + require.True(t, bytes.Equal(providedSenderAddress, address)) - result := txValidator.CheckTxValidity(txValidatorHandler) - assert.NotNil(t, result) - assert.True(t, errors.Is(result, process.ErrInsufficientFunds)) + acc, _ := accounts.NewUserAccount(address, &trie.DataTrieTrackerStub{}, &trie.TrieLeafParserStub{}) + acc.Nonce = accountNonce + acc.Balance = accountBalance + + return acc, nil + } + + shardCoordinator := createMockCoordinator("_", 0) + maxNonceDeltaAllowed := 100 + txValidator, err := dataValidators.NewTxValidator( + adb, + shardCoordinator, + &testscommon.WhiteListHandlerStub{}, + testscommon.NewPubkeyConverterMock(32), + &testscommon.TxVersionCheckerStub{}, + maxNonceDeltaAllowed, + ) + assert.Nil(t, err) + + currentShard := uint32(0) + txValidatorHandler := getInterceptedTxHandler(currentShard, currentShard, txNonce, providedSenderAddress, fee) + + result := txValidator.CheckTxValidity(txValidatorHandler) + assert.NotNil(t, result) + assert.True(t, errors.Is(result, process.ErrInsufficientFunds)) + }) + t.Run("relayed tx v3 should return false for relayer", func(t *testing.T) { + t.Parallel() + + accountNonce := uint64(0) + txNonce := uint64(1) + fee := big.NewInt(1000) + accountBalance := big.NewInt(10) + + providedRelayerAddress := []byte("relayer") + providedSenderAddress := []byte("address") + adb := &stateMock.AccountsStub{} + cnt := 0 + adb.GetExistingAccountCalled = func(address []byte) (handler vmcommon.AccountHandler, e error) { + cnt++ + if cnt == 1 { + require.True(t, bytes.Equal(providedSenderAddress, address)) + } else { + require.True(t, bytes.Equal(providedRelayerAddress, address)) + } + + acc, _ := accounts.NewUserAccount(address, &trie.DataTrieTrackerStub{}, &trie.TrieLeafParserStub{}) + acc.Nonce = accountNonce + acc.Balance = accountBalance + + return acc, nil + } + + shardCoordinator := createMockCoordinator("_", 0) + maxNonceDeltaAllowed := 100 + txValidator, err := dataValidators.NewTxValidator( + adb, + shardCoordinator, + &testscommon.WhiteListHandlerStub{}, + testscommon.NewPubkeyConverterMock(32), + &testscommon.TxVersionCheckerStub{}, + maxNonceDeltaAllowed, + ) + assert.Nil(t, err) + + currentShard := uint32(0) + txValidatorHandler := getInterceptedTxHandler(currentShard, currentShard, txNonce, providedSenderAddress, fee) + txValidatorHandlerStub, ok := txValidatorHandler.(*mock.InterceptedTxHandlerStub) + require.True(t, ok) + txValidatorHandlerStub.TransactionCalled = func() data.TransactionHandler { + return &transaction.Transaction{ + SndAddr: providedSenderAddress, + Signature: []byte("address sig"), + RelayerAddr: providedRelayerAddress, + RelayerSignature: []byte("relayer sig"), + } + } + result := txValidator.CheckTxValidity(txValidatorHandler) + assert.NotNil(t, result) + assert.True(t, errors.Is(result, process.ErrInsufficientFunds)) + }) } func TestTxValidator_CheckTxValidityAccountNotExitsShouldReturnFalse(t *testing.T) { diff --git a/process/economics/economicsData.go b/process/economics/economicsData.go index 5b7ce045237..4da39f94862 100644 --- a/process/economics/economicsData.go +++ b/process/economics/economicsData.go @@ -488,15 +488,24 @@ func (ed *economicsData) ComputeGasLimit(tx data.TransactionWithFeeHandler) uint return ed.ComputeGasLimitInEpoch(tx, currentEpoch) } -// ComputeGasLimitInEpoch returns the gas limit need by the provided transaction in order to be executed in a specific epoch +// ComputeGasLimitInEpoch returns the gas limit needed by the provided transaction in order to be executed in a specific epoch func (ed *economicsData) ComputeGasLimitInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) uint64 { gasLimit := ed.getMinGasLimit(epoch) dataLen := uint64(len(tx.GetData())) gasLimit += dataLen * ed.gasPerDataByte txInstance, ok := tx.(*transaction.Transaction) - if ok && ed.txVersionHandler.IsGuardedTransaction(txInstance) { - gasLimit += ed.getExtraGasLimitGuardedTx(epoch) + if ok { + if ed.txVersionHandler.IsGuardedTransaction(txInstance) { + gasLimit += ed.getExtraGasLimitGuardedTx(epoch) + } + + hasValidRelayer := len(txInstance.GetRelayerAddr()) == len(txInstance.GetSndAddr()) && len(txInstance.GetRelayerAddr()) > 0 + hasValidRelayerSignature := len(txInstance.GetRelayerSignature()) == len(txInstance.GetSignature()) && len(txInstance.GetRelayerSignature()) > 0 + isRelayedV3 := hasValidRelayer && hasValidRelayerSignature + if isRelayedV3 { + gasLimit += ed.MinGasLimitInEpoch(epoch) + } } return gasLimit diff --git a/process/errors.go b/process/errors.go index 83e8095dcb3..d75093d8cd9 100644 --- a/process/errors.go +++ b/process/errors.go @@ -1229,3 +1229,9 @@ var ErrNilSentSignatureTracker = errors.New("nil sent signature tracker") // ErrTransferAndExecuteByUserAddressesAreNil signals that transfer and execute by user addresses are nil var ErrTransferAndExecuteByUserAddressesAreNil = errors.New("transfer and execute by user addresses are nil") + +// ErrRelayedTxV3Disabled signals that relayed tx v3 are disabled +var ErrRelayedTxV3Disabled = errors.New("relayed tx v3 are disabled") + +// ErrGuardedRelayerNotAllowed signals that the provided relayer is guarded +var ErrGuardedRelayerNotAllowed = errors.New("guarded relayer not allowed") diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index b1e95a71339..72ae41a3bd6 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -152,10 +152,15 @@ func (txProc *baseTxProcessor) checkTxValues( txFee = txProc.economicsFee.ComputeTxFee(tx) } - if acntSnd.GetBalance().Cmp(txFee) < 0 { + feePayer, err := txProc.getFeePayer(tx, acntSnd) + if err != nil { + return err + } + + if feePayer.GetBalance().Cmp(txFee) < 0 { return fmt.Errorf("%w, has: %s, wanted: %s", process.ErrInsufficientFee, - acntSnd.GetBalance().String(), + feePayer.GetBalance().String(), txFee.String(), ) } @@ -167,13 +172,29 @@ func (txProc *baseTxProcessor) checkTxValues( } cost := big.NewInt(0).Add(txFee, tx.Value) - if acntSnd.GetBalance().Cmp(cost) < 0 { + if feePayer.GetBalance().Cmp(cost) < 0 { return process.ErrInsufficientFunds } return nil } +func (txProc *baseTxProcessor) getFeePayer( + tx *transaction.Transaction, + acntSnd state.UserAccountHandler, +) (state.UserAccountHandler, error) { + if !isRelayedTxV3(tx) { + return acntSnd, nil + } + + acntRelayer, _, err := txProc.getAccounts(tx.RelayerAddr, tx.RelayerAddr) + if err != nil { + return nil, err + } + + return acntRelayer, nil +} + func (txProc *baseTxProcessor) computeInnerTxFee(tx *transaction.Transaction) *big.Int { if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedBaseCostFlag) { return txProc.computeInnerTxFeeAfterBaseCostFix(tx) diff --git a/process/transaction/export_test.go b/process/transaction/export_test.go index cd657c3991d..f6c154dc6d1 100644 --- a/process/transaction/export_test.go +++ b/process/transaction/export_test.go @@ -55,6 +55,7 @@ func (txProc *txProcessor) ProcessUserTx( userTx *transaction.Transaction, relayedTxValue *big.Int, relayedNonce uint64, + relayerAddr []byte, originalTxHash []byte, ) (vmcommon.ReturnCode, error) { return txProc.processUserTx( @@ -62,6 +63,7 @@ func (txProc *txProcessor) ProcessUserTx( userTx, relayedTxValue, relayedNonce, + relayerAddr, originalTxHash) } diff --git a/process/transaction/interceptedTransaction.go b/process/transaction/interceptedTransaction.go index 75b9a65ae7c..890939b621d 100644 --- a/process/transaction/interceptedTransaction.go +++ b/process/transaction/interceptedTransaction.go @@ -189,6 +189,11 @@ func (inTx *InterceptedTransaction) CheckValidity() error { return err } + err = inTx.verifyIfRelayedTxV3(inTx.tx) + if err != nil { + return err + } + err = inTx.verifyIfRelayedTx(inTx.tx) if err != nil { return err @@ -205,8 +210,12 @@ func (inTx *InterceptedTransaction) CheckValidity() error { return nil } -func (inTx *InterceptedTransaction) checkRecursiveRelayed(userTxData []byte) error { - funcName, _, err := inTx.argsParser.ParseCallData(string(userTxData)) +func (inTx *InterceptedTransaction) checkRecursiveRelayed(userTx *transaction.Transaction) error { + if isRelayedTxV3(userTx) { + return process.ErrRecursiveRelayedTxIsNotAllowed + } + + funcName, _, err := inTx.argsParser.ParseCallData(string(userTx.Data)) if err != nil { return nil } @@ -223,6 +232,36 @@ func isRelayedTx(funcName string) bool { core.RelayedTransactionV2 == funcName } +func isRelayedTxV3(tx *transaction.Transaction) bool { + return len(tx.RelayerAddr) == len(tx.SndAddr) && len(tx.RelayerAddr) > 0 && + len(tx.RelayerSignature) == len(tx.Signature) && len(tx.RelayerSignature) > 0 +} + +func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transaction) error { + if !isRelayedTxV3(tx) { + return nil + } + + err := inTx.integrity(tx) + if err != nil { + return fmt.Errorf("inner transaction: %w", err) + } + + userTx := *tx + userTx.RelayerSignature = make([]byte, 0) // temporary removed signature for recursive relayed checks + err = inTx.verifyUserTx(&userTx) + if err != nil { + return fmt.Errorf("inner transaction: %w", err) + } + + err = inTx.verifyRelayerSig(tx) + if err != nil { + return fmt.Errorf("inner transaction: %w", err) + } + + return nil +} + func (inTx *InterceptedTransaction) verifyIfRelayedTxV2(tx *transaction.Transaction) error { funcName, userTxArgs, err := inTx.argsParser.ParseCallData(string(tx.Data)) if err != nil { @@ -272,7 +311,7 @@ func (inTx *InterceptedTransaction) verifyIfRelayedTx(tx *transaction.Transactio func (inTx *InterceptedTransaction) verifyUserTx(userTx *transaction.Transaction) error { // recursive relayed transactions are not allowed - err := inTx.checkRecursiveRelayed(userTx.Data) + err := inTx.checkRecursiveRelayed(userTx) if err != nil { return fmt.Errorf("inner transaction: %w", err) } @@ -370,6 +409,21 @@ func (inTx *InterceptedTransaction) verifySig(tx *transaction.Transaction) error return inTx.singleSigner.Verify(senderPubKey, txMessageForSigVerification, tx.Signature) } +// verifyRelayerSig checks if the tx is correctly signed by relayer +func (inTx *InterceptedTransaction) verifyRelayerSig(tx *transaction.Transaction) error { + txMessageForSigVerification, err := inTx.getTxMessageForGivenTx(tx) + if err != nil { + return err + } + + relayerPubKey, err := inTx.keyGen.PublicKeyFromByteArray(tx.RelayerAddr) + if err != nil { + return err + } + + return inTx.singleSigner.Verify(relayerPubKey, txMessageForSigVerification, tx.RelayerSignature) +} + // VerifyGuardianSig verifies if the guardian signature is valid func (inTx *InterceptedTransaction) VerifyGuardianSig(tx *transaction.Transaction) error { txMessageForSigVerification, err := inTx.getTxMessageForGivenTx(tx) diff --git a/process/transaction/interceptedTransaction_test.go b/process/transaction/interceptedTransaction_test.go index f35ce467d13..4eafa62ae8d 100644 --- a/process/transaction/interceptedTransaction_test.go +++ b/process/transaction/interceptedTransaction_test.go @@ -36,6 +36,7 @@ var senderShard = uint32(2) var recvShard = uint32(3) var senderAddress = []byte("12345678901234567890123456789012") var recvAddress = []byte("23456789012345678901234567890123") +var relayerAddress = []byte("34567890123456789012345678901234") var sigBad = []byte("bad-signature") var sigOk = []byte("signature") @@ -1500,6 +1501,46 @@ func TestInterceptedTransaction_CheckValidityOfRelayedTxV2(t *testing.T) { assert.Nil(t, err) } +func TestInterceptedTransaction_CheckValidityOfRelayedTxV3(t *testing.T) { + t.Parallel() + + minTxVersion := uint32(1) + chainID := []byte("chain") + tx := &dataTransaction.Transaction{ + Nonce: 1, + Value: big.NewInt(2), + GasLimit: 3, + GasPrice: 4, + RcvAddr: recvAddress, + SndAddr: senderAddress, + ChainID: chainID, + Version: minTxVersion, + RelayerAddr: relayerAddress, + } + txi, _ := createInterceptedTxFromPlainTxWithArgParser(tx) + err := txi.CheckValidity() + assert.Equal(t, err, process.ErrNilSignature) + + tx.Signature = sigOk + tx.RelayerSignature = sigOk + + tx.Data = []byte(core.RelayedTransactionV2 + "@" + hex.EncodeToString(recvAddress) + "@" + hex.EncodeToString(big.NewInt(0).SetUint64(0).Bytes()) + "@" + hex.EncodeToString([]byte("some method")) + "@" + hex.EncodeToString(sigOk)) + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + err = txi.CheckValidity() + assert.True(t, errors.Is(err, process.ErrRecursiveRelayedTxIsNotAllowed)) + + tx.Data = nil + tx.RelayerSignature = bytes.Repeat([]byte("a"), len(sigOk)) // same length but invalid relayer sig + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + err = txi.CheckValidity() + assert.NotNil(t, err) + + tx.RelayerSignature = sigOk + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + err = txi.CheckValidity() + assert.Nil(t, err) +} + // ------- IsInterfaceNil func TestInterceptedTransaction_IsInterfaceNil(t *testing.T) { t.Parallel() diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 51910b537e2..81fd8dac766 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -240,6 +240,8 @@ func (txProc *txProcessor) ProcessTransaction(tx *transaction.Transaction) (vmco return txProc.processRelayedTx(tx, acntSnd, acntDst) case process.RelayedTxV2: return txProc.processRelayedTxV2(tx, acntSnd, acntDst) + case process.RelayedTxV3: + return txProc.processRelayedTxV3(tx) } return vmcommon.UserError, txProc.executingFailedTransaction(tx, acntSnd, process.ErrWrongTransaction) @@ -316,7 +318,7 @@ func (txProc *txProcessor) executingFailedTransaction( rpt := &receipt.Receipt{ Value: big.NewInt(0).Set(txFee), - SndAddr: tx.SndAddr, + SndAddr: acntSnd.AddressBytes(), Data: []byte(txError.Error()), TxHash: txHash, } @@ -603,8 +605,14 @@ func (txProc *txProcessor) finishExecutionOfRelayedTx( tx *transaction.Transaction, userTx *transaction.Transaction, ) (vmcommon.ReturnCode, error) { - computedFees := txProc.computeRelayedTxFees(tx, userTx) - txHash, err := txProc.processTxAtRelayer(relayerAcnt, computedFees.totalFee, computedFees.relayerFee, tx) + isUserTxOfRelayedV3 := isRelayedTxV3(tx) + relayedValue := tx.Value + if isUserTxOfRelayedV3 { + relayedValue = big.NewInt(0) + } + + computedFees := txProc.computeRelayedTxFees(tx, userTx, isUserTxOfRelayedV3) + txHash, err := txProc.processTxAtRelayer(relayerAcnt, computedFees.totalFee, computedFees.relayerFee, tx, relayedValue) if err != nil { return 0, err } @@ -613,12 +621,19 @@ func (txProc *txProcessor) finishExecutionOfRelayedTx( return vmcommon.Ok, nil } - err = txProc.addFeeAndValueToDest(acntDst, tx.Value, computedFees.remainingFee) + err = txProc.addFeeAndValueToDest(acntDst, relayedValue, computedFees.remainingFee) if err != nil { return 0, err } - return txProc.processUserTx(tx, userTx, tx.Value, tx.Nonce, txHash) + relayedNonce := tx.Nonce + relayerAddr := tx.SndAddr + if isUserTxOfRelayedV3 && !check.IfNil(relayerAcnt) { + relayedNonce = relayerAcnt.GetNonce() - 1 // nonce already increased inside processTxAtRelayer + relayerAddr = tx.RelayerAddr + } + + return txProc.processUserTx(tx, userTx, relayedValue, relayedNonce, relayerAddr, txHash) } func (txProc *txProcessor) processTxAtRelayer( @@ -626,6 +641,7 @@ func (txProc *txProcessor) processTxAtRelayer( totalFee *big.Int, relayerFee *big.Int, tx *transaction.Transaction, + valueToSubFromRelayer *big.Int, ) ([]byte, error) { txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) if err != nil { @@ -633,7 +649,7 @@ func (txProc *txProcessor) processTxAtRelayer( } if !check.IfNil(relayerAcnt) { - err = relayerAcnt.SubFromBalance(tx.GetValue()) + err = relayerAcnt.SubFromBalance(valueToSubFromRelayer) if err != nil { return nil, err } @@ -669,6 +685,37 @@ func (txProc *txProcessor) addFeeAndValueToDest(acntDst state.UserAccountHandler return txProc.accounts.SaveAccount(acntDst) } +func (txProc *txProcessor) processRelayedTxV3(tx *transaction.Transaction) (vmcommon.ReturnCode, error) { + relayerAccount, sndAccount, err := txProc.getAccounts(tx.RelayerAddr, tx.SndAddr) + if err != nil { + return 0, err + } + + if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsV3Flag) { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrRelayedTxV3Disabled) + } + + if !txProc.shardCoordinator.SameShard(tx.RelayerAddr, tx.SndAddr) { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrShardIdMissmatch) + } + + if !check.IfNil(relayerAccount) && relayerAccount.IsGuarded() { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrGuardedRelayerNotAllowed) + } + + userTx := *tx + // remove relayer addr and signature for tx type handler + userTx.RelayerAddr = nil + userTx.RelayerSignature = nil + minGasLimit := txProc.economicsFee.MinGasLimit() + userTx.GasLimit = userTx.GasLimit - minGasLimit + if userTx.GasLimit < txProc.economicsFee.ComputeGasLimit(&userTx) { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrInsufficientGasLimitInTx) + } + + return txProc.finishExecutionOfRelayedTx(relayerAccount, sndAccount, tx, &userTx) +} + func (txProc *txProcessor) processRelayedTxV2( tx *transaction.Transaction, relayerAcnt, acntDst state.UserAccountHandler, @@ -736,12 +783,17 @@ func (txProc *txProcessor) processRelayedTx( return txProc.finishExecutionOfRelayedTx(relayerAcnt, acntDst, tx, userTx) } -func (txProc *txProcessor) computeRelayedTxFees(tx, userTx *transaction.Transaction) relayedFees { +func (txProc *txProcessor) computeRelayedTxFees(tx, userTx *transaction.Transaction, isUserTxOfRelayedV3 bool) relayedFees { relayerFee := txProc.economicsFee.ComputeMoveBalanceFee(tx) totalFee := txProc.economicsFee.ComputeTxFee(tx) if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedBaseCostFlag) { userFee := txProc.computeInnerTxFeeAfterBaseCostFix(userTx) + if isUserTxOfRelayedV3 { + relayerGas := txProc.economicsFee.MinGasLimit() + relayerFee = core.SafeMul(relayerGas, tx.GasPrice) + } + totalFee = totalFee.Add(relayerFee, userFee) } remainingFee := big.NewInt(0).Sub(totalFee, relayerFee) @@ -838,10 +890,10 @@ func (txProc *txProcessor) processUserTx( userTx *transaction.Transaction, relayedTxValue *big.Int, relayedNonce uint64, + relayerAddr []byte, originalTxHash []byte, ) (vmcommon.ReturnCode, error) { - relayerAdr := originalTx.SndAddr acntSnd, acntDst, err := txProc.getAccounts(userTx.SndAddr, userTx.RcvAddr) if err != nil { errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, relayedTxValue, originalTxHash, originalTx, err) @@ -850,7 +902,7 @@ func (txProc *txProcessor) processUserTx( } return vmcommon.UserError, txProc.executeFailedRelayedUserTx( userTx, - relayerAdr, + relayerAddr, relayedTxValue, relayedNonce, originalTx, @@ -867,7 +919,7 @@ func (txProc *txProcessor) processUserTx( } return vmcommon.UserError, txProc.executeFailedRelayedUserTx( userTx, - relayerAdr, + relayerAddr, relayedTxValue, relayedNonce, originalTx, @@ -875,7 +927,7 @@ func (txProc *txProcessor) processUserTx( err.Error()) } - scrFromTx, err := txProc.makeSCRFromUserTx(userTx, relayerAdr, relayedTxValue, originalTxHash) + scrFromTx, err := txProc.makeSCRFromUserTx(userTx, relayerAddr, relayedTxValue, originalTxHash) if err != nil { return 0, err } @@ -913,7 +965,7 @@ func (txProc *txProcessor) processUserTx( } return vmcommon.UserError, txProc.executeFailedRelayedUserTx( userTx, - relayerAdr, + relayerAddr, relayedTxValue, relayedNonce, originalTx, @@ -924,7 +976,7 @@ func (txProc *txProcessor) processUserTx( if errors.Is(err, process.ErrInvalidMetaTransaction) || errors.Is(err, process.ErrAccountNotPayable) { return vmcommon.UserError, txProc.executeFailedRelayedUserTx( userTx, - relayerAdr, + relayerAddr, relayedTxValue, relayedNonce, originalTx, diff --git a/process/transaction/shardProcess_test.go b/process/transaction/shardProcess_test.go index 88797d31a0c..b6a9814a197 100644 --- a/process/transaction/shardProcess_test.go +++ b/process/transaction/shardProcess_test.go @@ -2653,6 +2653,157 @@ func TestTxProcessor_ProcessRelayedTransactionDisabled(t *testing.T) { assert.True(t, called) } +func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { + t.Parallel() + + pubKeyConverter := testscommon.NewPubkeyConverterMock(4) + + userAddr := []byte("user") + tx := &transaction.Transaction{} + tx.Nonce = 0 + tx.SndAddr = []byte("sSRC") + tx.RcvAddr = userAddr + tx.Value = big.NewInt(45) + tx.GasPrice = 1 + tx.GasLimit = 1 + tx.RelayerAddr = []byte("rela") + tx.Signature = []byte("ssig") + tx.RelayerSignature = []byte("rsig") + + acntSrc := createUserAcc(tx.SndAddr) + _ = acntSrc.AddToBalance(big.NewInt(100)) + acntDst := createUserAcc(tx.RcvAddr) + _ = acntDst.AddToBalance(big.NewInt(10)) + acntRelayer := createUserAcc(tx.RelayerAddr) + _ = acntRelayer.AddToBalance(big.NewInt(10)) + + adb := &stateMock.AccountsStub{} + adb.LoadAccountCalled = func(address []byte) (vmcommon.AccountHandler, error) { + if bytes.Equal(address, tx.SndAddr) { + return acntSrc, nil + } + if bytes.Equal(address, tx.RcvAddr) { + return acntDst, nil + } + if bytes.Equal(address, tx.RelayerAddr) { + return acntRelayer, nil + } + + return nil, errors.New("failure") + } + scProcessorMock := &testscommon.SCProcessorMock{} + shardC, _ := sharding.NewMultiShardCoordinator(1, 0) + + esdtTransferParser, _ := parsers.NewESDTTransferParser(&mock.MarshalizerMock{}) + argTxTypeHandler := coordinator.ArgNewTxTypeHandler{ + PubkeyConverter: pubKeyConverter, + ShardCoordinator: shardC, + BuiltInFunctions: builtInFunctions.NewBuiltInFunctionContainer(), + ArgumentParser: parsers.NewCallArgsParser(), + ESDTTransferParser: esdtTransferParser, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.RelayedTransactionsV3Flag), + } + txTypeHandler, _ := coordinator.NewTxTypeHandler(argTxTypeHandler) + + args := createArgsForTxProcessor() + args.Accounts = adb + args.ScProcessor = scProcessorMock + args.ShardCoordinator = shardC + args.TxTypeHandler = txTypeHandler + args.PubkeyConv = pubKeyConverter + args.ArgsParser = smartContract.NewArgumentParser() + args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.RelayedTransactionsV3Flag) + txProc, _ := txproc.NewTxProcessor(args) + require.NotNil(t, txProc) + + t.Run("should work", func(t *testing.T) { + txCopy := *tx + returnCode, err := txProc.ProcessTransaction(&txCopy) + assert.NoError(t, err) + assert.Equal(t, vmcommon.Ok, returnCode) + }) + t.Run("getAccounts error should error", func(t *testing.T) { + tx.Nonce++ + txCopy := *tx + txCopy.RelayerAddr = []byte("newR") // same length as sender + returnCode, err := txProc.ProcessTransaction(&txCopy) + assert.Error(t, err) + assert.Equal(t, vmcommon.Ok, returnCode) + }) + t.Run("flag not active should error", func(t *testing.T) { + argsCopy := args + argsCopy.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub() + txProcLocal, _ := txproc.NewTxProcessor(argsCopy) + require.NotNil(t, txProcLocal) + + txCopy := *tx + returnCode, err := txProcLocal.ProcessTransaction(&txCopy) + assert.Equal(t, process.ErrFailedTransaction, err) + assert.Equal(t, vmcommon.UserError, returnCode) + }) + t.Run("relayer not in the same shard with the sender should error", func(t *testing.T) { + argsCopy := args + argsCopy.ShardCoordinator = &mock.ShardCoordinatorStub{ + SameShardCalled: func(firstAddress, secondAddress []byte) bool { + return false + }, + } + txProcLocal, _ := txproc.NewTxProcessor(argsCopy) + require.NotNil(t, txProcLocal) + + txCopy := *tx + returnCode, err := txProcLocal.ProcessTransaction(&txCopy) + assert.Equal(t, process.ErrFailedTransaction, err) + assert.Equal(t, vmcommon.UserError, returnCode) + }) + t.Run("guarded relayer account should error", func(t *testing.T) { + acntRelayerCopy := acntRelayer + acntRelayerCopy.IsGuarded() + argsCopy := args + argsCopy.Accounts = &stateMock.AccountsStub{ + LoadAccountCalled: func(address []byte) (vmcommon.AccountHandler, error) { + if bytes.Equal(address, tx.SndAddr) { + return acntSrc, nil + } + if bytes.Equal(address, tx.RcvAddr) { + return acntDst, nil + } + if bytes.Equal(address, tx.RelayerAddr) { + return &stateMock.UserAccountStub{ + IsGuardedCalled: func() bool { + return true + }, + }, nil + } + + return nil, errors.New("failure") + }, + } + txProcLocal, _ := txproc.NewTxProcessor(argsCopy) + require.NotNil(t, txProcLocal) + + txCopy := *tx + returnCode, err := txProcLocal.ProcessTransaction(&txCopy) + assert.Equal(t, process.ErrFailedTransaction, err) + assert.Equal(t, vmcommon.UserError, returnCode) + }) + t.Run("insufficient gas limit should error", func(t *testing.T) { + txCopy := *tx + argsCopy := args + argsCopy.EconomicsFee = &economicsmocks.EconomicsHandlerStub{ + ComputeGasLimitCalled: func(tx data.TransactionWithFeeHandler) uint64 { + return txCopy.GasLimit + 1 + }, + } + txProcLocal, _ := txproc.NewTxProcessor(argsCopy) + require.NotNil(t, txProcLocal) + + returnCode, err := txProcLocal.ProcessTransaction(&txCopy) + assert.Equal(t, process.ErrFailedTransaction, err) + assert.Equal(t, vmcommon.UserError, returnCode) + }) +} + func TestTxProcessor_ConsumeMoveBalanceWithUserTx(t *testing.T) { t.Parallel() @@ -2761,7 +2912,7 @@ func TestTxProcessor_ProcessUserTxOfTypeRelayedShouldError(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) + returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, tx.SndAddr, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.UserError, returnCode) } @@ -2824,7 +2975,7 @@ func TestTxProcessor_ProcessUserTxOfTypeMoveBalanceShouldWork(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) + returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, tx.SndAddr, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.Ok, returnCode) } @@ -2887,7 +3038,7 @@ func TestTxProcessor_ProcessUserTxOfTypeSCDeploymentShouldWork(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) + returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, tx.SndAddr, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.Ok, returnCode) } @@ -2950,7 +3101,7 @@ func TestTxProcessor_ProcessUserTxOfTypeSCInvokingShouldWork(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) + returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, tx.SndAddr, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.Ok, returnCode) } @@ -3013,7 +3164,7 @@ func TestTxProcessor_ProcessUserTxOfTypeBuiltInFunctionCallShouldWork(t *testing execTx, _ := txproc.NewTxProcessor(args) - returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) + returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, tx.SndAddr, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.Ok, returnCode) } @@ -3080,7 +3231,7 @@ func TestTxProcessor_ProcessUserTxErrNotPayableShouldFailRelayTx(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) + returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, tx.SndAddr, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.UserError, returnCode) } @@ -3149,7 +3300,7 @@ func TestTxProcessor_ProcessUserTxFailedBuiltInFunctionCall(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) + returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, tx.SndAddr, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.ExecutionFailed, returnCode) } diff --git a/statusHandler/statusMetricsProvider.go b/statusHandler/statusMetricsProvider.go index 8050d335431..f068b2630f8 100644 --- a/statusHandler/statusMetricsProvider.go +++ b/statusHandler/statusMetricsProvider.go @@ -379,6 +379,7 @@ func (sm *statusMetrics) EnableEpochsMetrics() (map[string]interface{}, error) { enableEpochsMetrics[common.MetricCryptoOpcodesV2EnableEpoch] = sm.uint64Metrics[common.MetricCryptoOpcodesV2EnableEpoch] enableEpochsMetrics[common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch] = sm.uint64Metrics[common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch] enableEpochsMetrics[common.MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch] = sm.uint64Metrics[common.MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch] + enableEpochsMetrics[common.MetricRelayedTransactionsV3EnableEpoch] = sm.uint64Metrics[common.MetricRelayedTransactionsV3EnableEpoch] numNodesChangeConfig := sm.uint64Metrics[common.MetricMaxNodesChangeEnableEpoch+"_count"] diff --git a/statusHandler/statusMetricsProvider_test.go b/statusHandler/statusMetricsProvider_test.go index 14b5b5225d3..65374bee5f0 100644 --- a/statusHandler/statusMetricsProvider_test.go +++ b/statusHandler/statusMetricsProvider_test.go @@ -402,6 +402,7 @@ func TestStatusMetrics_EnableEpochMetrics(t *testing.T) { sm.SetUInt64Value(common.MetricCryptoOpcodesV2EnableEpoch, uint64(4)) sm.SetUInt64Value(common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch, uint64(4)) sm.SetUInt64Value(common.MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch, uint64(4)) + sm.SetUInt64Value(common.MetricRelayedTransactionsV3EnableEpoch, uint64(4)) maxNodesChangeConfig := []map[string]uint64{ { @@ -533,6 +534,7 @@ func TestStatusMetrics_EnableEpochMetrics(t *testing.T) { common.MetricCryptoOpcodesV2EnableEpoch: uint64(4), common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch: uint64(4), common.MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch: uint64(4), + common.MetricRelayedTransactionsV3EnableEpoch: uint64(4), common.MetricMaxNodesChangeEnableEpoch: []map[string]interface{}{ { From 905bd78383f2813229c46d7e8b62cf63bd6c5aee Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 29 Oct 2024 16:06:36 +0200 Subject: [PATCH 02/74] update deps after merge --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 75a2eee7f19..8a697fc5064 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.1-0.20241021133229-d0833256e3ec - github.com/multiversx/mx-chain-core-go v1.2.23-0.20241018134424-75bab2a9058c + github.com/multiversx/mx-chain-core-go v1.2.23-0.20241029140551-8ed69b598c83 github.com/multiversx/mx-chain-crypto-go v1.2.12 github.com/multiversx/mx-chain-es-indexer-go v1.7.10-0.20241018130218-f48c7282690b github.com/multiversx/mx-chain-logger-go v1.0.15 diff --git a/go.sum b/go.sum index 4de240abdf8..71ca81946b8 100644 --- a/go.sum +++ b/go.sum @@ -387,8 +387,8 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.1-0.20241021133229-d0833256e3ec h1:KwpeVZXSHzic8DV9zaJZmaBgDNIIpSdbGz4Q+9fZyiI= github.com/multiversx/mx-chain-communication-go v1.1.1-0.20241021133229-d0833256e3ec/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.23-0.20241018134424-75bab2a9058c h1:hPCfMSj2vd9xNkARNxB1b3b9k8taFb+Xfja+WK97jno= -github.com/multiversx/mx-chain-core-go v1.2.23-0.20241018134424-75bab2a9058c/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.23-0.20241029140551-8ed69b598c83 h1:p9nCldwfWSQrvPjDQpeFwNxMxPW1NxreD967S0lT6vs= +github.com/multiversx/mx-chain-core-go v1.2.23-0.20241029140551-8ed69b598c83/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= github.com/multiversx/mx-chain-es-indexer-go v1.7.10-0.20241018130218-f48c7282690b h1:GYvm0yGkdQ3OCfNqnyIQNzAzydN3cES8noJZ3eZHN1A= From a36e68cd9629c7aa1476fa86c72ca712c906de55 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 29 Oct 2024 17:02:00 +0200 Subject: [PATCH 03/74] small fix + fix tests --- cmd/node/config/config.toml | 2 +- cmd/node/config/enableEpochs.toml | 4 ++-- process/transaction/baseProcess.go | 15 ++++++++++----- process/transaction/shardProcess_test.go | 13 +++++-------- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/cmd/node/config/config.toml b/cmd/node/config/config.toml index 6e1205d5f7e..95c91cbde1b 100644 --- a/cmd/node/config/config.toml +++ b/cmd/node/config/config.toml @@ -623,7 +623,7 @@ [EpochStartConfig] GenesisEpoch = 0 MinRoundsBetweenEpochs = 20 - RoundsPerEpoch = 200 + RoundsPerEpoch = 20 # Min and Max ShuffledOutRestartThreshold represents the minimum and maximum duration of an epoch (in percentage) after a node which # has been shuffled out has to restart its process in order to start in a new shard MinShuffledOutRestartThreshold = 0.05 diff --git a/cmd/node/config/enableEpochs.toml b/cmd/node/config/enableEpochs.toml index 0b45c059ef1..74e5c734e38 100644 --- a/cmd/node/config/enableEpochs.toml +++ b/cmd/node/config/enableEpochs.toml @@ -325,7 +325,7 @@ UnJailCleanupEnableEpoch = 4 # FixRelayedBaseCostEnableEpoch represents the epoch when the fix for relayed base cost will be enabled - FixRelayedBaseCostEnableEpoch = 4 + FixRelayedBaseCostEnableEpoch = 1 # MultiESDTNFTTransferAndExecuteByUserEnableEpoch represents the epoch when enshrined sovereign cross chain opcodes are enabled MultiESDTNFTTransferAndExecuteByUserEnableEpoch = 9999999 @@ -334,7 +334,7 @@ FixRelayedMoveBalanceToNonPayableSCEnableEpoch = 4 # RelayedTransactionsV3 represents the epoch when the relayed transactions v3 will be enabled - RelayedTransactionsV3 = 5 + RelayedTransactionsV3 = 1 # BLSMultiSignerEnableEpoch represents the activation epoch for different types of BLS multi-signers BLSMultiSignerEnableEpoch = [ diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 72ae41a3bd6..4ead73d6031 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -152,11 +152,16 @@ func (txProc *baseTxProcessor) checkTxValues( txFee = txProc.economicsFee.ComputeTxFee(tx) } - feePayer, err := txProc.getFeePayer(tx, acntSnd) + feePayer, isRelayedV3, err := txProc.getFeePayer(tx, acntSnd) if err != nil { return err } + // early exit for relayed v3, the cost will be compared with the sender balance + if isRelayedV3 { + return nil + } + if feePayer.GetBalance().Cmp(txFee) < 0 { return fmt.Errorf("%w, has: %s, wanted: %s", process.ErrInsufficientFee, @@ -182,17 +187,17 @@ func (txProc *baseTxProcessor) checkTxValues( func (txProc *baseTxProcessor) getFeePayer( tx *transaction.Transaction, acntSnd state.UserAccountHandler, -) (state.UserAccountHandler, error) { +) (state.UserAccountHandler, bool, error) { if !isRelayedTxV3(tx) { - return acntSnd, nil + return acntSnd, false, nil } acntRelayer, _, err := txProc.getAccounts(tx.RelayerAddr, tx.RelayerAddr) if err != nil { - return nil, err + return nil, true, err } - return acntRelayer, nil + return acntRelayer, true, nil } func (txProc *baseTxProcessor) computeInnerTxFee(tx *transaction.Transaction) *big.Int { diff --git a/process/transaction/shardProcess_test.go b/process/transaction/shardProcess_test.go index b6a9814a197..c8cf116fa4e 100644 --- a/process/transaction/shardProcess_test.go +++ b/process/transaction/shardProcess_test.go @@ -2718,18 +2718,11 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { t.Run("should work", func(t *testing.T) { txCopy := *tx + txCopy.Nonce = acntSrc.GetNonce() returnCode, err := txProc.ProcessTransaction(&txCopy) assert.NoError(t, err) assert.Equal(t, vmcommon.Ok, returnCode) }) - t.Run("getAccounts error should error", func(t *testing.T) { - tx.Nonce++ - txCopy := *tx - txCopy.RelayerAddr = []byte("newR") // same length as sender - returnCode, err := txProc.ProcessTransaction(&txCopy) - assert.Error(t, err) - assert.Equal(t, vmcommon.Ok, returnCode) - }) t.Run("flag not active should error", func(t *testing.T) { argsCopy := args argsCopy.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub() @@ -2737,6 +2730,7 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { require.NotNil(t, txProcLocal) txCopy := *tx + txCopy.Nonce = acntSrc.GetNonce() returnCode, err := txProcLocal.ProcessTransaction(&txCopy) assert.Equal(t, process.ErrFailedTransaction, err) assert.Equal(t, vmcommon.UserError, returnCode) @@ -2752,6 +2746,7 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { require.NotNil(t, txProcLocal) txCopy := *tx + txCopy.Nonce = acntSrc.GetNonce() returnCode, err := txProcLocal.ProcessTransaction(&txCopy) assert.Equal(t, process.ErrFailedTransaction, err) assert.Equal(t, vmcommon.UserError, returnCode) @@ -2783,12 +2778,14 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { require.NotNil(t, txProcLocal) txCopy := *tx + txCopy.Nonce = acntSrc.GetNonce() returnCode, err := txProcLocal.ProcessTransaction(&txCopy) assert.Equal(t, process.ErrFailedTransaction, err) assert.Equal(t, vmcommon.UserError, returnCode) }) t.Run("insufficient gas limit should error", func(t *testing.T) { txCopy := *tx + txCopy.Nonce = acntSrc.GetNonce() argsCopy := args argsCopy.EconomicsFee = &economicsmocks.EconomicsHandlerStub{ ComputeGasLimitCalled: func(tx data.TransactionWithFeeHandler) uint64 { From ab06f0bca21a726a63809d5a41910fb2555e0db6 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Wed, 30 Oct 2024 11:30:36 +0200 Subject: [PATCH 04/74] revert config values modified for local tests --- cmd/node/config/config.toml | 2 +- cmd/node/config/enableEpochs.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/node/config/config.toml b/cmd/node/config/config.toml index 95c91cbde1b..6e1205d5f7e 100644 --- a/cmd/node/config/config.toml +++ b/cmd/node/config/config.toml @@ -623,7 +623,7 @@ [EpochStartConfig] GenesisEpoch = 0 MinRoundsBetweenEpochs = 20 - RoundsPerEpoch = 20 + RoundsPerEpoch = 200 # Min and Max ShuffledOutRestartThreshold represents the minimum and maximum duration of an epoch (in percentage) after a node which # has been shuffled out has to restart its process in order to start in a new shard MinShuffledOutRestartThreshold = 0.05 diff --git a/cmd/node/config/enableEpochs.toml b/cmd/node/config/enableEpochs.toml index 74e5c734e38..0b45c059ef1 100644 --- a/cmd/node/config/enableEpochs.toml +++ b/cmd/node/config/enableEpochs.toml @@ -325,7 +325,7 @@ UnJailCleanupEnableEpoch = 4 # FixRelayedBaseCostEnableEpoch represents the epoch when the fix for relayed base cost will be enabled - FixRelayedBaseCostEnableEpoch = 1 + FixRelayedBaseCostEnableEpoch = 4 # MultiESDTNFTTransferAndExecuteByUserEnableEpoch represents the epoch when enshrined sovereign cross chain opcodes are enabled MultiESDTNFTTransferAndExecuteByUserEnableEpoch = 9999999 @@ -334,7 +334,7 @@ FixRelayedMoveBalanceToNonPayableSCEnableEpoch = 4 # RelayedTransactionsV3 represents the epoch when the relayed transactions v3 will be enabled - RelayedTransactionsV3 = 1 + RelayedTransactionsV3 = 5 # BLSMultiSignerEnableEpoch represents the activation epoch for different types of BLS multi-signers BLSMultiSignerEnableEpoch = [ From 09a2751f5715f799a8cb0edf9568b51d57a4ef1f Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Wed, 30 Oct 2024 14:08:54 +0200 Subject: [PATCH 05/74] guarded integration tests --- .../relayedTx/relayedTx_test.go | 69 ++++++++++++++++--- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index 7021133fddd..eabad3d708a 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -34,6 +34,8 @@ const ( mockRelayerTxSignature = "rsig" maxNumOfBlocksToGenerateWhenExecutingTx = 10 roundsPerEpoch = 30 + guardAccountCost = 250_000 + extraGasLimitForGuarded = minGasLimit ) var ( @@ -41,10 +43,12 @@ var ( ) func TestRelayedV3WithChainSimulator(t *testing.T) { - t.Run("successful intra shard move balance with exact gas", testRelayedV3MoveBalance(0, 0, false)) - t.Run("successful intra shard move balance with extra gas", testRelayedV3MoveBalance(0, 0, true)) - t.Run("successful cross shard move balance with exact gas", testRelayedV3MoveBalance(0, 1, false)) - t.Run("successful cross shard move balance with extra gas", testRelayedV3MoveBalance(0, 1, true)) + t.Run("successful intra shard move balance", testRelayedV3MoveBalance(0, 0, false, false)) + t.Run("successful intra shard guarded move balance", testRelayedV3MoveBalance(0, 0, false, true)) + t.Run("successful intra shard move balance with extra gas", testRelayedV3MoveBalance(0, 0, true, false)) + t.Run("successful cross shard move balance", testRelayedV3MoveBalance(0, 1, false, false)) + t.Run("successful cross shard guarded move balance", testRelayedV3MoveBalance(0, 1, false, true)) + t.Run("successful cross shard move balance with extra gas", testRelayedV3MoveBalance(0, 1, true, false)) t.Run("intra shard move balance, lower nonce", testRelayedV3MoveBalanceLowerNonce(0, 0)) t.Run("cross shard move balance, lower nonce", testRelayedV3MoveBalanceLowerNonce(0, 1)) t.Run("intra shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 0)) @@ -62,6 +66,7 @@ func testRelayedV3MoveBalance( relayerShard uint32, destinationShard uint32, extraGas bool, + guardedTx bool, ) func(t *testing.T) { return func(t *testing.T) { if testing.Short() { @@ -87,22 +92,59 @@ func testRelayedV3MoveBalance( receiver, err := cs.GenerateAndMintWalletAddress(destinationShard, big.NewInt(0)) require.NoError(t, err) + guardian, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + // generate one block so the minting has effect err = cs.GenerateBlocks(1) require.NoError(t, err) + senderNonce := uint64(0) + if guardedTx { + // Set guardian for sender + setGuardianTxData := "SetGuardian@" + hex.EncodeToString(guardian.Bytes) + "@" + hex.EncodeToString([]byte("uuid")) + setGuardianGasLimit := minGasLimit + 1500*len(setGuardianTxData) + guardAccountCost + setGuardianTx := generateTransaction(sender.Bytes, senderNonce, sender.Bytes, big.NewInt(0), setGuardianTxData, uint64(setGuardianGasLimit)) + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(setGuardianTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + senderNonce++ + + // fast-forward until the guardian becomes active + err = cs.GenerateBlocks(roundsPerEpoch * 20) + require.NoError(t, err) + + // guard account + guardAccountTxData := "GuardAccount" + guardAccountGasLimit := minGasLimit + 1500*len(guardAccountTxData) + guardAccountCost + guardAccountTx := generateTransaction(sender.Bytes, senderNonce, sender.Bytes, big.NewInt(0), guardAccountTxData, uint64(guardAccountGasLimit)) + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(guardAccountTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + senderNonce++ + } + + senderBalanceBefore := getBalance(t, cs, sender) + gasLimit := minGasLimit * 2 extraGasLimit := 0 if extraGas { extraGasLimit = minGasLimit } - relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, receiver.Bytes, relayer.Bytes, oneEGLD, "", uint64(gasLimit+extraGasLimit)) + if guardedTx { + gasLimit += extraGasLimitForGuarded + } + relayedTx := generateRelayedV3Transaction(sender.Bytes, senderNonce, receiver.Bytes, relayer.Bytes, oneEGLD, "", uint64(gasLimit+extraGasLimit)) + + if guardedTx { + relayedTx.GuardianAddr = guardian.Bytes + relayedTx.GuardianSignature = []byte(mockTxSignature) + relayedTx.Options = 2 + } result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) require.NoError(t, err) // check fee fields - initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, big.NewInt(0), true) + initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, big.NewInt(0), true, guardedTx) require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) require.Equal(t, fee.String(), result.Fee) require.Equal(t, gasUsed, result.GasUsed) @@ -114,7 +156,7 @@ func testRelayedV3MoveBalance( // check sender balance senderBalanceAfter := getBalance(t, cs, sender) - senderBalanceDiff := big.NewInt(0).Sub(initialBalance, senderBalanceAfter) + senderBalanceDiff := big.NewInt(0).Sub(senderBalanceBefore, senderBalanceAfter) require.Equal(t, oneEGLD.String(), senderBalanceDiff.String()) // check receiver balance @@ -283,7 +325,7 @@ func testRelayedV3ScCall( require.NotZero(t, refundValue.Uint64()) // check fee fields - initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, refundValue, false) + initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, refundValue, false, false) require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) require.Equal(t, fee.String(), result.Fee) require.Equal(t, gasUsed, result.GasUsed) @@ -298,7 +340,7 @@ func testRelayedV3ScCall( require.Equal(t, initialBalance.String(), senderBalanceAfter.String()) // check owner balance - _, feeDeploy, _ := computeTxGasAndFeeBasedOnRefund(resultDeploy, refundDeploy, false) + _, feeDeploy, _ := computeTxGasAndFeeBasedOnRefund(resultDeploy, refundDeploy, false, false) ownerBalanceAfter := getBalance(t, cs, owner) ownerFee := big.NewInt(0).Sub(initialBalance, ownerBalanceAfter) require.Equal(t, feeDeploy.String(), ownerFee.String()) @@ -375,7 +417,7 @@ func testRelayedV3ScCallInvalidGasLimit( require.Zero(t, refundValue.Uint64()) // check fee fields, should consume full gas - initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, refundValue, false) + initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, refundValue, false, false) require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) require.Equal(t, fee.String(), result.Fee) require.Equal(t, result.InitiallyPaidFee, result.Fee) @@ -457,7 +499,7 @@ func testRelayedV3ScCallInvalidMethod( require.Zero(t, refundValue.Uint64()) // no refund, tx failed // check fee fields, should consume full gas - initiallyPaidFee, fee, _ := computeTxGasAndFeeBasedOnRefund(result, refundValue, false) + initiallyPaidFee, fee, _ := computeTxGasAndFeeBasedOnRefund(result, refundValue, false, false) require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) // check relayer balance @@ -825,11 +867,16 @@ func computeTxGasAndFeeBasedOnRefund( result *transaction.ApiTransactionResult, refund *big.Int, isMoveBalance bool, + guardedTx bool, ) (*big.Int, *big.Int, uint64) { deductedGasPrice := uint64(minGasPrice / deductionFactor) initialTx := result.Tx gasForFullPrice := uint64(minGasLimit + gasPerDataByte*len(initialTx.GetData())) + if guardedTx { + gasForFullPrice += extraGasLimitForGuarded + } + if result.ProcessingTypeOnSource == process.RelayedTxV3.String() { gasForFullPrice += uint64(minGasLimit) // relayer fee } From 68dbf896b52636ecda7a6d9e6a730a0094875121 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 11 Nov 2024 13:10:37 +0200 Subject: [PATCH 06/74] fixes after review --- common/common.go | 14 +++++++ common/common_test.go | 41 +++++++++++++++++++ .../multiShard/relayedTx/common.go | 1 - .../transactionsFeeProcessor.go | 9 +--- process/coordinator/transactionType.go | 10 +---- process/dataValidators/txValidator.go | 30 ++++++-------- process/economics/economicsData.go | 16 +++++--- process/transaction/baseProcess.go | 12 +++--- process/transaction/interceptedTransaction.go | 10 ++--- process/transaction/shardProcess.go | 16 ++++++-- process/transaction/shardProcess_test.go | 1 + 11 files changed, 103 insertions(+), 57 deletions(-) create mode 100644 common/common.go create mode 100644 common/common_test.go diff --git a/common/common.go b/common/common.go new file mode 100644 index 00000000000..9c32a9bf2e7 --- /dev/null +++ b/common/common.go @@ -0,0 +1,14 @@ +package common + +import "github.com/multiversx/mx-chain-core-go/data" + +// IsRelayedTxV3 returns true if the provided transaction is of type relayed v3 +func IsRelayedTxV3(tx data.TransactionHandler) bool { + relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler) + if !isRelayedV3 { + return false + } + hasValidRelayer := len(relayedTx.GetRelayerAddr()) == len(tx.GetSndAddr()) && len(relayedTx.GetRelayerAddr()) > 0 + hasValidRelayerSignature := len(relayedTx.GetRelayerSignature()) == len(relayedTx.GetSignature()) && len(relayedTx.GetRelayerSignature()) > 0 + return hasValidRelayer && hasValidRelayerSignature +} diff --git a/common/common_test.go b/common/common_test.go new file mode 100644 index 00000000000..9e44ec87e9f --- /dev/null +++ b/common/common_test.go @@ -0,0 +1,41 @@ +package common + +import ( + "math/big" + "testing" + + "github.com/multiversx/mx-chain-core-go/data/smartContractResult" + "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/stretchr/testify/require" +) + +func TestIsRelayedTxV3(t *testing.T) { + t.Parallel() + + scr := &smartContractResult.SmartContractResult{} + require.False(t, IsRelayedTxV3(scr)) + + notRelayedTxV3 := &transaction.Transaction{ + Nonce: 1, + Value: big.NewInt(100), + RcvAddr: []byte("receiver"), + SndAddr: []byte("sender0"), + GasPrice: 100, + GasLimit: 10, + Signature: []byte("signature"), + } + require.False(t, IsRelayedTxV3(notRelayedTxV3)) + + relayedTxV3 := &transaction.Transaction{ + Nonce: 1, + Value: big.NewInt(100), + RcvAddr: []byte("receiver"), + SndAddr: []byte("sender1"), + GasPrice: 100, + GasLimit: 10, + Signature: []byte("signature"), + RelayerAddr: []byte("relayer"), + RelayerSignature: []byte("signature"), + } + require.True(t, IsRelayedTxV3(relayedTxV3)) +} diff --git a/integrationTests/multiShard/relayedTx/common.go b/integrationTests/multiShard/relayedTx/common.go index b50874f8763..26fd6ea0692 100644 --- a/integrationTests/multiShard/relayedTx/common.go +++ b/integrationTests/multiShard/relayedTx/common.go @@ -262,7 +262,6 @@ func createRelayedTxV3( player.Nonce++ player.Balance.Sub(player.Balance, value) - relayer.Nonce++ txFee := economicsFee.ComputeTxFee(tx) relayer.Balance.Sub(relayer.Balance, txFee) diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index 8dfaa1bf338..4fe57119814 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -271,15 +271,8 @@ func (tep *transactionsFeeProcessor) setGasUsedAndFeeBasedOnRefundValue( refund *big.Int, epoch uint32, ) { - tx := txWithResults.GetTxHandler() - relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler) - if isRelayedV3 { - hasValidRelayer := len(relayedTx.GetRelayerAddr()) == len(tx.GetSndAddr()) && len(relayedTx.GetRelayerAddr()) > 0 - hasValidRelayerSignature := len(relayedTx.GetRelayerSignature()) == len(relayedTx.GetSignature()) && len(relayedTx.GetRelayerSignature()) > 0 - isRelayedV3 = hasValidRelayer && hasValidRelayerSignature - } isValidUserTxAfterBaseCostActivation := !check.IfNilReflect(userTx) && tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) - if isValidUserTxAfterBaseCostActivation && !isRelayedV3 { + if isValidUserTxAfterBaseCostActivation && !common.IsRelayedTxV3(txWithResults.GetTxHandler()) { gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(userTx, refund) tx := txWithResults.GetTxHandler() diff --git a/process/coordinator/transactionType.go b/process/coordinator/transactionType.go index dd648a4dd54..5d195c70b2c 100644 --- a/process/coordinator/transactionType.go +++ b/process/coordinator/transactionType.go @@ -83,14 +83,8 @@ func (tth *txTypeHandler) ComputeTransactionType(tx data.TransactionHandler) (pr return process.InvalidTransaction, process.InvalidTransaction } - relayedTxV3, ok := tx.(data.RelayedTransactionHandler) - if ok { - hasValidRelayer := len(relayedTxV3.GetRelayerAddr()) == len(tx.GetSndAddr()) && len(relayedTxV3.GetRelayerAddr()) > 0 - hasValidRelayerSignature := len(relayedTxV3.GetRelayerSignature()) == len(relayedTxV3.GetSignature()) && len(relayedTxV3.GetRelayerSignature()) > 0 - isRelayedV3 := hasValidRelayer && hasValidRelayerSignature - if isRelayedV3 { - return process.RelayedTxV3, process.RelayedTxV3 - } + if common.IsRelayedTxV3(tx) { + return process.RelayedTxV3, process.RelayedTxV3 } isEmptyAddress := tth.isDestAddressEmpty(tx) diff --git a/process/dataValidators/txValidator.go b/process/dataValidators/txValidator.go index b95c1bca2b7..1e0c67ee007 100644 --- a/process/dataValidators/txValidator.go +++ b/process/dataValidators/txValidator.go @@ -6,6 +6,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/check" "github.com/multiversx/mx-chain-core-go/data" + "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/state" @@ -108,24 +109,19 @@ func (txv *txValidator) getFeePayerAccount( payerAccount := accountHandler tx := interceptedTx.Transaction() - relayedTx, ok := tx.(data.RelayedTransactionHandler) - if ok { - hasValidRelayer := len(relayedTx.GetRelayerAddr()) == len(tx.GetSndAddr()) && len(relayedTx.GetRelayerAddr()) > 0 - hasValidRelayerSignature := len(relayedTx.GetRelayerSignature()) == len(relayedTx.GetSignature()) && len(relayedTx.GetRelayerSignature()) > 0 - isRelayedV3 := hasValidRelayer && hasValidRelayerSignature - if isRelayedV3 { - payerAddress = relayedTx.GetRelayerAddr() - relayerAccount, err := txv.accounts.GetExistingAccount(payerAddress) - if err != nil { - return nil, fmt.Errorf("%w for address %s and shard %d, err: %s", - process.ErrAccountNotFound, - txv.pubKeyConverter.SilentEncode(payerAddress, log), - txv.shardCoordinator.SelfId(), - err.Error(), - ) - } - payerAccount = relayerAccount + if common.IsRelayedTxV3(tx) { + relayedTx := tx.(data.RelayedTransactionHandler) + payerAddress = relayedTx.GetRelayerAddr() + relayerAccount, err := txv.accounts.GetExistingAccount(payerAddress) + if err != nil { + return nil, fmt.Errorf("%w for address %s and shard %d, err: %s", + process.ErrAccountNotFound, + txv.pubKeyConverter.SilentEncode(payerAddress, log), + txv.shardCoordinator.SelfId(), + err.Error(), + ) } + payerAccount = relayerAccount } account, ok := payerAccount.(state.UserAccountHandler) if !ok { diff --git a/process/economics/economicsData.go b/process/economics/economicsData.go index 4da39f94862..dfce9d5a6f6 100644 --- a/process/economics/economicsData.go +++ b/process/economics/economicsData.go @@ -500,12 +500,7 @@ func (ed *economicsData) ComputeGasLimitInEpoch(tx data.TransactionWithFeeHandle gasLimit += ed.getExtraGasLimitGuardedTx(epoch) } - hasValidRelayer := len(txInstance.GetRelayerAddr()) == len(txInstance.GetSndAddr()) && len(txInstance.GetRelayerAddr()) > 0 - hasValidRelayerSignature := len(txInstance.GetRelayerSignature()) == len(txInstance.GetSignature()) && len(txInstance.GetRelayerSignature()) > 0 - isRelayedV3 := hasValidRelayer && hasValidRelayerSignature - if isRelayedV3 { - gasLimit += ed.MinGasLimitInEpoch(epoch) - } + gasLimit += ed.getExtraGasLimitRelayedTx(txInstance, epoch) } return gasLimit @@ -614,6 +609,15 @@ func (ed *economicsData) ComputeGasLimitBasedOnBalanceInEpoch(tx data.Transactio return totalGasLimit, nil } +// getExtraGasLimitRelayedTx returns extra gas limit for relayed tx in a specific epoch +func (ed *economicsData) getExtraGasLimitRelayedTx(txInstance *transaction.Transaction, epoch uint32) uint64 { + if common.IsRelayedTxV3(txInstance) { + return ed.MinGasLimitInEpoch(epoch) + } + + return 0 +} + // IsInterfaceNil returns true if there is no value under the interface func (ed *economicsData) IsInterfaceNil() bool { return ed == nil diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 4ead73d6031..d480ec22b51 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -157,11 +157,6 @@ func (txProc *baseTxProcessor) checkTxValues( return err } - // early exit for relayed v3, the cost will be compared with the sender balance - if isRelayedV3 { - return nil - } - if feePayer.GetBalance().Cmp(txFee) < 0 { return fmt.Errorf("%w, has: %s, wanted: %s", process.ErrInsufficientFee, @@ -176,6 +171,11 @@ func (txProc *baseTxProcessor) checkTxValues( txFee = core.SafeMul(tx.GasLimit, tx.GasPrice) } + // early exit for relayed v3, the cost will be compared with the sender balance + if isRelayedV3 { + return nil + } + cost := big.NewInt(0).Add(txFee, tx.Value) if feePayer.GetBalance().Cmp(cost) < 0 { return process.ErrInsufficientFunds @@ -188,7 +188,7 @@ func (txProc *baseTxProcessor) getFeePayer( tx *transaction.Transaction, acntSnd state.UserAccountHandler, ) (state.UserAccountHandler, bool, error) { - if !isRelayedTxV3(tx) { + if !common.IsRelayedTxV3(tx) { return acntSnd, false, nil } diff --git a/process/transaction/interceptedTransaction.go b/process/transaction/interceptedTransaction.go index 890939b621d..9afe05c02f3 100644 --- a/process/transaction/interceptedTransaction.go +++ b/process/transaction/interceptedTransaction.go @@ -13,6 +13,7 @@ import ( "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" "github.com/multiversx/mx-chain-crypto-go" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/sharding" logger "github.com/multiversx/mx-chain-logger-go" @@ -211,7 +212,7 @@ func (inTx *InterceptedTransaction) CheckValidity() error { } func (inTx *InterceptedTransaction) checkRecursiveRelayed(userTx *transaction.Transaction) error { - if isRelayedTxV3(userTx) { + if common.IsRelayedTxV3(userTx) { return process.ErrRecursiveRelayedTxIsNotAllowed } @@ -232,13 +233,8 @@ func isRelayedTx(funcName string) bool { core.RelayedTransactionV2 == funcName } -func isRelayedTxV3(tx *transaction.Transaction) bool { - return len(tx.RelayerAddr) == len(tx.SndAddr) && len(tx.RelayerAddr) > 0 && - len(tx.RelayerSignature) == len(tx.Signature) && len(tx.RelayerSignature) > 0 -} - func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transaction) error { - if !isRelayedTxV3(tx) { + if !common.IsRelayedTxV3(tx) { return nil } diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 81fd8dac766..6637a8466d2 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -605,14 +605,20 @@ func (txProc *txProcessor) finishExecutionOfRelayedTx( tx *transaction.Transaction, userTx *transaction.Transaction, ) (vmcommon.ReturnCode, error) { - isUserTxOfRelayedV3 := isRelayedTxV3(tx) + isUserTxOfRelayedV3 := common.IsRelayedTxV3(tx) relayedValue := tx.Value if isUserTxOfRelayedV3 { relayedValue = big.NewInt(0) } computedFees := txProc.computeRelayedTxFees(tx, userTx, isUserTxOfRelayedV3) - txHash, err := txProc.processTxAtRelayer(relayerAcnt, computedFees.totalFee, computedFees.relayerFee, tx, relayedValue) + txHash, err := txProc.processTxAtRelayer( + relayerAcnt, + computedFees.totalFee, + computedFees.relayerFee, + tx, + relayedValue, + isUserTxOfRelayedV3) if err != nil { return 0, err } @@ -629,7 +635,6 @@ func (txProc *txProcessor) finishExecutionOfRelayedTx( relayedNonce := tx.Nonce relayerAddr := tx.SndAddr if isUserTxOfRelayedV3 && !check.IfNil(relayerAcnt) { - relayedNonce = relayerAcnt.GetNonce() - 1 // nonce already increased inside processTxAtRelayer relayerAddr = tx.RelayerAddr } @@ -642,6 +647,7 @@ func (txProc *txProcessor) processTxAtRelayer( relayerFee *big.Int, tx *transaction.Transaction, valueToSubFromRelayer *big.Int, + isUserTxOfRelayedV3 bool, ) ([]byte, error) { txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) if err != nil { @@ -659,7 +665,9 @@ func (txProc *txProcessor) processTxAtRelayer( return nil, err } - relayerAcnt.IncreaseNonce(1) + if !isUserTxOfRelayedV3 { // won't increase relayer nonce for v3 + relayerAcnt.IncreaseNonce(1) + } err = txProc.accounts.SaveAccount(relayerAcnt) if err != nil { return nil, err diff --git a/process/transaction/shardProcess_test.go b/process/transaction/shardProcess_test.go index c8cf116fa4e..c278b83c80b 100644 --- a/process/transaction/shardProcess_test.go +++ b/process/transaction/shardProcess_test.go @@ -2768,6 +2768,7 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { IsGuardedCalled: func() bool { return true }, + Balance: big.NewInt(1), }, nil } From 531aad5fefe9ca88daf115aebc40136b44cba949 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 11 Nov 2024 13:12:47 +0200 Subject: [PATCH 07/74] deps update --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 8a697fc5064..4ea01439b9c 100644 --- a/go.mod +++ b/go.mod @@ -14,10 +14,10 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 - github.com/multiversx/mx-chain-communication-go v1.1.1-0.20241021133229-d0833256e3ec - github.com/multiversx/mx-chain-core-go v1.2.23-0.20241029140551-8ed69b598c83 + github.com/multiversx/mx-chain-communication-go v1.1.1 + github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.10-0.20241018130218-f48c7282690b + github.com/multiversx/mx-chain-es-indexer-go v1.7.10 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 github.com/multiversx/mx-chain-storage-go v1.0.16 diff --git a/go.sum b/go.sum index 71ca81946b8..2982014a282 100644 --- a/go.sum +++ b/go.sum @@ -385,14 +385,14 @@ github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/n github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUYwbO0993uPI= github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= -github.com/multiversx/mx-chain-communication-go v1.1.1-0.20241021133229-d0833256e3ec h1:KwpeVZXSHzic8DV9zaJZmaBgDNIIpSdbGz4Q+9fZyiI= -github.com/multiversx/mx-chain-communication-go v1.1.1-0.20241021133229-d0833256e3ec/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.23-0.20241029140551-8ed69b598c83 h1:p9nCldwfWSQrvPjDQpeFwNxMxPW1NxreD967S0lT6vs= -github.com/multiversx/mx-chain-core-go v1.2.23-0.20241029140551-8ed69b598c83/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-communication-go v1.1.1 h1:y4DoQeQOJTaSUsRzczQFazf8JYQmInddypApqA3AkwM= +github.com/multiversx/mx-chain-communication-go v1.1.1/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83 h1:VuFFYZ9hpMacAcqcKM0hg6j4D16qKAGihi3X6PaF8qs= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.10-0.20241018130218-f48c7282690b h1:GYvm0yGkdQ3OCfNqnyIQNzAzydN3cES8noJZ3eZHN1A= -github.com/multiversx/mx-chain-es-indexer-go v1.7.10-0.20241018130218-f48c7282690b/go.mod h1:oGcRK2E3Syv6vRTszWrrb/TqD8akq0yeoMr1wPPiTO4= +github.com/multiversx/mx-chain-es-indexer-go v1.7.10 h1:Umi7WN8h4BOXLw7CM3VgvaWkLGef7nXtaPIGbjBCT3U= +github.com/multiversx/mx-chain-es-indexer-go v1.7.10/go.mod h1:oGcRK2E3Syv6vRTszWrrb/TqD8akq0yeoMr1wPPiTO4= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= From 86aaa3977c15d81bccc615ed54dec6e4399a141d Mon Sep 17 00:00:00 2001 From: axenteoctavian Date: Tue, 12 Nov 2024 18:09:11 +0200 Subject: [PATCH 08/74] implemented override with array of string and int --- common/reflectcommon/structFieldsUpdate.go | 12 ++- .../reflectcommon/structFieldsUpdate_test.go | 81 ++++++++++++++++++- testscommon/toml/config.go | 7 ++ testscommon/toml/config.toml | 4 + testscommon/toml/overwrite.toml | 79 +++++++++--------- 5 files changed, 138 insertions(+), 45 deletions(-) diff --git a/common/reflectcommon/structFieldsUpdate.go b/common/reflectcommon/structFieldsUpdate.go index be8671eff4f..4e70a0d3728 100644 --- a/common/reflectcommon/structFieldsUpdate.go +++ b/common/reflectcommon/structFieldsUpdate.go @@ -122,7 +122,7 @@ func trySetTheNewValue(value *reflect.Value, newValue interface{}) error { case reflect.Struct: structVal := reflect.ValueOf(newValue) - return trySetStructValue(value, structVal) + return trySetItemValue(value, structVal) case reflect.Map: mapValue := reflect.ValueOf(newValue) @@ -141,7 +141,7 @@ func trySetSliceValue(value *reflect.Value, newValue interface{}) error { item := sliceVal.Index(i) newItem := reflect.New(value.Type().Elem()).Elem() - err := trySetStructValue(&newItem, item) + err := trySetItemValue(&newItem, item) if err != nil { return err } @@ -154,7 +154,7 @@ func trySetSliceValue(value *reflect.Value, newValue interface{}) error { return nil } -func trySetStructValue(value *reflect.Value, newValue reflect.Value) error { +func trySetItemValue(value *reflect.Value, newValue reflect.Value) error { switch newValue.Kind() { case reflect.Invalid: return fmt.Errorf("invalid new value kind") @@ -162,6 +162,12 @@ func trySetStructValue(value *reflect.Value, newValue reflect.Value) error { return updateStructFromMap(value, newValue) case reflect.Struct: // overwrite with go struct return updateStructFromStruct(value, newValue) + case reflect.Interface: + return trySetTheNewValue(value, newValue.Interface()) + case reflect.String: + return trySetTheNewValue(value, newValue.Interface()) + case reflect.Int: + return trySetTheNewValue(value, newValue.Interface()) default: return fmt.Errorf("unsupported type <%s> when trying to set the value of type <%s>", newValue.Kind(), value.Kind()) } diff --git a/common/reflectcommon/structFieldsUpdate_test.go b/common/reflectcommon/structFieldsUpdate_test.go index 44d3ae7d694..bcf168a25b3 100644 --- a/common/reflectcommon/structFieldsUpdate_test.go +++ b/common/reflectcommon/structFieldsUpdate_test.go @@ -76,12 +76,12 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { t.Parallel() path := "TrieSyncStorage.DB" - expectedNewValue := "provided value" + expectedNewValue := false cfg := &config.Config{} err := AdaptStructureValueBasedOnPath(cfg, path, expectedNewValue) - require.Equal(t, "unsupported type when trying to set the value of type ", err.Error()) + require.Equal(t, "unsupported type when trying to set the value of type ", err.Error()) }) t.Run("should error when setting invalid type on struct", func(t *testing.T) { @@ -1064,10 +1064,10 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { path := "TestConfigNestedStruct.ConfigNestedStruct.Message.MessageDescription" - expectedNewValue := []int{10, 20} + expectedNewValue := []float32{10.1, 20.2} err = AdaptStructureValueBasedOnPath(testConfig, path, expectedNewValue) - require.Equal(t, "unsupported type when trying to set the value of type ", err.Error()) + require.Equal(t, "unsupported type when trying to set the value of type ", err.Error()) }) t.Run("should error on slice when override different struct", func(t *testing.T) { @@ -1204,6 +1204,79 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { require.Equal(t, "unsupported type when trying to add value in type ", err.Error()) }) + t.Run("should work and override string array from config", func(t *testing.T) { + t.Parallel() + + testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") + require.NoError(t, err) + + expectedArray := []string{"x", "y", "z"} + + err = AdaptStructureValueBasedOnPath(testConfig, "TestArray.Strings", expectedArray) + require.NoError(t, err) + require.Equal(t, expectedArray, testConfig.TestArray.Strings) + }) + + t.Run("should work and override int array from config", func(t *testing.T) { + t.Parallel() + + testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") + require.NoError(t, err) + + expectedArray := []int{10, 20, 30} + + err = AdaptStructureValueBasedOnPath(testConfig, "TestArray.Ints", expectedArray) + require.NoError(t, err) + require.Equal(t, expectedArray, testConfig.TestArray.Ints) + }) + + t.Run("should work and override string array", func(t *testing.T) { + t.Parallel() + + testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") + require.NoError(t, err) + + overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") + require.NoError(t, err) + + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[38].Path, overrideConfig.OverridableConfigTomlValues[38].Value) + require.NoError(t, err) + expectedArray := []string{"x", "y", "z"} + require.Equal(t, expectedArray, testConfig.TestArray.Strings) + }) + + t.Run("should work and override int array", func(t *testing.T) { + t.Parallel() + + testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") + require.NoError(t, err) + + overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") + require.NoError(t, err) + + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[39].Path, overrideConfig.OverridableConfigTomlValues[39].Value) + require.NoError(t, err) + expectedArray := []int{10, 20, 30} + require.Equal(t, expectedArray, testConfig.TestArray.Ints) + }) + + t.Run("should work and override struct of array", func(t *testing.T) { + t.Parallel() + + testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") + require.NoError(t, err) + + overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") + require.NoError(t, err) + expectedStringsArray := []string{"x", "y", "z"} + expectedIntsArray := []int{10, 20, 30} + + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[40].Path, overrideConfig.OverridableConfigTomlValues[40].Value) + require.NoError(t, err) + require.Equal(t, expectedStringsArray, testConfig.TestArray.Strings) + require.Equal(t, expectedIntsArray, testConfig.TestArray.Ints) + }) + } func loadTestConfig(filepath string) (*toml.Config, error) { diff --git a/testscommon/toml/config.go b/testscommon/toml/config.go index 56cfeb1f0ad..7f64ee446d4 100644 --- a/testscommon/toml/config.go +++ b/testscommon/toml/config.go @@ -16,6 +16,7 @@ type Config struct { TestConfigNestedStruct TestMap TestInterface + TestArray } // TestConfigI8 will hold an int8 value for testing @@ -180,3 +181,9 @@ type MapValues struct { type TestInterface struct { Value interface{} } + +// TestArray will hold an array of strings and integers +type TestArray struct { + Strings []string + Ints []int +} diff --git a/testscommon/toml/config.toml b/testscommon/toml/config.toml index 91512d5e664..890e3922789 100644 --- a/testscommon/toml/config.toml +++ b/testscommon/toml/config.toml @@ -51,3 +51,7 @@ [Map] [Map.Key1] Number = 999 + +[TestArray] + Strings = ["a", "b", "c"] + Ints = [0, 1, 2] diff --git a/testscommon/toml/overwrite.toml b/testscommon/toml/overwrite.toml index 63f74b7828c..5e495e5c08b 100644 --- a/testscommon/toml/overwrite.toml +++ b/testscommon/toml/overwrite.toml @@ -1,40 +1,43 @@ OverridableConfigTomlValues = [ - { File = "config.toml", Path = "TestConfigI8.Int8.Number", Value = 127 }, - { File = "config.toml", Path = "TestConfigI8.Int8.Number", Value = 128 }, - { File = "config.toml", Path = "TestConfigI8.Int8.Number", Value = -128 }, - { File = "config.toml", Path = "TestConfigI8.Int8.Number", Value = -129 }, - { File = "config.toml", Path = "TestConfigI16.Int16.Number", Value = 32767 }, - { File = "config.toml", Path = "TestConfigI16.Int16.Number", Value = 32768 }, - { File = "config.toml", Path = "TestConfigI16.Int16.Number", Value = -32768 }, - { File = "config.toml", Path = "TestConfigI16.Int16.Number", Value = -32769 }, - { File = "config.toml", Path = "TestConfigI32.Int32.Number", Value = 2147483647 }, - { File = "config.toml", Path = "TestConfigI32.Int32.Number", Value = 2147483648 }, - { File = "config.toml", Path = "TestConfigI32.Int32.Number", Value = -2147483648 }, - { File = "config.toml", Path = "TestConfigI32.Int32.Number", Value = -2147483649 }, - { File = "config.toml", Path = "TestConfigI64.Int64.Number", Value = 9223372036854775807 }, - { File = "config.toml", Path = "TestConfigI64.Int64.Number", Value = -9223372036854775808 }, - { File = "config.toml", Path = "TestConfigU8.Uint8.Number", Value = 255 }, - { File = "config.toml", Path = "TestConfigU8.Uint8.Number", Value = 256 }, - { File = "config.toml", Path = "TestConfigU8.Uint8.Number", Value = -256 }, - { File = "config.toml", Path = "TestConfigU16.Uint16.Number", Value = 65535 }, - { File = "config.toml", Path = "TestConfigU16.Uint16.Number", Value = 65536 }, - { File = "config.toml", Path = "TestConfigU16.Uint16.Number", Value = -65536 }, - { File = "config.toml", Path = "TestConfigU32.Uint32.Number", Value = 4294967295 }, - { File = "config.toml", Path = "TestConfigU32.Uint32.Number", Value = 4294967296 }, - { File = "config.toml", Path = "TestConfigU32.Uint32.Number", Value = -4294967296 }, - { File = "config.toml", Path = "TestConfigU64.Uint64.Number", Value = 9223372036854775807 }, - { File = "config.toml", Path = "TestConfigU64.Uint64.Number", Value = -9223372036854775808 }, - { File = "config.toml", Path = "TestConfigF32.Float32.Number", Value = 3.4 }, - { File = "config.toml", Path = "TestConfigF32.Float32.Number", Value = 3.4e+39 }, - { File = "config.toml", Path = "TestConfigF32.Float32.Number", Value = -3.4 }, - { File = "config.toml", Path = "TestConfigF32.Float32.Number", Value = -3.4e+40 }, - { File = "config.toml", Path = "TestConfigF64.Float64.Number", Value = 1.7e+308 }, - { File = "config.toml", Path = "TestConfigF64.Float64.Number", Value = -1.7e+308 }, - { File = "config.toml", Path = "TestConfigStruct.ConfigStruct.Description", Value = { Number = 11 } }, - { File = "config.toml", Path = "TestConfigStruct.ConfigStruct.Description", Value = { Nr = 222 } }, - { File = "config.toml", Path = "TestConfigStruct.ConfigStruct.Description", Value = { Number = "11" } }, - { File = "config.toml", Path = "TestConfigNestedStruct.ConfigNestedStruct", Value = { Text = "Overwritten text", Message = { Public = false, MessageDescription = [{ Text = "Overwritten Text1" }] } } }, - { File = "config.toml", Path = "TestConfigNestedStruct.ConfigNestedStruct.Message.MessageDescription", Value = [{ Text = "Overwritten Text1" }, { Text = "Overwritten Text2" }] }, - { File = "config.toml", Path = "TestMap.Map", Value = { "Key1" = { Number = 10 }, "Key2" = { Number = 11 } } }, - { File = "config.toml", Path = "TestMap.Map", Value = { "Key2" = { Number = 2 }, "Key3" = { Number = 3 } } }, + { File = "config.toml", Path = "TestConfigI8.Int8.Number", Value = 127 }, + { File = "config.toml", Path = "TestConfigI8.Int8.Number", Value = 128 }, + { File = "config.toml", Path = "TestConfigI8.Int8.Number", Value = -128 }, + { File = "config.toml", Path = "TestConfigI8.Int8.Number", Value = -129 }, + { File = "config.toml", Path = "TestConfigI16.Int16.Number", Value = 32767 }, + { File = "config.toml", Path = "TestConfigI16.Int16.Number", Value = 32768 }, + { File = "config.toml", Path = "TestConfigI16.Int16.Number", Value = -32768 }, + { File = "config.toml", Path = "TestConfigI16.Int16.Number", Value = -32769 }, + { File = "config.toml", Path = "TestConfigI32.Int32.Number", Value = 2147483647 }, + { File = "config.toml", Path = "TestConfigI32.Int32.Number", Value = 2147483648 }, + { File = "config.toml", Path = "TestConfigI32.Int32.Number", Value = -2147483648 }, + { File = "config.toml", Path = "TestConfigI32.Int32.Number", Value = -2147483649 }, + { File = "config.toml", Path = "TestConfigI64.Int64.Number", Value = 9223372036854775807 }, + { File = "config.toml", Path = "TestConfigI64.Int64.Number", Value = -9223372036854775808 }, + { File = "config.toml", Path = "TestConfigU8.Uint8.Number", Value = 255 }, + { File = "config.toml", Path = "TestConfigU8.Uint8.Number", Value = 256 }, + { File = "config.toml", Path = "TestConfigU8.Uint8.Number", Value = -256 }, + { File = "config.toml", Path = "TestConfigU16.Uint16.Number", Value = 65535 }, + { File = "config.toml", Path = "TestConfigU16.Uint16.Number", Value = 65536 }, + { File = "config.toml", Path = "TestConfigU16.Uint16.Number", Value = -65536 }, + { File = "config.toml", Path = "TestConfigU32.Uint32.Number", Value = 4294967295 }, + { File = "config.toml", Path = "TestConfigU32.Uint32.Number", Value = 4294967296 }, + { File = "config.toml", Path = "TestConfigU32.Uint32.Number", Value = -4294967296 }, + { File = "config.toml", Path = "TestConfigU64.Uint64.Number", Value = 9223372036854775807 }, + { File = "config.toml", Path = "TestConfigU64.Uint64.Number", Value = -9223372036854775808 }, + { File = "config.toml", Path = "TestConfigF32.Float32.Number", Value = 3.4 }, + { File = "config.toml", Path = "TestConfigF32.Float32.Number", Value = 3.4e+39 }, + { File = "config.toml", Path = "TestConfigF32.Float32.Number", Value = -3.4 }, + { File = "config.toml", Path = "TestConfigF32.Float32.Number", Value = -3.4e+40 }, + { File = "config.toml", Path = "TestConfigF64.Float64.Number", Value = 1.7e+308 }, + { File = "config.toml", Path = "TestConfigF64.Float64.Number", Value = -1.7e+308 }, + { File = "config.toml", Path = "TestConfigStruct.ConfigStruct.Description", Value = { Number = 11 } }, + { File = "config.toml", Path = "TestConfigStruct.ConfigStruct.Description", Value = { Nr = 222 } }, + { File = "config.toml", Path = "TestConfigStruct.ConfigStruct.Description", Value = { Number = "11" } }, + { File = "config.toml", Path = "TestConfigNestedStruct.ConfigNestedStruct", Value = { Text = "Overwritten text", Message = { Public = false, MessageDescription = [{ Text = "Overwritten Text1" }] } } }, + { File = "config.toml", Path = "TestConfigNestedStruct.ConfigNestedStruct.Message.MessageDescription", Value = [{ Text = "Overwritten Text1" }, { Text = "Overwritten Text2" }] }, + { File = "config.toml", Path = "TestMap.Map", Value = { "Key1" = { Number = 10 }, "Key2" = { Number = 11 } } }, + { File = "config.toml", Path = "TestMap.Map", Value = { "Key2" = { Number = 2 }, "Key3" = { Number = 3 } } }, + { File = "config.toml", Path = "TestArray.Strings", Value = ["x", "y", "z"] }, + { File = "config.toml", Path = "TestArray.Ints", Value = [10, 20, 30] }, + { File = "config.toml", Path = "TestArray", Value = { Strings = ["x", "y", "z"], Ints = [10, 20, 30] } }, ] From 1a05453a36674c2eb21e47ecc70a626fc6054b84 Mon Sep 17 00:00:00 2001 From: axenteoctavian Date: Tue, 12 Nov 2024 18:23:38 +0200 Subject: [PATCH 09/74] better way for set slice --- common/reflectcommon/structFieldsUpdate.go | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/common/reflectcommon/structFieldsUpdate.go b/common/reflectcommon/structFieldsUpdate.go index 4e70a0d3728..7f8940b0400 100644 --- a/common/reflectcommon/structFieldsUpdate.go +++ b/common/reflectcommon/structFieldsUpdate.go @@ -122,11 +122,11 @@ func trySetTheNewValue(value *reflect.Value, newValue interface{}) error { case reflect.Struct: structVal := reflect.ValueOf(newValue) - return trySetItemValue(value, structVal) + return trySetStructValue(value, structVal) case reflect.Map: mapValue := reflect.ValueOf(newValue) - return tryUpdateMapValue(value, mapValue) + return trySetMapValue(value, mapValue) default: return fmt.Errorf("unsupported type <%s> when trying to set the value '%v' of type <%s>", valueKind, newValue, reflect.TypeOf(newValue)) } @@ -141,7 +141,7 @@ func trySetSliceValue(value *reflect.Value, newValue interface{}) error { item := sliceVal.Index(i) newItem := reflect.New(value.Type().Elem()).Elem() - err := trySetItemValue(&newItem, item) + err := trySetTheNewValue(&newItem, item.Interface()) if err != nil { return err } @@ -154,7 +154,7 @@ func trySetSliceValue(value *reflect.Value, newValue interface{}) error { return nil } -func trySetItemValue(value *reflect.Value, newValue reflect.Value) error { +func trySetStructValue(value *reflect.Value, newValue reflect.Value) error { switch newValue.Kind() { case reflect.Invalid: return fmt.Errorf("invalid new value kind") @@ -162,18 +162,12 @@ func trySetItemValue(value *reflect.Value, newValue reflect.Value) error { return updateStructFromMap(value, newValue) case reflect.Struct: // overwrite with go struct return updateStructFromStruct(value, newValue) - case reflect.Interface: - return trySetTheNewValue(value, newValue.Interface()) - case reflect.String: - return trySetTheNewValue(value, newValue.Interface()) - case reflect.Int: - return trySetTheNewValue(value, newValue.Interface()) default: return fmt.Errorf("unsupported type <%s> when trying to set the value of type <%s>", newValue.Kind(), value.Kind()) } } -func tryUpdateMapValue(value *reflect.Value, newValue reflect.Value) error { +func trySetMapValue(value *reflect.Value, newValue reflect.Value) error { if value.IsNil() { value.Set(reflect.MakeMap(value.Type())) } From 458e04fae54140f6b46d27fa6a34e27ea540f89f Mon Sep 17 00:00:00 2001 From: axenteoctavian Date: Tue, 12 Nov 2024 18:25:38 +0200 Subject: [PATCH 10/74] rollback some changes --- common/reflectcommon/structFieldsUpdate_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/reflectcommon/structFieldsUpdate_test.go b/common/reflectcommon/structFieldsUpdate_test.go index bcf168a25b3..79bf0caacb3 100644 --- a/common/reflectcommon/structFieldsUpdate_test.go +++ b/common/reflectcommon/structFieldsUpdate_test.go @@ -76,12 +76,12 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { t.Parallel() path := "TrieSyncStorage.DB" - expectedNewValue := false + expectedNewValue := "provided value" cfg := &config.Config{} err := AdaptStructureValueBasedOnPath(cfg, path, expectedNewValue) - require.Equal(t, "unsupported type when trying to set the value of type ", err.Error()) + require.Equal(t, "unsupported type when trying to set the value of type ", err.Error()) }) t.Run("should error when setting invalid type on struct", func(t *testing.T) { @@ -1064,10 +1064,10 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { path := "TestConfigNestedStruct.ConfigNestedStruct.Message.MessageDescription" - expectedNewValue := []float32{10.1, 20.2} + expectedNewValue := []int{10, 20} err = AdaptStructureValueBasedOnPath(testConfig, path, expectedNewValue) - require.Equal(t, "unsupported type when trying to set the value of type ", err.Error()) + require.Equal(t, "unsupported type when trying to set the value of type ", err.Error()) }) t.Run("should error on slice when override different struct", func(t *testing.T) { From 8a1e9ed20c1d980f1602d8e12af7407aebf41bf6 Mon Sep 17 00:00:00 2001 From: axenteoctavian Date: Tue, 12 Nov 2024 18:36:24 +0200 Subject: [PATCH 11/74] update test name --- common/reflectcommon/structFieldsUpdate_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/reflectcommon/structFieldsUpdate_test.go b/common/reflectcommon/structFieldsUpdate_test.go index 79bf0caacb3..c2b3edced1f 100644 --- a/common/reflectcommon/structFieldsUpdate_test.go +++ b/common/reflectcommon/structFieldsUpdate_test.go @@ -1260,7 +1260,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { require.Equal(t, expectedArray, testConfig.TestArray.Ints) }) - t.Run("should work and override struct of array", func(t *testing.T) { + t.Run("should work and override struct of arrays", func(t *testing.T) { t.Parallel() testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") From 0fd6cedc626774315657a74fdc621148027086cb Mon Sep 17 00:00:00 2001 From: axenteoctavian Date: Wed, 13 Nov 2024 10:02:24 +0200 Subject: [PATCH 12/74] update test name --- common/reflectcommon/structFieldsUpdate_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/common/reflectcommon/structFieldsUpdate_test.go b/common/reflectcommon/structFieldsUpdate_test.go index c2b3edced1f..27a30ea9d00 100644 --- a/common/reflectcommon/structFieldsUpdate_test.go +++ b/common/reflectcommon/structFieldsUpdate_test.go @@ -1204,7 +1204,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { require.Equal(t, "unsupported type when trying to add value in type ", err.Error()) }) - t.Run("should work and override string array from config", func(t *testing.T) { + t.Run("should work and override string array", func(t *testing.T) { t.Parallel() testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") @@ -1217,7 +1217,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { require.Equal(t, expectedArray, testConfig.TestArray.Strings) }) - t.Run("should work and override int array from config", func(t *testing.T) { + t.Run("should work and override int array", func(t *testing.T) { t.Parallel() testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") @@ -1230,7 +1230,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { require.Equal(t, expectedArray, testConfig.TestArray.Ints) }) - t.Run("should work and override string array", func(t *testing.T) { + t.Run("should work and override string array from toml", func(t *testing.T) { t.Parallel() testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") @@ -1245,7 +1245,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { require.Equal(t, expectedArray, testConfig.TestArray.Strings) }) - t.Run("should work and override int array", func(t *testing.T) { + t.Run("should work and override int array from toml", func(t *testing.T) { t.Parallel() testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") @@ -1260,7 +1260,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { require.Equal(t, expectedArray, testConfig.TestArray.Ints) }) - t.Run("should work and override struct of arrays", func(t *testing.T) { + t.Run("should work and override struct of arrays from toml", func(t *testing.T) { t.Parallel() testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") From 6c02c942752af944fe5d97363be7139e05e61a28 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Wed, 13 Nov 2024 17:44:24 +0200 Subject: [PATCH 13/74] further fixes after review --- common/common.go | 4 +- common/common_test.go | 6 +- .../multiShard/relayedTx/common.go | 12 +- .../transactionsFeeProcessor.go | 4 +- process/coordinator/transactionType.go | 2 +- process/dataValidators/txValidator.go | 2 +- process/economics/economicsData.go | 2 +- process/transaction/baseProcess.go | 61 +++- process/transaction/interceptedTransaction.go | 4 +- process/transaction/shardProcess.go | 267 +++++++++++++++--- 10 files changed, 306 insertions(+), 58 deletions(-) diff --git a/common/common.go b/common/common.go index 9c32a9bf2e7..136c449d87d 100644 --- a/common/common.go +++ b/common/common.go @@ -2,8 +2,8 @@ package common import "github.com/multiversx/mx-chain-core-go/data" -// IsRelayedTxV3 returns true if the provided transaction is of type relayed v3 -func IsRelayedTxV3(tx data.TransactionHandler) bool { +// IsValidRelayedTxV3 returns true if the provided transaction a valid transaction of type relayed v3 +func IsValidRelayedTxV3(tx data.TransactionHandler) bool { relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler) if !isRelayedV3 { return false diff --git a/common/common_test.go b/common/common_test.go index 9e44ec87e9f..1786a9d9421 100644 --- a/common/common_test.go +++ b/common/common_test.go @@ -13,7 +13,7 @@ func TestIsRelayedTxV3(t *testing.T) { t.Parallel() scr := &smartContractResult.SmartContractResult{} - require.False(t, IsRelayedTxV3(scr)) + require.False(t, IsValidRelayedTxV3(scr)) notRelayedTxV3 := &transaction.Transaction{ Nonce: 1, @@ -24,7 +24,7 @@ func TestIsRelayedTxV3(t *testing.T) { GasLimit: 10, Signature: []byte("signature"), } - require.False(t, IsRelayedTxV3(notRelayedTxV3)) + require.False(t, IsValidRelayedTxV3(notRelayedTxV3)) relayedTxV3 := &transaction.Transaction{ Nonce: 1, @@ -37,5 +37,5 @@ func TestIsRelayedTxV3(t *testing.T) { RelayerAddr: []byte("relayer"), RelayerSignature: []byte("signature"), } - require.True(t, IsRelayedTxV3(relayedTxV3)) + require.True(t, IsValidRelayedTxV3(relayedTxV3)) } diff --git a/integrationTests/multiShard/relayedTx/common.go b/integrationTests/multiShard/relayedTx/common.go index 26fd6ea0692..c440b574d8c 100644 --- a/integrationTests/multiShard/relayedTx/common.go +++ b/integrationTests/multiShard/relayedTx/common.go @@ -2,7 +2,6 @@ package relayedTx import ( "encoding/hex" - "fmt" "math/big" "github.com/multiversx/mx-chain-core-go/core" @@ -12,8 +11,11 @@ import ( "github.com/multiversx/mx-chain-go/integrationTests" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/state" + logger "github.com/multiversx/mx-chain-logger-go" ) +var log = logger.GetOrCreate("relayedtests") + // CreateGeneralSetupForRelayTxTest will create the general setup for relayed transactions func CreateGeneralSetupForRelayTxTest(baseCostFixEnabled bool) ([]*integrationTests.TestProcessorNode, []int, []*integrationTests.TestWalletAccount, *integrationTests.TestWalletAccount) { initialVal := big.NewInt(10000000000) @@ -94,7 +96,7 @@ func CreateAndSendRelayedAndUserTx( _, err := txDispatcherNode.SendTransaction(relayedTx) if err != nil { - fmt.Println(err.Error()) + log.Error("CreateAndSendRelayedAndUserTx.SendTransaction", "error", err) } return relayedTx, userTx @@ -117,7 +119,7 @@ func CreateAndSendRelayedAndUserTxV2( _, err := txDispatcherNode.SendTransaction(relayedTx) if err != nil { - fmt.Println(err.Error()) + log.Error("CreateAndSendRelayedAndUserTxV2.SendTransaction", "error", err) } return relayedTx, userTx @@ -139,7 +141,7 @@ func CreateAndSendRelayedAndUserTxV3( _, err := txDispatcherNode.SendTransaction(relayedTx) if err != nil { - fmt.Println(err.Error()) + log.Error("CreateAndSendRelayedAndUserTxV3.SendTransaction", "error", err) } return relayedTx, relayedTx @@ -281,7 +283,7 @@ func createAndSendSimpleTransaction( userTx := createUserTx(player, rcvAddr, value, gasLimit, txData) _, err := txDispatcherNode.SendTransaction(userTx) if err != nil { - fmt.Println(err.Error()) + log.Error("createAndSendSimpleTransaction.SendTransaction", "error", err) } } diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index 4fe57119814..bbe1979b1b6 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -271,8 +271,8 @@ func (tep *transactionsFeeProcessor) setGasUsedAndFeeBasedOnRefundValue( refund *big.Int, epoch uint32, ) { - isValidUserTxAfterBaseCostActivation := !check.IfNilReflect(userTx) && tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) - if isValidUserTxAfterBaseCostActivation && !common.IsRelayedTxV3(txWithResults.GetTxHandler()) { + isValidUserTxAfterBaseCostActivation := !check.IfNil(userTx) && tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) + if isValidUserTxAfterBaseCostActivation && !common.IsValidRelayedTxV3(txWithResults.GetTxHandler()) { gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(userTx, refund) tx := txWithResults.GetTxHandler() diff --git a/process/coordinator/transactionType.go b/process/coordinator/transactionType.go index 5d195c70b2c..77de8a5476a 100644 --- a/process/coordinator/transactionType.go +++ b/process/coordinator/transactionType.go @@ -83,7 +83,7 @@ func (tth *txTypeHandler) ComputeTransactionType(tx data.TransactionHandler) (pr return process.InvalidTransaction, process.InvalidTransaction } - if common.IsRelayedTxV3(tx) { + if common.IsValidRelayedTxV3(tx) { return process.RelayedTxV3, process.RelayedTxV3 } diff --git a/process/dataValidators/txValidator.go b/process/dataValidators/txValidator.go index 1e0c67ee007..414ce52c5b6 100644 --- a/process/dataValidators/txValidator.go +++ b/process/dataValidators/txValidator.go @@ -109,7 +109,7 @@ func (txv *txValidator) getFeePayerAccount( payerAccount := accountHandler tx := interceptedTx.Transaction() - if common.IsRelayedTxV3(tx) { + if common.IsValidRelayedTxV3(tx) { relayedTx := tx.(data.RelayedTransactionHandler) payerAddress = relayedTx.GetRelayerAddr() relayerAccount, err := txv.accounts.GetExistingAccount(payerAddress) diff --git a/process/economics/economicsData.go b/process/economics/economicsData.go index dfce9d5a6f6..1e4ebe57454 100644 --- a/process/economics/economicsData.go +++ b/process/economics/economicsData.go @@ -611,7 +611,7 @@ func (ed *economicsData) ComputeGasLimitBasedOnBalanceInEpoch(tx data.Transactio // getExtraGasLimitRelayedTx returns extra gas limit for relayed tx in a specific epoch func (ed *economicsData) getExtraGasLimitRelayedTx(txInstance *transaction.Transaction, epoch uint32) uint64 { - if common.IsRelayedTxV3(txInstance) { + if common.IsValidRelayedTxV3(txInstance) { return ed.MinGasLimitInEpoch(epoch) } diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index d480ec22b51..fec873a0fa6 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -171,7 +171,10 @@ func (txProc *baseTxProcessor) checkTxValues( txFee = core.SafeMul(tx.GasLimit, tx.GasPrice) } - // early exit for relayed v3, the cost will be compared with the sender balance + // early exit for relayed v3. This check is done on the relayed transaction, thus + // the fee payer at this point should be the relayer. + // The check for the cost (fee + value), will be done later on, as part of checkUserTxOfRelayedV3Values + // on the sender account, after relayed moved the fee. if isRelayedV3 { return nil } @@ -184,11 +187,65 @@ func (txProc *baseTxProcessor) checkTxValues( return nil } +func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( + tx *transaction.Transaction, + acntSnd, acntDst state.UserAccountHandler, +) error { + err := txProc.verifyGuardian(tx, acntSnd) + if err != nil { + return err + } + err = txProc.checkUserNames(tx, acntSnd, acntDst) + if err != nil { + return err + } + if check.IfNil(acntSnd) { + return nil + } + if acntSnd.GetNonce() < tx.Nonce { + return process.ErrHigherNonceInTransaction + } + if acntSnd.GetNonce() > tx.Nonce { + return process.ErrLowerNonceInTransaction + } + err = txProc.economicsFee.CheckValidityTxValues(tx) + if err != nil { + return err + } + + if tx.GasLimit < txProc.economicsFee.ComputeGasLimit(tx) { + return process.ErrNotEnoughGasInUserTx + } + + txFee := txProc.computeInnerTxFee(tx) + + if acntSnd.GetBalance().Cmp(txFee) < 0 { + return fmt.Errorf("%w, has: %s, wanted: %s", + process.ErrInsufficientFee, + acntSnd.GetBalance().String(), + txFee.String(), + ) + } + + if !txProc.enableEpochsHandler.IsFlagEnabled(common.PenalizedTooMuchGasFlag) { + // backwards compatibility issue when provided gas limit and gas price exceeds the available balance before the + // activation of the "penalize too much gas" flag + txFee = core.SafeMul(tx.GasLimit, tx.GasPrice) + } + + cost := big.NewInt(0).Add(txFee, tx.Value) + if acntSnd.GetBalance().Cmp(cost) < 0 { + return process.ErrInsufficientFunds + } + + return nil +} + func (txProc *baseTxProcessor) getFeePayer( tx *transaction.Transaction, acntSnd state.UserAccountHandler, ) (state.UserAccountHandler, bool, error) { - if !common.IsRelayedTxV3(tx) { + if !common.IsValidRelayedTxV3(tx) { return acntSnd, false, nil } diff --git a/process/transaction/interceptedTransaction.go b/process/transaction/interceptedTransaction.go index 9afe05c02f3..9efd86c321a 100644 --- a/process/transaction/interceptedTransaction.go +++ b/process/transaction/interceptedTransaction.go @@ -212,7 +212,7 @@ func (inTx *InterceptedTransaction) CheckValidity() error { } func (inTx *InterceptedTransaction) checkRecursiveRelayed(userTx *transaction.Transaction) error { - if common.IsRelayedTxV3(userTx) { + if common.IsValidRelayedTxV3(userTx) { return process.ErrRecursiveRelayedTxIsNotAllowed } @@ -234,7 +234,7 @@ func isRelayedTx(funcName string) bool { } func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transaction) error { - if !common.IsRelayedTxV3(tx) { + if !common.IsValidRelayedTxV3(tx) { return nil } diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 6637a8466d2..11d82f1acfc 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -225,7 +225,7 @@ func (txProc *txProcessor) ProcessTransaction(tx *transaction.Transaction) (vmco switch txType { case process.MoveBalance: - err = txProc.processMoveBalance(tx, acntSnd, acntDst, dstShardTxType, nil, false) + err = txProc.processMoveBalance(tx, acntSnd, acntDst, dstShardTxType, nil, false, false) if err != nil { return vmcommon.UserError, txProc.executeAfterFailedMoveBalanceTransaction(tx, err) } @@ -290,15 +290,15 @@ func (txProc *txProcessor) executeAfterFailedMoveBalanceTransaction( func (txProc *txProcessor) executingFailedTransaction( tx *transaction.Transaction, - acntSnd state.UserAccountHandler, + relayerAccount state.UserAccountHandler, txError error, ) error { - if check.IfNil(acntSnd) { + if check.IfNil(relayerAccount) { return nil } txFee := txProc.economicsFee.ComputeTxFee(tx) - err := acntSnd.SubFromBalance(txFee) + err := relayerAccount.SubFromBalance(txFee) if err != nil { return err } @@ -308,7 +308,7 @@ func (txProc *txProcessor) executingFailedTransaction( return err } - acntSnd.IncreaseNonce(1) + relayerAccount.IncreaseNonce(1) err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}, txHash) if err != nil { return err @@ -318,7 +318,7 @@ func (txProc *txProcessor) executingFailedTransaction( rpt := &receipt.Receipt{ Value: big.NewInt(0).Set(txFee), - SndAddr: acntSnd.AddressBytes(), + SndAddr: relayerAccount.AddressBytes(), Data: []byte(txError.Error()), TxHash: txHash, } @@ -330,7 +330,7 @@ func (txProc *txProcessor) executingFailedTransaction( txProc.txFeeHandler.ProcessTransactionFee(txFee, big.NewInt(0), txHash) - err = txProc.accounts.SaveAccount(acntSnd) + err = txProc.accounts.SaveAccount(relayerAccount) if err != nil { return err } @@ -464,6 +464,7 @@ func (txProc *txProcessor) processMoveBalance( destShardTxType process.TransactionType, originalTxHash []byte, isUserTxOfRelayed bool, + isUserTxOfRelayedV3 bool, ) error { moveBalanceCost, totalCost, err := txProc.processTxFee(tx, acntSrc, acntDst, destShardTxType, isUserTxOfRelayed) @@ -525,9 +526,12 @@ func (txProc *txProcessor) processMoveBalance( } } - txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) - if err != nil { - return err + txHash := originalTxHash + if !isUserTxOfRelayedV3 { + txHash, err = core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) + if err != nil { + return err + } } err = txProc.createReceiptWithReturnedGas(txHash, tx, acntSrc, moveBalanceCost, totalCost, destShardTxType, isUserTxOfRelayed) @@ -600,25 +604,18 @@ func makeUserTxFromRelayedTxV2Args(args [][]byte) *transaction.Transaction { return userTx } -func (txProc *txProcessor) finishExecutionOfRelayedTx( +func (txProc *txProcessor) finishExecutionOfRelayedTxV3( relayerAcnt, acntDst state.UserAccountHandler, tx *transaction.Transaction, userTx *transaction.Transaction, ) (vmcommon.ReturnCode, error) { - isUserTxOfRelayedV3 := common.IsRelayedTxV3(tx) - relayedValue := tx.Value - if isUserTxOfRelayedV3 { - relayedValue = big.NewInt(0) - } - - computedFees := txProc.computeRelayedTxFees(tx, userTx, isUserTxOfRelayedV3) - txHash, err := txProc.processTxAtRelayer( + computedFees := txProc.computeRelayedTxV3Fees(tx, userTx) + txHash, err := txProc.processTxV3AtRelayer( relayerAcnt, computedFees.totalFee, computedFees.relayerFee, tx, - relayedValue, - isUserTxOfRelayedV3) + big.NewInt(0)) if err != nil { return 0, err } @@ -627,18 +624,43 @@ func (txProc *txProcessor) finishExecutionOfRelayedTx( return vmcommon.Ok, nil } - err = txProc.addFeeAndValueToDest(acntDst, relayedValue, computedFees.remainingFee) + err = txProc.addFeeAndValueToDest(acntDst, big.NewInt(0), computedFees.remainingFee) if err != nil { return 0, err } relayedNonce := tx.Nonce - relayerAddr := tx.SndAddr - if isUserTxOfRelayedV3 && !check.IfNil(relayerAcnt) { - relayerAddr = tx.RelayerAddr + relayerAddr := tx.RelayerAddr + + return txProc.processUserTxOfRelayedV3(tx, userTx, relayedNonce, relayerAddr, txHash) +} + +func (txProc *txProcessor) finishExecutionOfRelayedTx( + relayerAcnt, acntDst state.UserAccountHandler, + tx *transaction.Transaction, + userTx *transaction.Transaction, +) (vmcommon.ReturnCode, error) { + computedFees := txProc.computeRelayedTxFees(tx, userTx) + txHash, err := txProc.processTxAtRelayer( + relayerAcnt, + computedFees.totalFee, + computedFees.relayerFee, + tx, + tx.Value) + if err != nil { + return 0, err + } + + if check.IfNil(acntDst) { + return vmcommon.Ok, nil + } + + err = txProc.addFeeAndValueToDest(acntDst, tx.Value, computedFees.remainingFee) + if err != nil { + return 0, err } - return txProc.processUserTx(tx, userTx, relayedValue, relayedNonce, relayerAddr, txHash) + return txProc.processUserTx(tx, userTx, tx.Value, tx.Nonce, tx.SndAddr, txHash) } func (txProc *txProcessor) processTxAtRelayer( @@ -647,7 +669,6 @@ func (txProc *txProcessor) processTxAtRelayer( relayerFee *big.Int, tx *transaction.Transaction, valueToSubFromRelayer *big.Int, - isUserTxOfRelayedV3 bool, ) ([]byte, error) { txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) if err != nil { @@ -665,9 +686,41 @@ func (txProc *txProcessor) processTxAtRelayer( return nil, err } - if !isUserTxOfRelayedV3 { // won't increase relayer nonce for v3 - relayerAcnt.IncreaseNonce(1) + relayerAcnt.IncreaseNonce(1) + err = txProc.accounts.SaveAccount(relayerAcnt) + if err != nil { + return nil, err + } + + txProc.txFeeHandler.ProcessTransactionFee(relayerFee, big.NewInt(0), txHash) + } + + return txHash, nil +} + +func (txProc *txProcessor) processTxV3AtRelayer( + relayerAcnt state.UserAccountHandler, + totalFee *big.Int, + relayerFee *big.Int, + tx *transaction.Transaction, + valueToSubFromRelayer *big.Int, +) ([]byte, error) { + txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) + if err != nil { + return nil, err + } + + if !check.IfNil(relayerAcnt) { + err = relayerAcnt.SubFromBalance(valueToSubFromRelayer) + if err != nil { + return nil, err + } + + err = relayerAcnt.SubFromBalance(totalFee) + if err != nil { + return nil, err } + err = txProc.accounts.SaveAccount(relayerAcnt) if err != nil { return nil, err @@ -712,8 +765,8 @@ func (txProc *txProcessor) processRelayedTxV3(tx *transaction.Transaction) (vmco } userTx := *tx - // remove relayer addr and signature for tx type handler - userTx.RelayerAddr = nil + // remove relayer signature for tx type handler + // hash of this user tx won't be computed/used, but the originalTxHash userTx.RelayerSignature = nil minGasLimit := txProc.economicsFee.MinGasLimit() userTx.GasLimit = userTx.GasLimit - minGasLimit @@ -721,7 +774,7 @@ func (txProc *txProcessor) processRelayedTxV3(tx *transaction.Transaction) (vmco return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrInsufficientGasLimitInTx) } - return txProc.finishExecutionOfRelayedTx(relayerAccount, sndAccount, tx, &userTx) + return txProc.finishExecutionOfRelayedTxV3(relayerAccount, sndAccount, tx, &userTx) } func (txProc *txProcessor) processRelayedTxV2( @@ -791,17 +844,12 @@ func (txProc *txProcessor) processRelayedTx( return txProc.finishExecutionOfRelayedTx(relayerAcnt, acntDst, tx, userTx) } -func (txProc *txProcessor) computeRelayedTxFees(tx, userTx *transaction.Transaction, isUserTxOfRelayedV3 bool) relayedFees { +func (txProc *txProcessor) computeRelayedTxFees(tx, userTx *transaction.Transaction) relayedFees { relayerFee := txProc.economicsFee.ComputeMoveBalanceFee(tx) totalFee := txProc.economicsFee.ComputeTxFee(tx) if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedBaseCostFlag) { userFee := txProc.computeInnerTxFeeAfterBaseCostFix(userTx) - if isUserTxOfRelayedV3 { - relayerGas := txProc.economicsFee.MinGasLimit() - relayerFee = core.SafeMul(relayerGas, tx.GasPrice) - } - totalFee = totalFee.Add(relayerFee, userFee) } remainingFee := big.NewInt(0).Sub(totalFee, relayerFee) @@ -815,6 +863,23 @@ func (txProc *txProcessor) computeRelayedTxFees(tx, userTx *transaction.Transact return computedFees } +func (txProc *txProcessor) computeRelayedTxV3Fees(tx, userTx *transaction.Transaction) relayedFees { + relayerGas := txProc.economicsFee.MinGasLimit() + relayerFee := core.SafeMul(relayerGas, tx.GasPrice) + + userFee := txProc.computeInnerTxFeeAfterBaseCostFix(userTx) + + totalFee := big.NewInt(0).Add(relayerFee, userFee) + + computedFees := relayedFees{ + totalFee: totalFee, + remainingFee: userFee, + relayerFee: relayerFee, + } + + return computedFees +} + func (txProc *txProcessor) removeValueAndConsumedFeeFromUser( userTx *transaction.Transaction, relayedTxValue *big.Int, @@ -943,7 +1008,7 @@ func (txProc *txProcessor) processUserTx( returnCode := vmcommon.Ok switch txType { case process.MoveBalance: - err = txProc.processMoveBalance(userTx, acntSnd, acntDst, dstShardTxType, originalTxHash, true) + err = txProc.processMoveBalance(userTx, acntSnd, acntDst, dstShardTxType, originalTxHash, true, false) case process.SCDeployment: err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) if err != nil { @@ -1018,6 +1083,130 @@ func (txProc *txProcessor) processUserTx( return vmcommon.Ok, nil } +func (txProc *txProcessor) processUserTxOfRelayedV3( + originalTx *transaction.Transaction, + userTx *transaction.Transaction, + relayedNonce uint64, + relayerAddr []byte, + originalTxHash []byte, +) (vmcommon.ReturnCode, error) { + + acntSnd, acntDst, err := txProc.getAccounts(userTx.SndAddr, userTx.RcvAddr) + if err != nil { + errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, big.NewInt(0), originalTxHash, originalTx, err) + if errRemove != nil { + return vmcommon.UserError, errRemove + } + return vmcommon.UserError, txProc.executeFailedRelayedUserTx( + userTx, + relayerAddr, + big.NewInt(0), + relayedNonce, + originalTx, + originalTxHash, + err.Error()) + } + + txType, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(userTx) + err = txProc.checkUserTxOfRelayedV3Values(userTx, acntSnd, acntDst) + if err != nil { + errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, big.NewInt(0), originalTxHash, originalTx, err) + if errRemove != nil { + return vmcommon.UserError, errRemove + } + return vmcommon.UserError, txProc.executeFailedRelayedUserTx( + userTx, + relayerAddr, + big.NewInt(0), + relayedNonce, + originalTx, + originalTxHash, + err.Error()) + } + + scrFromTx, err := txProc.makeSCRFromUserTx(userTx, relayerAddr, big.NewInt(0), originalTxHash) + if err != nil { + return 0, err + } + + returnCode := vmcommon.Ok + switch txType { + case process.MoveBalance: + err = txProc.processMoveBalance(userTx, acntSnd, acntDst, dstShardTxType, originalTxHash, true, true) + case process.SCDeployment: + err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) + if err != nil { + break + } + + returnCode, err = txProc.scProcessor.DeploySmartContract(scrFromTx, acntSnd) + case process.SCInvoking: + err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) + if err != nil { + break + } + + returnCode, err = txProc.scProcessor.ExecuteSmartContractTransaction(scrFromTx, acntSnd, acntDst) + case process.BuiltInFunctionCall: + err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) + if err != nil { + break + } + + returnCode, err = txProc.scProcessor.ExecuteBuiltInFunction(scrFromTx, acntSnd, acntDst) + default: + err = process.ErrWrongTransaction + errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, big.NewInt(0), originalTxHash, originalTx, err) + if errRemove != nil { + return vmcommon.UserError, errRemove + } + return vmcommon.UserError, txProc.executeFailedRelayedUserTx( + userTx, + relayerAddr, + big.NewInt(0), + relayedNonce, + originalTx, + originalTxHash, + err.Error()) + } + + if errors.Is(err, process.ErrInvalidMetaTransaction) || errors.Is(err, process.ErrAccountNotPayable) { + return vmcommon.UserError, txProc.executeFailedRelayedUserTx( + userTx, + relayerAddr, + big.NewInt(0), + relayedNonce, + originalTx, + originalTxHash, + err.Error()) + } + + if errors.Is(err, process.ErrFailedTransaction) { + // in case of failed inner user tx transaction we should just simply return execution failed and + // not failed transaction - as the actual transaction (the relayed we correctly executed) and thus + // it should not lend in the invalid miniblock + return vmcommon.ExecutionFailed, nil + } + + if err != nil { + log.Error("processUserTx", "protocolError", err) + return vmcommon.ExecutionFailed, err + } + + // no need to add the smart contract result From TX to the intermediate transactions in case of error + // returning value is resolved inside smart contract processor or above by executeFailedRelayedUserTx + if returnCode != vmcommon.Ok { + return returnCode, nil + } + + err = txProc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrFromTx}, originalTxHash) + if err != nil { + return 0, err + } + + return vmcommon.Ok, nil +} + func (txProc *baseTxProcessor) isCrossTxFromMe(adrSrc, adrDst []byte) bool { shardForSrc := txProc.shardCoordinator.ComputeId(adrSrc) shardForDst := txProc.shardCoordinator.ComputeId(adrDst) From ea799ab74103af94b86408aecb4e938cb05bb6ee Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 19 Nov 2024 11:51:59 +0200 Subject: [PATCH 14/74] updated indexer --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4ea01439b9c..8a16cd548bd 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/multiversx/mx-chain-communication-go v1.1.1 github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.10 + github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 github.com/multiversx/mx-chain-storage-go v1.0.16 diff --git a/go.sum b/go.sum index 2982014a282..7c4551cae64 100644 --- a/go.sum +++ b/go.sum @@ -391,8 +391,8 @@ github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83 h1: github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.10 h1:Umi7WN8h4BOXLw7CM3VgvaWkLGef7nXtaPIGbjBCT3U= -github.com/multiversx/mx-chain-es-indexer-go v1.7.10/go.mod h1:oGcRK2E3Syv6vRTszWrrb/TqD8akq0yeoMr1wPPiTO4= +github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1 h1:wgMxgtUWd9//FPCTOLj/75j9Kwnd9PE2tHk0KLIFF6s= +github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1/go.mod h1:/KoFDVgh9kGYiINm2THJsII7jfxmbTXWtBoSS1dJo1w= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= From dab1093b05ef7509121ea34989ad28df51406cf2 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Fri, 22 Nov 2024 16:47:52 +0200 Subject: [PATCH 15/74] proper name for EnableEpoch epoch --- cmd/node/config/enableEpochs.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/node/config/enableEpochs.toml b/cmd/node/config/enableEpochs.toml index 9f0261959ea..cffdd5ea773 100644 --- a/cmd/node/config/enableEpochs.toml +++ b/cmd/node/config/enableEpochs.toml @@ -333,8 +333,8 @@ # FixRelayedMoveBalanceToNonPayableSCEnableEpoch represents the epoch when the fix for relayed move balance to non payable sc will be enabled FixRelayedMoveBalanceToNonPayableSCEnableEpoch = 1 - # RelayedTransactionsV3 represents the epoch when the relayed transactions v3 will be enabled - RelayedTransactionsV3 = 5 + # RelayedTransactionsV3EnableEpoch represents the epoch when the relayed transactions v3 will be enabled + RelayedTransactionsV3EnableEpoch = 2 # BLSMultiSignerEnableEpoch represents the activation epoch for different types of BLS multi-signers BLSMultiSignerEnableEpoch = [ From 95fac83754d0281823b12c41d503e18d64511156 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 25 Nov 2024 12:47:49 +0200 Subject: [PATCH 16/74] fixes after review --- process/transaction/shardProcess.go | 73 ++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 11d82f1acfc..8dfd7f884d3 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -290,12 +290,66 @@ func (txProc *txProcessor) executeAfterFailedMoveBalanceTransaction( func (txProc *txProcessor) executingFailedTransaction( tx *transaction.Transaction, + acntSnd state.UserAccountHandler, + txError error, +) error { + if check.IfNil(acntSnd) { + return nil + } + + txFee := txProc.economicsFee.ComputeTxFee(tx) + err := acntSnd.SubFromBalance(txFee) + if err != nil { + return err + } + + txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) + if err != nil { + return err + } + + acntSnd.IncreaseNonce(1) + err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}, txHash) + if err != nil { + return err + } + + log.Trace("executingFailedTransaction", "fail reason(error)", txError, "tx hash", txHash) + + rpt := &receipt.Receipt{ + Value: big.NewInt(0).Set(txFee), + SndAddr: tx.SndAddr, + Data: []byte(txError.Error()), + TxHash: txHash, + } + + err = txProc.receiptForwarder.AddIntermediateTransactions([]data.TransactionHandler{rpt}, txHash) + if err != nil { + return err + } + + txProc.txFeeHandler.ProcessTransactionFee(txFee, big.NewInt(0), txHash) + + err = txProc.accounts.SaveAccount(acntSnd) + if err != nil { + return err + } + + return process.ErrFailedTransaction +} + +func (txProc *txProcessor) executingFailedTransactionRelayedV3( + tx *transaction.Transaction, + acntSnd state.UserAccountHandler, relayerAccount state.UserAccountHandler, txError error, ) error { if check.IfNil(relayerAccount) { return nil } + if check.IfNil(acntSnd) { + return nil + } txFee := txProc.economicsFee.ComputeTxFee(tx) err := relayerAccount.SubFromBalance(txFee) @@ -308,13 +362,13 @@ func (txProc *txProcessor) executingFailedTransaction( return err } - relayerAccount.IncreaseNonce(1) + acntSnd.IncreaseNonce(1) err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}, txHash) if err != nil { return err } - log.Trace("executingFailedTransaction", "fail reason(error)", txError, "tx hash", txHash) + log.Trace("executingFailedTransactionRelayedV3", "fail reason(error)", txError, "tx hash", txHash) rpt := &receipt.Receipt{ Value: big.NewInt(0).Set(txFee), @@ -335,6 +389,11 @@ func (txProc *txProcessor) executingFailedTransaction( return err } + err = txProc.accounts.SaveAccount(acntSnd) + if err != nil { + return err + } + return process.ErrFailedTransaction } @@ -610,7 +669,7 @@ func (txProc *txProcessor) finishExecutionOfRelayedTxV3( userTx *transaction.Transaction, ) (vmcommon.ReturnCode, error) { computedFees := txProc.computeRelayedTxV3Fees(tx, userTx) - txHash, err := txProc.processTxV3AtRelayer( + txHash, err := txProc.consumeFeeFromRelayer( relayerAcnt, computedFees.totalFee, computedFees.relayerFee, @@ -698,7 +757,7 @@ func (txProc *txProcessor) processTxAtRelayer( return txHash, nil } -func (txProc *txProcessor) processTxV3AtRelayer( +func (txProc *txProcessor) consumeFeeFromRelayer( relayerAcnt state.UserAccountHandler, totalFee *big.Int, relayerFee *big.Int, @@ -753,15 +812,15 @@ func (txProc *txProcessor) processRelayedTxV3(tx *transaction.Transaction) (vmco } if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsV3Flag) { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrRelayedTxV3Disabled) + return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrRelayedTxV3Disabled) } if !txProc.shardCoordinator.SameShard(tx.RelayerAddr, tx.SndAddr) { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrShardIdMissmatch) + return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrShardIdMissmatch) } if !check.IfNil(relayerAccount) && relayerAccount.IsGuarded() { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrGuardedRelayerNotAllowed) + return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrGuardedRelayerNotAllowed) } userTx := *tx From 0c2fe332c20e1675b94cf32a590f85e5163bd3ba Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 26 Nov 2024 18:18:09 +0200 Subject: [PATCH 17/74] fixes after tests: fix validation error + fix txs to meta --- .../relayedTx/relayedTx_test.go | 68 +++++++++++++++++++ node/node.go | 10 ++- node/node_test.go | 34 +++++++--- process/transaction/metaProcess.go | 2 + 4 files changed, 104 insertions(+), 10 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index eabad3d708a..63f1828d451 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -20,6 +20,7 @@ import ( "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" chainSimulatorProcess "github.com/multiversx/mx-chain-go/node/chainSimulator/process" "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/vm" "github.com/stretchr/testify/require" ) @@ -60,6 +61,8 @@ func TestRelayedV3WithChainSimulator(t *testing.T) { t.Run("cross shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 1)) t.Run("intra shard sc call, invalid method", testRelayedV3ScCallInvalidMethod(0, 0)) t.Run("cross shard sc call, invalid method", testRelayedV3ScCallInvalidMethod(0, 1)) + + t.Run("create new delegation contract", testRelayedV3MetaInteraction()) } func testRelayedV3MoveBalance( @@ -513,6 +516,71 @@ func testRelayedV3ScCallInvalidMethod( } } +func testRelayedV3MetaInteraction() func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + relayerShard := uint32(0) + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10000)) + relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + // send relayed tx with invalid value + txDataAdd := "createNewDelegationContract@00@00" + gasLimit := uint64(60000000) + value := big.NewInt(0).Mul(oneEGLD, big.NewInt(1250)) + relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, vm.DelegationManagerSCAddress, relayer.Bytes, value, txDataAdd, gasLimit) + + relayerBefore := getBalance(t, cs, relayer) + senderBefore := getBalance(t, cs, sender) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + require.NoError(t, cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx)) + + relayerAfter := getBalance(t, cs, relayer) + senderAfter := getBalance(t, cs, sender) + + // check consumed fees + refund := getRefundValue(result.SmartContractResults) + consumedFee := big.NewInt(0).Sub(relayerBefore, relayerAfter) + + gasForFullPrice := uint64(len(txDataAdd)*gasPerDataByte + minGasLimit + minGasLimit) + gasForDeductedPrice := gasLimit - gasForFullPrice + deductedGasPrice := uint64(minGasPrice / deductionFactor) + initialFee := gasForFullPrice*minGasPrice + gasForDeductedPrice*deductedGasPrice + initialFeeInt := big.NewInt(0).SetUint64(initialFee) + expectedConsumedFee := big.NewInt(0).Sub(initialFeeInt, refund) + + gasUsed := gasForFullPrice + gasForDeductedPrice - refund.Uint64()/deductedGasPrice + require.Equal(t, expectedConsumedFee.String(), consumedFee.String()) + require.Equal(t, value.String(), big.NewInt(0).Sub(senderBefore, senderAfter).String(), "sender should have consumed the value only") + require.Equal(t, initialFeeInt.String(), result.InitiallyPaidFee) + require.Equal(t, expectedConsumedFee.String(), result.Fee) + require.Equal(t, gasUsed, result.GasUsed) + } +} + func TestFixRelayedMoveBalanceWithChainSimulator(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") diff --git a/node/node.go b/node/node.go index ca07f4a0acf..6dec8372c04 100644 --- a/node/node.go +++ b/node/node.go @@ -723,7 +723,7 @@ func (n *Node) ValidateTransaction(tx *transaction.Transaction) error { if errors.Is(err, process.ErrAccountNotFound) { return fmt.Errorf("%w for address %s", process.ErrInsufficientFunds, - n.coreComponents.AddressPubKeyConverter().SilentEncode(tx.SndAddr, log), + n.getFeePayer(tx), ) } @@ -1545,6 +1545,14 @@ func (n *Node) getKeyBytes(key string) ([]byte, error) { return hex.DecodeString(key) } +func (n *Node) getFeePayer(tx *transaction.Transaction) string { + if common.IsValidRelayedTxV3(tx) { + return n.coreComponents.AddressPubKeyConverter().SilentEncode(tx.GetRelayerAddr(), log) + } + + return n.coreComponents.AddressPubKeyConverter().SilentEncode(tx.GetSndAddr(), log) +} + // IsInterfaceNil returns true if there is no value under the interface func (n *Node) IsInterfaceNil() bool { return n == nil diff --git a/node/node_test.go b/node/node_test.go index 319890a5d0d..cd064e6087b 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -3004,15 +3004,31 @@ func TestValidateTransaction_ShouldAdaptAccountNotFoundError(t *testing.T) { node.WithCryptoComponents(getDefaultCryptoComponents()), ) - tx := &transaction.Transaction{ - SndAddr: bytes.Repeat([]byte("1"), 32), - RcvAddr: bytes.Repeat([]byte("1"), 32), - Value: big.NewInt(37), - Signature: []byte("signature"), - ChainID: []byte("chainID"), - } - err := n.ValidateTransaction(tx) - require.Equal(t, "insufficient funds for address erd1xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycspcqad6", err.Error()) + t.Run("normal tx", func(t *testing.T) { + tx := &transaction.Transaction{ + SndAddr: bytes.Repeat([]byte("1"), 32), + RcvAddr: bytes.Repeat([]byte("1"), 32), + Value: big.NewInt(37), + Signature: []byte("signature"), + ChainID: []byte("chainID"), + } + + err := n.ValidateTransaction(tx) + require.Equal(t, "insufficient funds for address erd1xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycspcqad6", err.Error()) + }) + t.Run("relayed tx v3", func(t *testing.T) { + tx := &transaction.Transaction{ + SndAddr: bytes.Repeat([]byte("1"), 32), + RcvAddr: bytes.Repeat([]byte("1"), 32), + Value: big.NewInt(37), + Signature: []byte("sSignature"), + RelayerAddr: bytes.Repeat([]byte("2"), 32), + RelayerSignature: []byte("rSignature"), + ChainID: []byte("chainID"), + } + err := n.ValidateTransaction(tx) + require.Equal(t, "insufficient funds for address erd1xgeryv3jxgeryv3jxgeryv3jxgeryv3jxgeryv3jxgeryv3jxgeqvw86cj", err.Error()) + }) } func TestCreateShardedStores_NilShardCoordinatorShouldError(t *testing.T) { diff --git a/process/transaction/metaProcess.go b/process/transaction/metaProcess.go index 13d6fd4715b..bf3bceb2780 100644 --- a/process/transaction/metaProcess.go +++ b/process/transaction/metaProcess.go @@ -145,6 +145,8 @@ func (txProc *metaTxProcessor) ProcessTransaction(tx *transaction.Transaction) ( if txProc.enableEpochsHandler.IsFlagEnabled(common.ESDTFlag) { return txProc.processSCInvoking(tx, tx.SndAddr, tx.RcvAddr) } + case process.RelayedTxV3: + return vmcommon.Ok, nil // it will be processed through the scr created on source } snapshot := txProc.accounts.JournalLen() From 2c05aa7b85713be1e07c1dc23c0713a8a868509d Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 26 Nov 2024 18:53:13 +0200 Subject: [PATCH 18/74] proper fix for wrapped error --- node/node.go | 18 +++++++++++++----- node/node_test.go | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/node/node.go b/node/node.go index 6dec8372c04..512d199a531 100644 --- a/node/node.go +++ b/node/node.go @@ -723,7 +723,7 @@ func (n *Node) ValidateTransaction(tx *transaction.Transaction) error { if errors.Is(err, process.ErrAccountNotFound) { return fmt.Errorf("%w for address %s", process.ErrInsufficientFunds, - n.getFeePayer(tx), + n.extractAddressFromError(err), ) } @@ -1545,12 +1545,20 @@ func (n *Node) getKeyBytes(key string) ([]byte, error) { return hex.DecodeString(key) } -func (n *Node) getFeePayer(tx *transaction.Transaction) string { - if common.IsValidRelayedTxV3(tx) { - return n.coreComponents.AddressPubKeyConverter().SilentEncode(tx.GetRelayerAddr(), log) +func (n *Node) extractAddressFromError(err error) string { + if !strings.Contains(err.Error(), "for address") { + return "" } - return n.coreComponents.AddressPubKeyConverter().SilentEncode(tx.GetSndAddr(), log) + errWords := strings.Split(err.Error(), " ") + for _, word := range errWords { + _, errDecode := n.coreComponents.AddressPubKeyConverter().Decode(word) + if errDecode == nil { + return word + } + } + + return "" } // IsInterfaceNil returns true if there is no value under the interface diff --git a/node/node_test.go b/node/node_test.go index cd064e6087b..48c1b115091 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -3016,7 +3016,7 @@ func TestValidateTransaction_ShouldAdaptAccountNotFoundError(t *testing.T) { err := n.ValidateTransaction(tx) require.Equal(t, "insufficient funds for address erd1xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycspcqad6", err.Error()) }) - t.Run("relayed tx v3", func(t *testing.T) { + t.Run("relayed tx v3, no funds for sender", func(t *testing.T) { tx := &transaction.Transaction{ SndAddr: bytes.Repeat([]byte("1"), 32), RcvAddr: bytes.Repeat([]byte("1"), 32), @@ -3027,6 +3027,38 @@ func TestValidateTransaction_ShouldAdaptAccountNotFoundError(t *testing.T) { ChainID: []byte("chainID"), } err := n.ValidateTransaction(tx) + require.Equal(t, "insufficient funds for address erd1xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycnzvf3xycspcqad6", err.Error()) + }) + t.Run("relayed tx v3, no funds for relayer", func(t *testing.T) { + tx := &transaction.Transaction{ + SndAddr: bytes.Repeat([]byte("1"), 32), + RcvAddr: bytes.Repeat([]byte("1"), 32), + Value: big.NewInt(37), + Signature: []byte("sSignature"), + RelayerAddr: bytes.Repeat([]byte("2"), 32), + RelayerSignature: []byte("rSignature"), + ChainID: []byte("chainID"), + } + + stateComp := getDefaultStateComponents() + stateComp.AccountsAPI = &stateMock.AccountsStub{ + GetExistingAccountCalled: func(addressContainer []byte) (vmcommon.AccountHandler, error) { + if bytes.Equal(addressContainer, tx.SndAddr) { + return &stateMock.UserAccountStub{}, nil + } + + return nil, errors.New("account not found") + }, + } + nLocal, _ := node.NewNode( + node.WithCoreComponents(getDefaultCoreComponents()), + node.WithBootstrapComponents(getDefaultBootstrapComponents()), + node.WithProcessComponents(getDefaultProcessComponents()), + node.WithStateComponents(stateComp), + node.WithCryptoComponents(getDefaultCryptoComponents()), + ) + + err := nLocal.ValidateTransaction(tx) require.Equal(t, "insufficient funds for address erd1xgeryv3jxgeryv3jxgeryv3jxgeryv3jxgeryv3jxgeryv3jxgeqvw86cj", err.Error()) }) } From 3170be4aa43c56b9a49f16191494e110a2073f07 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Wed, 27 Nov 2024 11:58:03 +0200 Subject: [PATCH 19/74] extra check for relayer != guardian --- process/errors.go | 3 ++ process/mock/multipleShardsCoordinatorMock.go | 6 +++- process/transaction/interceptedTransaction.go | 12 ++++++-- .../interceptedTransaction_test.go | 30 ++++++++++++++++++- process/transaction/shardProcess.go | 4 +++ process/transaction/shardProcess_test.go | 8 +++++ 6 files changed, 59 insertions(+), 4 deletions(-) diff --git a/process/errors.go b/process/errors.go index d75093d8cd9..cd508052e61 100644 --- a/process/errors.go +++ b/process/errors.go @@ -1235,3 +1235,6 @@ var ErrRelayedTxV3Disabled = errors.New("relayed tx v3 are disabled") // ErrGuardedRelayerNotAllowed signals that the provided relayer is guarded var ErrGuardedRelayerNotAllowed = errors.New("guarded relayer not allowed") + +// ErrRelayedByGuardianNotAllowed signals that the provided guardian is also the relayer +var ErrRelayedByGuardianNotAllowed = errors.New("relayed by guardian not allowed") diff --git a/process/mock/multipleShardsCoordinatorMock.go b/process/mock/multipleShardsCoordinatorMock.go index bff3e16d090..27cb599cf92 100644 --- a/process/mock/multipleShardsCoordinatorMock.go +++ b/process/mock/multipleShardsCoordinatorMock.go @@ -6,6 +6,7 @@ import ( type multipleShardsCoordinatorMock struct { ComputeIdCalled func(address []byte) uint32 + SameShardCalled func(firstAddress, secondAddress []byte) bool noShards uint32 CurrentShard uint32 } @@ -44,7 +45,10 @@ func (scm *multipleShardsCoordinatorMock) SetSelfId(_ uint32) error { } // SameShard - -func (scm *multipleShardsCoordinatorMock) SameShard(_, _ []byte) bool { +func (scm *multipleShardsCoordinatorMock) SameShard(firstAddress, secondAddress []byte) bool { + if scm.SameShardCalled != nil { + return scm.SameShardCalled(firstAddress, secondAddress) + } return true } diff --git a/process/transaction/interceptedTransaction.go b/process/transaction/interceptedTransaction.go index 9efd86c321a..b3c48a0eab2 100644 --- a/process/transaction/interceptedTransaction.go +++ b/process/transaction/interceptedTransaction.go @@ -240,7 +240,15 @@ func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transact err := inTx.integrity(tx) if err != nil { - return fmt.Errorf("inner transaction: %w", err) + return err + } + + if !inTx.coordinator.SameShard(tx.RelayerAddr, tx.SndAddr) { + return process.ErrShardIdMissmatch + } + + if bytes.Equal(tx.RelayerAddr, tx.GuardianAddr) { + return process.ErrRelayedByGuardianNotAllowed } userTx := *tx @@ -252,7 +260,7 @@ func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transact err = inTx.verifyRelayerSig(tx) if err != nil { - return fmt.Errorf("inner transaction: %w", err) + return err } return nil diff --git a/process/transaction/interceptedTransaction_test.go b/process/transaction/interceptedTransaction_test.go index 4eafa62ae8d..5a95cc15a24 100644 --- a/process/transaction/interceptedTransaction_test.go +++ b/process/transaction/interceptedTransaction_test.go @@ -171,7 +171,8 @@ func createInterceptedTxFromPlainTxWithArgParser(tx *dataTransaction.Transaction shardCoordinator := mock.NewMultipleShardsCoordinatorMock() shardCoordinator.CurrentShard = 0 shardCoordinator.ComputeIdCalled = func(address []byte) uint32 { - if bytes.Equal(address, senderAddress) { + if bytes.Equal(address, senderAddress) || + bytes.Equal(address, relayerAddress) { return senderShard } if bytes.Equal(address, recvAddress) { @@ -180,6 +181,10 @@ func createInterceptedTxFromPlainTxWithArgParser(tx *dataTransaction.Transaction return shardCoordinator.CurrentShard } + shardCoordinator.SameShardCalled = func(firstAddress, secondAddress []byte) bool { + return string(firstAddress) == string(relayerAddress) && + string(secondAddress) == string(senderAddress) + } return transaction.NewInterceptedTransaction( txBuff, @@ -1524,17 +1529,40 @@ func TestInterceptedTransaction_CheckValidityOfRelayedTxV3(t *testing.T) { tx.Signature = sigOk tx.RelayerSignature = sigOk + // sender in different shard than relayer should fail + tx.RelayerAddr = bytes.Repeat([]byte("a"), len(relayerAddress)) + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + err = txi.CheckValidity() + assert.Equal(t, process.ErrShardIdMissmatch, err) + + // relayer == guardian should fail + tx.Version = 2 + tx.Options = 2 + tx.RelayerAddr = relayerAddress + tx.GuardianAddr = tx.RelayerAddr + tx.GuardianSignature = sigOk + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + err = txi.CheckValidity() + assert.Equal(t, process.ErrRelayedByGuardianNotAllowed, err) + + // recursive relayed txs + tx.Version = minTxVersion + tx.Options = 0 + tx.GuardianAddr = nil + tx.GuardianSignature = nil tx.Data = []byte(core.RelayedTransactionV2 + "@" + hex.EncodeToString(recvAddress) + "@" + hex.EncodeToString(big.NewInt(0).SetUint64(0).Bytes()) + "@" + hex.EncodeToString([]byte("some method")) + "@" + hex.EncodeToString(sigOk)) txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) err = txi.CheckValidity() assert.True(t, errors.Is(err, process.ErrRecursiveRelayedTxIsNotAllowed)) + // invalid relayer signature tx.Data = nil tx.RelayerSignature = bytes.Repeat([]byte("a"), len(sigOk)) // same length but invalid relayer sig txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) err = txi.CheckValidity() assert.NotNil(t, err) + // should work tx.RelayerSignature = sigOk txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) err = txi.CheckValidity() diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 8dfd7f884d3..26143d10a81 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -823,6 +823,10 @@ func (txProc *txProcessor) processRelayedTxV3(tx *transaction.Transaction) (vmco return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrGuardedRelayerNotAllowed) } + if bytes.Equal(tx.RelayerAddr, tx.GuardianAddr) { + return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrRelayedByGuardianNotAllowed) + } + userTx := *tx // remove relayer signature for tx type handler // hash of this user tx won't be computed/used, but the originalTxHash diff --git a/process/transaction/shardProcess_test.go b/process/transaction/shardProcess_test.go index c278b83c80b..8db2d4f21cb 100644 --- a/process/transaction/shardProcess_test.go +++ b/process/transaction/shardProcess_test.go @@ -2784,6 +2784,14 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { assert.Equal(t, process.ErrFailedTransaction, err) assert.Equal(t, vmcommon.UserError, returnCode) }) + t.Run("same guardian and relayer should error", func(t *testing.T) { + txCopy := *tx + txCopy.Nonce = acntSrc.GetNonce() + txCopy.GuardianAddr = txCopy.RelayerAddr + returnCode, err := txProc.ProcessTransaction(&txCopy) + assert.Equal(t, process.ErrFailedTransaction, err) + assert.Equal(t, vmcommon.UserError, returnCode) + }) t.Run("insufficient gas limit should error", func(t *testing.T) { txCopy := *tx txCopy.Nonce = acntSrc.GetNonce() From d23b95356a9d93b3c81bd4ac3b656bbf886dbc56 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Wed, 27 Nov 2024 11:58:42 +0200 Subject: [PATCH 20/74] fix typos --- .../chainSimulator/relayedTx/relayedTx_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index 63f1828d451..7d4cff0d01f 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -544,11 +544,11 @@ func testRelayedV3MetaInteraction() func(t *testing.T) { err = cs.GenerateBlocks(1) require.NoError(t, err) - // send relayed tx with invalid value - txDataAdd := "createNewDelegationContract@00@00" + // send createNewDelegationContract transaction + txData := "createNewDelegationContract@00@00" gasLimit := uint64(60000000) value := big.NewInt(0).Mul(oneEGLD, big.NewInt(1250)) - relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, vm.DelegationManagerSCAddress, relayer.Bytes, value, txDataAdd, gasLimit) + relayedTx := generateRelayedV3Transaction(sender.Bytes, 0, vm.DelegationManagerSCAddress, relayer.Bytes, value, txData, gasLimit) relayerBefore := getBalance(t, cs, relayer) senderBefore := getBalance(t, cs, sender) @@ -565,7 +565,7 @@ func testRelayedV3MetaInteraction() func(t *testing.T) { refund := getRefundValue(result.SmartContractResults) consumedFee := big.NewInt(0).Sub(relayerBefore, relayerAfter) - gasForFullPrice := uint64(len(txDataAdd)*gasPerDataByte + minGasLimit + minGasLimit) + gasForFullPrice := uint64(len(txData)*gasPerDataByte + minGasLimit + minGasLimit) gasForDeductedPrice := gasLimit - gasForFullPrice deductedGasPrice := uint64(minGasPrice / deductionFactor) initialFee := gasForFullPrice*minGasPrice + gasForDeductedPrice*deductedGasPrice From 6ae2337bb3d7b185ff142b6e583015629f1646a2 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 28 Nov 2024 17:26:14 +0200 Subject: [PATCH 21/74] proper execution of relayed v3 --- .../relayedTx/relayedTx_test.go | 50 +- .../smartContract/processorV2/processV2.go | 62 ++- .../smartContract/processorV2/vmInputV2.go | 11 +- process/transaction/baseProcess.go | 63 ++- process/transaction/metaProcess.go | 8 +- process/transaction/shardProcess.go | 476 ++++++++++-------- process/transaction/shardProcess_test.go | 12 +- 7 files changed, 398 insertions(+), 284 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index 7d4cff0d01f..57c4393e1a4 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -146,6 +146,10 @@ func testRelayedV3MoveBalance( result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) require.NoError(t, err) + if relayerShard == destinationShard { + require.NoError(t, cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx)) + } + // check fee fields initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, big.NewInt(0), true, guardedTx) require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) @@ -166,25 +170,11 @@ func testRelayedV3MoveBalance( receiverBalanceAfter := getBalance(t, cs, receiver) require.Equal(t, oneEGLD.String(), receiverBalanceAfter.String()) - // check scr - require.Equal(t, 1, len(result.SmartContractResults)) - require.Equal(t, relayer.Bech32, result.SmartContractResults[0].RelayerAddr) - require.Equal(t, sender.Bech32, result.SmartContractResults[0].SndAddr) - require.Equal(t, receiver.Bech32, result.SmartContractResults[0].RcvAddr) - require.Equal(t, relayedTx.Value, result.SmartContractResults[0].Value) + // check scrs, should be none + require.Zero(t, len(result.SmartContractResults)) // check intra shard logs, should be none require.Nil(t, result.Logs) - - // check cross shard log, should be one completedTxEvent - if relayerShard == destinationShard { - return - } - scrResult, err := cs.GetNodeHandler(destinationShard).GetFacadeHandler().GetTransaction(result.SmartContractResults[0].Hash, true) - require.NoError(t, err) - require.NotNil(t, scrResult.Logs) - require.Equal(t, 1, len(scrResult.Logs.Events)) - require.Contains(t, scrResult.Logs.Events[0].Identifier, core.CompletedTxEventIdentifier) } } @@ -349,7 +339,7 @@ func testRelayedV3ScCall( require.Equal(t, feeDeploy.String(), ownerFee.String()) // check scrs - require.Equal(t, 2, len(result.SmartContractResults)) + require.Equal(t, 1, len(result.SmartContractResults)) for _, scr := range result.SmartContractResults { checkSCRSucceeded(t, cs, scr) } @@ -398,16 +388,9 @@ func testRelayedV3ScCallInvalidGasLimit( result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) require.NoError(t, err) - logs := result.Logs - // if cross shard, generate few more blocks for cross shard scrs - if relayerShard != ownerShard { - require.NoError(t, cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx)) - logs = result.SmartContractResults[0].Logs - } - - require.NotNil(t, logs) - require.Equal(t, 2, len(logs.Events)) - for _, event := range logs.Events { + require.NotNil(t, result.Logs) + require.Equal(t, 2, len(result.Logs.Events)) + for _, event := range result.Logs.Events { if event.Identifier == core.SignalErrorOperation { continue } @@ -480,16 +463,9 @@ func testRelayedV3ScCallInvalidMethod( result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) require.NoError(t, err) - logs := result.Logs - // if cross shard, generate few more blocks for cross shard scrs - if relayerShard != ownerShard { - require.NoError(t, cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx)) - logs = result.SmartContractResults[0].Logs - } - - require.NotNil(t, logs) - require.Equal(t, 2, len(logs.Events)) - for _, event := range logs.Events { + require.NotNil(t, result.Logs) + require.Equal(t, 2, len(result.Logs.Events)) + for _, event := range result.Logs.Events { if event.Identifier == core.SignalErrorOperation { continue } diff --git a/process/smartContract/processorV2/processV2.go b/process/smartContract/processorV2/processV2.go index 5f6c02b7d09..e34f0ac72aa 100644 --- a/process/smartContract/processorV2/processV2.go +++ b/process/smartContract/processorV2/processV2.go @@ -603,6 +603,9 @@ func (sc *scProcessor) updateDeveloperRewards( } moveBalanceGasLimit := sc.economicsFee.ComputeGasLimit(tx) + if common.IsValidRelayedTxV3(tx) { + moveBalanceGasLimit -= sc.economicsFee.MinGasLimit() // this was already consumed from the relayer + } if !isSmartContractResult(tx) { usedGasByMainSC, err = core.SafeSubUint64(usedGasByMainSC, moveBalanceGasLimit) if err != nil { @@ -744,6 +747,9 @@ func (sc *scProcessor) computeTotalConsumedFeeAndDevRwd( } moveBalanceGasLimit := sc.economicsFee.ComputeGasLimit(tx) + if common.IsValidRelayedTxV3(tx) { + moveBalanceGasLimit -= sc.economicsFee.MinGasLimit() // this was already consumed from the relayer + } if !isSmartContractResult(tx) { displayConsumedGas := consumedGas consumedGas, err = core.SafeSubUint64(consumedGas, moveBalanceGasLimit) @@ -1408,7 +1414,7 @@ func (sc *scProcessor) getOriginalTxHashIfIntraShardRelayedSCR( tx data.TransactionHandler, txHash []byte, ) []byte { - relayedSCR, isRelayed := isRelayedTx(tx) + relayedSCR, isRelayed := isRelayedSCR(tx) if !isRelayed { return txHash } @@ -1578,7 +1584,7 @@ func (sc *scProcessor) processForRelayerWhenError( txHash []byte, returnMessage []byte, ) (*vmcommon.LogEntry, error) { - relayedSCR, isRelayed := isRelayedTx(originalTx) + relayedSCR, isRelayed := isRelayedSCR(originalTx) if !isRelayed { return nil, nil } @@ -1664,7 +1670,7 @@ func createNewLogFromSCRIfError(txHandler data.TransactionHandler) *vmcommon.Log } // transaction must be of type SCR and relayed address to be set with relayed value higher than 0 -func isRelayedTx(tx data.TransactionHandler) (*smartContractResult.SmartContractResult, bool) { +func isRelayedSCR(tx data.TransactionHandler) (*smartContractResult.SmartContractResult, bool) { relayedSCR, ok := tx.(*smartContractResult.SmartContractResult) if !ok { return nil, false @@ -1686,7 +1692,7 @@ func (sc *scProcessor) addBackTxValues( ) error { valueForSnd := big.NewInt(0).Set(scrIfError.Value) - relayedSCR, isRelayed := isRelayedTx(originalTx) + relayedSCR, isRelayed := isRelayedSCR(originalTx) if isRelayed { valueForSnd.Sub(valueForSnd, relayedSCR.RelayedValue) if valueForSnd.Cmp(zero) < 0 { @@ -1924,6 +1930,11 @@ func (sc *scProcessor) processSCPayment(tx data.TransactionHandler, acntSnd stat cost := sc.economicsFee.ComputeTxFee(tx) cost = cost.Add(cost, tx.GetValue()) + if common.IsValidRelayedTxV3(tx) { + // for relayed v3, fee was consumed from relayer + cost = tx.GetValue() + } + if cost.Cmp(big.NewInt(0)) == 0 { return nil } @@ -2257,12 +2268,18 @@ func createBaseSCR( result.CallType = vmData.DirectCall setOriginalTxHash(result, txHash, tx) - relayedTx, isRelayed := isRelayedTx(tx) + relayedTx, isRelayed := isRelayedSCR(tx) if isRelayed { result.RelayedValue = big.NewInt(0) result.RelayerAddr = relayedTx.RelayerAddr } + if common.IsValidRelayedTxV3(tx) { + relayedTx := tx.(data.RelayedTransactionHandler) + result.RelayedValue = big.NewInt(0) + result.RelayerAddr = relayedTx.GetRelayerAddr() + } + return result } @@ -2299,12 +2316,18 @@ func (sc *scProcessor) createAsyncCallBackSCRFromVMOutput( OriginalSender: origScr.GetOriginalSender(), } setOriginalTxHash(scr, txHash, tx) - relayedTx, isRelayed := isRelayedTx(tx) + relayedTx, isRelayed := isRelayedSCR(tx) if isRelayed { scr.RelayedValue = big.NewInt(0) scr.RelayerAddr = relayedTx.RelayerAddr } + if common.IsValidRelayedTxV3(tx) { + relayedTx := tx.(data.RelayedTransactionHandler) + scr.RelayedValue = big.NewInt(0) + scr.RelayerAddr = relayedTx.GetRelayerAddr() + } + sc.addVMOutputResultsToSCR(vmOutput, scr) var err error @@ -2569,7 +2592,7 @@ func (sc *scProcessor) createSCRForSenderAndRelayer( } var refundGasToRelayerSCR *smartContractResult.SmartContractResult - relayedSCR, isRelayed := isRelayedTx(tx) + relayedSCR, isRelayed := isRelayedSCR(tx) shouldRefundGasToRelayerSCR := isRelayed && callType != vmData.AsynchronousCall && gasRefund.Cmp(zero) > 0 if shouldRefundGasToRelayerSCR { senderForRelayerRefund := tx.GetRcvAddr() @@ -2592,6 +2615,31 @@ func (sc *scProcessor) createSCRForSenderAndRelayer( gasRemaining = 0 } + isRelayedV3 := common.IsValidRelayedTxV3(tx) + shouldRefundGasToRelayerSCR = isRelayedV3 && callType != vmData.AsynchronousCall && gasRefund.Cmp(zero) > 0 + if shouldRefundGasToRelayerSCR { + senderForRelayerRefund := tx.GetRcvAddr() + if !sc.isSelfShard(tx.GetRcvAddr()) { + senderForRelayerRefund = tx.GetSndAddr() + } + + relayedTx := tx.(data.RelayedTransactionHandler) + + refundGasToRelayerSCR = &smartContractResult.SmartContractResult{ + Nonce: tx.GetNonce() + 1, + Value: big.NewInt(0).Set(gasRefund), + RcvAddr: relayedTx.GetRelayerAddr(), + SndAddr: senderForRelayerRefund, + PrevTxHash: txHash, + OriginalTxHash: txHash, + GasPrice: tx.GetGasPrice(), + CallType: vmData.DirectCall, + ReturnMessage: []byte("gas refund for relayer"), + OriginalSender: tx.GetSndAddr(), + } + gasRemaining = 0 + } + scTx := &smartContractResult.SmartContractResult{} scTx.Value = big.NewInt(0).Set(storageFreeRefund) if callType != vmData.AsynchronousCall && check.IfNil(refundGasToRelayerSCR) { diff --git a/process/smartContract/processorV2/vmInputV2.go b/process/smartContract/processorV2/vmInputV2.go index 06c4c3f0ad2..44b20b1bcc3 100644 --- a/process/smartContract/processorV2/vmInputV2.go +++ b/process/smartContract/processorV2/vmInputV2.go @@ -7,6 +7,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/vm" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" vmcommon "github.com/multiversx/mx-chain-vm-common-go" ) @@ -40,10 +41,14 @@ func (sc *scProcessor) initializeVMInputFromTx(vmInput *vmcommon.VMInput, tx dat vmInput.CallValue = new(big.Int).Set(tx.GetValue()) vmInput.GasPrice = tx.GetGasPrice() - relayedTx, isRelayed := isRelayedTx(tx) + relayedTx, isRelayed := isRelayedSCR(tx) if isRelayed { vmInput.RelayerAddr = relayedTx.RelayerAddr } + if common.IsValidRelayedTxV3(tx) { + relayedTx := tx.(data.RelayedTransactionHandler) + vmInput.RelayerAddr = relayedTx.GetRelayerAddr() + } vmInput.GasProvided, err = sc.prepareGasProvided(tx) if err != nil { @@ -68,6 +73,10 @@ func (sc *scProcessor) prepareGasProvided(tx data.TransactionHandler) (uint64, e } gasForTxData := sc.economicsFee.ComputeGasLimit(tx) + if common.IsValidRelayedTxV3(tx) { + gasForTxData -= sc.economicsFee.MinGasLimit() // this was already consumed from the relayer + } + if tx.GetGasLimit() < gasForTxData { return 0, process.ErrNotEnoughGas } diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index fec873a0fa6..9aecdd534d4 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -119,6 +119,15 @@ func (txProc *baseTxProcessor) checkTxValues( acntSnd, acntDst state.UserAccountHandler, isUserTxOfRelayed bool, ) error { + if common.IsValidRelayedTxV3(tx) { + relayerAccount, _, err := txProc.getAccounts(tx.RelayerAddr, tx.RelayerAddr) + if err != nil { + return err + } + + return txProc.checkUserTxOfRelayedV3Values(tx, acntSnd, acntDst, relayerAccount) + } + err := txProc.verifyGuardian(tx, acntSnd) if err != nil { return err @@ -152,15 +161,10 @@ func (txProc *baseTxProcessor) checkTxValues( txFee = txProc.economicsFee.ComputeTxFee(tx) } - feePayer, isRelayedV3, err := txProc.getFeePayer(tx, acntSnd) - if err != nil { - return err - } - - if feePayer.GetBalance().Cmp(txFee) < 0 { + if acntSnd.GetBalance().Cmp(txFee) < 0 { return fmt.Errorf("%w, has: %s, wanted: %s", process.ErrInsufficientFee, - feePayer.GetBalance().String(), + acntSnd.GetBalance().String(), txFee.String(), ) } @@ -171,16 +175,8 @@ func (txProc *baseTxProcessor) checkTxValues( txFee = core.SafeMul(tx.GasLimit, tx.GasPrice) } - // early exit for relayed v3. This check is done on the relayed transaction, thus - // the fee payer at this point should be the relayer. - // The check for the cost (fee + value), will be done later on, as part of checkUserTxOfRelayedV3Values - // on the sender account, after relayed moved the fee. - if isRelayedV3 { - return nil - } - cost := big.NewInt(0).Add(txFee, tx.Value) - if feePayer.GetBalance().Cmp(cost) < 0 { + if acntSnd.GetBalance().Cmp(cost) < 0 { return process.ErrInsufficientFunds } @@ -189,23 +185,25 @@ func (txProc *baseTxProcessor) checkTxValues( func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( tx *transaction.Transaction, - acntSnd, acntDst state.UserAccountHandler, + senderAccount state.UserAccountHandler, + destinationAccount state.UserAccountHandler, + relayerAccount state.UserAccountHandler, ) error { - err := txProc.verifyGuardian(tx, acntSnd) + err := txProc.verifyGuardian(tx, senderAccount) if err != nil { return err } - err = txProc.checkUserNames(tx, acntSnd, acntDst) + err = txProc.checkUserNames(tx, senderAccount, destinationAccount) if err != nil { return err } - if check.IfNil(acntSnd) { + if check.IfNil(senderAccount) { return nil } - if acntSnd.GetNonce() < tx.Nonce { + if senderAccount.GetNonce() < tx.Nonce { return process.ErrHigherNonceInTransaction } - if acntSnd.GetNonce() > tx.Nonce { + if senderAccount.GetNonce() > tx.Nonce { return process.ErrLowerNonceInTransaction } err = txProc.economicsFee.CheckValidityTxValues(tx) @@ -214,27 +212,24 @@ func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( } if tx.GasLimit < txProc.economicsFee.ComputeGasLimit(tx) { - return process.ErrNotEnoughGasInUserTx + return process.ErrNotEnoughGas } - txFee := txProc.computeInnerTxFee(tx) + if check.IfNil(relayerAccount) { + return nil + } - if acntSnd.GetBalance().Cmp(txFee) < 0 { + txFee := txProc.economicsFee.ComputeTxFee(tx) + + if relayerAccount.GetBalance().Cmp(txFee) < 0 { return fmt.Errorf("%w, has: %s, wanted: %s", process.ErrInsufficientFee, - acntSnd.GetBalance().String(), + relayerAccount.GetBalance().String(), txFee.String(), ) } - if !txProc.enableEpochsHandler.IsFlagEnabled(common.PenalizedTooMuchGasFlag) { - // backwards compatibility issue when provided gas limit and gas price exceeds the available balance before the - // activation of the "penalize too much gas" flag - txFee = core.SafeMul(tx.GasLimit, tx.GasPrice) - } - - cost := big.NewInt(0).Add(txFee, tx.Value) - if acntSnd.GetBalance().Cmp(cost) < 0 { + if senderAccount.GetBalance().Cmp(tx.Value) < 0 { return process.ErrInsufficientFunds } diff --git a/process/transaction/metaProcess.go b/process/transaction/metaProcess.go index bf3bceb2780..577b9c963fb 100644 --- a/process/transaction/metaProcess.go +++ b/process/transaction/metaProcess.go @@ -135,7 +135,13 @@ func (txProc *metaTxProcessor) ProcessTransaction(tx *transaction.Transaction) ( return 0, err } + txCopy := *tx txType, _ := txProc.txTypeHandler.ComputeTransactionType(tx) + if txType == process.RelayedTxV3 { + // extract the inner transaction in order to get the proper user tx type + txCopy.RelayerSignature = nil + txType, _ = txProc.txTypeHandler.ComputeTransactionType(&txCopy) + } switch txType { case process.SCDeployment: return txProc.processSCDeployment(tx, tx.SndAddr) @@ -145,8 +151,6 @@ func (txProc *metaTxProcessor) ProcessTransaction(tx *transaction.Transaction) ( if txProc.enableEpochsHandler.IsFlagEnabled(common.ESDTFlag) { return txProc.processSCInvoking(tx, tx.SndAddr, tx.RcvAddr) } - case process.RelayedTxV3: - return vmcommon.Ok, nil // it will be processed through the scr created on source } snapshot := txProc.accounts.JournalLen() diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 26143d10a81..5091fe71ba6 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -297,8 +297,13 @@ func (txProc *txProcessor) executingFailedTransaction( return nil } + feePayer, isRelayedV3, err := txProc.getFeePayer(tx, acntSnd) + if err != nil { + return err + } + txFee := txProc.economicsFee.ComputeTxFee(tx) - err := acntSnd.SubFromBalance(txFee) + err = feePayer.SubFromBalance(txFee) if err != nil { return err } @@ -330,11 +335,19 @@ func (txProc *txProcessor) executingFailedTransaction( txProc.txFeeHandler.ProcessTransactionFee(txFee, big.NewInt(0), txHash) - err = txProc.accounts.SaveAccount(acntSnd) + err = txProc.accounts.SaveAccount(feePayer) if err != nil { return err } + if isRelayedV3 { + // for relayed v3, the nonce was increased for sender, but fees consumed from relayer + err = txProc.accounts.SaveAccount(acntSnd) + if err != nil { + return err + } + } + return process.ErrFailedTransaction } @@ -454,6 +467,11 @@ func (txProc *txProcessor) processTxFee( return nil, nil, err } + err = txProc.accounts.SaveAccount(acntSnd) + if err != nil { + return nil, nil, err + } + if dstShardTxType == process.MoveBalance { return totalCost, totalCost, nil } @@ -482,22 +500,77 @@ func (txProc *txProcessor) processTxFee( if err != nil { return nil, nil, err } + + err = txProc.accounts.SaveAccount(acntSnd) + if err != nil { + return nil, nil, err + } } else { err := acntSnd.SubFromBalance(moveBalanceFee) if err != nil { return nil, nil, err } + + err = txProc.accounts.SaveAccount(acntSnd) + if err != nil { + return nil, nil, err + } } return moveBalanceFee, totalCost, nil } -func (txProc *txProcessor) checkIfValidTxToMetaChain( +func (txProc *txProcessor) processTxFeeOfRelayedV3( tx *transaction.Transaction, - adrDst []byte, + txHash []byte, + relayerAccount state.UserAccountHandler, + destinationAccount state.UserAccountHandler, + dstShardTxType process.TransactionType, ) error { + if check.IfNil(relayerAccount) { + return nil + } + + moveBalanceFee := txProc.economicsFee.ComputeMoveBalanceFee(tx) + totalCost := txProc.economicsFee.ComputeTxFee(tx) + + if !txProc.enableEpochsHandler.IsFlagEnabled(common.PenalizedTooMuchGasFlag) { + totalCost = core.SafeMul(tx.GasLimit, tx.GasPrice) + } + + isCrossShardSCCall := check.IfNil(destinationAccount) && len(tx.GetData()) > 0 && core.IsSmartContractAddress(tx.GetRcvAddr()) + if dstShardTxType != process.MoveBalance || + (!txProc.enableEpochsHandler.IsFlagEnabled(common.MetaProtectionFlag) && isCrossShardSCCall) { + + err := relayerAccount.SubFromBalance(totalCost) + if err != nil { + return err + } + + err = txProc.accounts.SaveAccount(relayerAccount) + if err != nil { + return err + } + } else { + err := relayerAccount.SubFromBalance(moveBalanceFee) + if err != nil { + return err + } + + txProc.txFeeHandler.ProcessTransactionFee(moveBalanceFee, big.NewInt(0), txHash) + + err = txProc.accounts.SaveAccount(relayerAccount) + if err != nil { + return err + } + } - destShardId := txProc.shardCoordinator.ComputeId(adrDst) + return nil +} + +func (txProc *txProcessor) checkIfValidTxToMetaChain(tx *transaction.Transaction) error { + + destShardId := txProc.shardCoordinator.ComputeId(tx.RcvAddr) if destShardId != core.MetachainShardId { return nil } @@ -562,7 +635,7 @@ func (txProc *txProcessor) processMoveBalance( return process.ErrAccountNotPayable } - err = txProc.checkIfValidTxToMetaChain(tx, tx.RcvAddr) + err = txProc.checkIfValidTxToMetaChain(tx) if err != nil { errLocal := txProc.revertConsumedValueFromSender(tx, acntSrc, isUserTxOfRelayed) if errLocal != nil { @@ -607,6 +680,76 @@ func (txProc *txProcessor) processMoveBalance( return nil } +func (txProc *txProcessor) processMoveBalanceOfRelayedV3( + tx *transaction.Transaction, + senderAccount state.UserAccountHandler, + destinationAccount state.UserAccountHandler, + relayerAccount state.UserAccountHandler, + destShardTxType process.TransactionType, + originalTxHash []byte, +) error { + err := txProc.processTxFeeOfRelayedV3(tx, originalTxHash, relayerAccount, destinationAccount, destShardTxType) + if err != nil { + return err + } + + // is sender address in node shard + if !check.IfNil(senderAccount) { + senderAccount.IncreaseNonce(1) + err = senderAccount.SubFromBalance(tx.Value) + if err != nil { + return err + } + + err = txProc.accounts.SaveAccount(senderAccount) + if err != nil { + return err + } + } + + isPayable, err := txProc.scProcessor.IsPayable(tx.SndAddr, tx.RcvAddr) + if err != nil { + errRefund := txProc.revertConsumedValueFromSender(tx, senderAccount, true) + if errRefund != nil { + log.Error("failed to return funds to sender after check if receiver is payable", "error", errRefund) + } + return err + } + if !isPayable { + err = txProc.revertConsumedValueFromSender(tx, senderAccount, true) + if err != nil { + log.Error("failed to return funds to sender while transferring to non payable sc", "error", err) + } + + return process.ErrAccountNotPayable + } + + err = txProc.checkIfValidTxToMetaChain(tx) + if err != nil { + errLocal := txProc.revertConsumedValueFromSender(tx, senderAccount, true) + if errLocal != nil { + log.Error("failed to return funds to sender while sending invalid tx to metachain", "error", errLocal) + } + + return err + } + + // is receiver address in node shard + if !check.IfNil(destinationAccount) { + err = destinationAccount.AddToBalance(tx.Value) + if err != nil { + return err + } + + err = txProc.accounts.SaveAccount(destinationAccount) + if err != nil { + return err + } + } + + return nil +} + func (txProc *txProcessor) revertConsumedValueFromSender( tx *transaction.Transaction, acntSrc state.UserAccountHandler, @@ -664,34 +807,85 @@ func makeUserTxFromRelayedTxV2Args(args [][]byte) *transaction.Transaction { } func (txProc *txProcessor) finishExecutionOfRelayedTxV3( - relayerAcnt, acntDst state.UserAccountHandler, + relayerAccount state.UserAccountHandler, tx *transaction.Transaction, userTx *transaction.Transaction, ) (vmcommon.ReturnCode, error) { - computedFees := txProc.computeRelayedTxV3Fees(tx, userTx) - txHash, err := txProc.consumeFeeFromRelayer( - relayerAcnt, - computedFees.totalFee, - computedFees.relayerFee, - tx, - big.NewInt(0)) + txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) if err != nil { return 0, err } - if check.IfNil(acntDst) { - return vmcommon.Ok, nil + senderAccount, destinationAccount, err := txProc.getAccounts(tx.SndAddr, tx.RcvAddr) + if err != nil { + errRemove := txProc.increaseSenderNonceIfNeededAndLog(txHash, tx, senderAccount, err) + if errRemove != nil { + return vmcommon.UserError, errRemove + } + return vmcommon.UserError, txProc.executeFailedRelayedV3UserTx( + tx, + txHash, + err.Error()) } - err = txProc.addFeeAndValueToDest(acntDst, big.NewInt(0), computedFees.remainingFee) - if err != nil { - return 0, err + txType, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(userTx) + returnCode := vmcommon.Ok + switch txType { + case process.MoveBalance: + err = txProc.processMoveBalanceOfRelayedV3(tx, senderAccount, destinationAccount, relayerAccount, dstShardTxType, txHash) + case process.SCDeployment: + err = txProc.processTxFeeOfRelayedV3(tx, txHash, relayerAccount, destinationAccount, dstShardTxType) + if err != nil { + break + } + + returnCode, err = txProc.scProcessor.DeploySmartContract(tx, destinationAccount) + case process.SCInvoking: + err = txProc.processTxFeeOfRelayedV3(tx, txHash, relayerAccount, destinationAccount, dstShardTxType) + if err != nil { + break + } + + returnCode, err = txProc.scProcessor.ExecuteSmartContractTransaction(tx, senderAccount, destinationAccount) + case process.BuiltInFunctionCall: + err = txProc.processTxFeeOfRelayedV3(tx, txHash, relayerAccount, destinationAccount, dstShardTxType) + if err != nil { + break + } + + returnCode, err = txProc.scProcessor.ExecuteBuiltInFunction(tx, senderAccount, destinationAccount) + default: + err = process.ErrWrongTransaction + errRemove := txProc.increaseSenderNonceIfNeededAndLog(txHash, tx, senderAccount, err) + if errRemove != nil { + return vmcommon.UserError, errRemove + } + return vmcommon.UserError, txProc.executeFailedRelayedV3UserTx( + tx, + txHash, + err.Error()) + } + + if errors.Is(err, process.ErrInvalidMetaTransaction) || errors.Is(err, process.ErrAccountNotPayable) { + return vmcommon.UserError, txProc.executeFailedRelayedV3UserTx( + tx, + txHash, + err.Error()) + } + + if errors.Is(err, process.ErrFailedTransaction) { + // in case of failed inner user tx transaction we should just simply return execution failed and + // not failed transaction - as the actual transaction (the relayed we correctly executed) and thus + // it should not lend in the invalid miniblock + return vmcommon.ExecutionFailed, nil } - relayedNonce := tx.Nonce - relayerAddr := tx.RelayerAddr + if err != nil { + log.Error("processUserTx", "protocolError", err) + return vmcommon.ExecutionFailed, err + } - return txProc.processUserTxOfRelayedV3(tx, userTx, relayedNonce, relayerAddr, txHash) + return returnCode, err } func (txProc *txProcessor) finishExecutionOfRelayedTx( @@ -757,41 +951,11 @@ func (txProc *txProcessor) processTxAtRelayer( return txHash, nil } -func (txProc *txProcessor) consumeFeeFromRelayer( - relayerAcnt state.UserAccountHandler, - totalFee *big.Int, - relayerFee *big.Int, - tx *transaction.Transaction, - valueToSubFromRelayer *big.Int, -) ([]byte, error) { - txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) - if err != nil { - return nil, err - } - - if !check.IfNil(relayerAcnt) { - err = relayerAcnt.SubFromBalance(valueToSubFromRelayer) - if err != nil { - return nil, err - } - - err = relayerAcnt.SubFromBalance(totalFee) - if err != nil { - return nil, err - } - - err = txProc.accounts.SaveAccount(relayerAcnt) - if err != nil { - return nil, err - } - - txProc.txFeeHandler.ProcessTransactionFee(relayerFee, big.NewInt(0), txHash) +func (txProc *txProcessor) addFeeAndValueToDest(acntDst state.UserAccountHandler, txValue *big.Int, remainingFee *big.Int) error { + if check.IfNil(acntDst) { + return nil } - return txHash, nil -} - -func (txProc *txProcessor) addFeeAndValueToDest(acntDst state.UserAccountHandler, txValue *big.Int, remainingFee *big.Int) error { err := acntDst.AddToBalance(txValue) if err != nil { return err @@ -837,7 +1001,7 @@ func (txProc *txProcessor) processRelayedTxV3(tx *transaction.Transaction) (vmco return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrInsufficientGasLimitInTx) } - return txProc.finishExecutionOfRelayedTxV3(relayerAccount, sndAccount, tx, &userTx) + return txProc.finishExecutionOfRelayedTxV3(relayerAccount, tx, &userTx) } func (txProc *txProcessor) processRelayedTxV2( @@ -926,23 +1090,6 @@ func (txProc *txProcessor) computeRelayedTxFees(tx, userTx *transaction.Transact return computedFees } -func (txProc *txProcessor) computeRelayedTxV3Fees(tx, userTx *transaction.Transaction) relayedFees { - relayerGas := txProc.economicsFee.MinGasLimit() - relayerFee := core.SafeMul(relayerGas, tx.GasPrice) - - userFee := txProc.computeInnerTxFeeAfterBaseCostFix(userTx) - - totalFee := big.NewInt(0).Add(relayerFee, userFee) - - computedFees := relayedFees{ - totalFee: totalFee, - remainingFee: userFee, - relayerFee: relayerFee, - } - - return computedFees -} - func (txProc *txProcessor) removeValueAndConsumedFeeFromUser( userTx *transaction.Transaction, relayedTxValue *big.Int, @@ -986,6 +1133,28 @@ func (txProc *txProcessor) removeValueAndConsumedFeeFromUser( return nil } +func (txProc *txProcessor) increaseSenderNonceIfNeededAndLog( + originalTxHash []byte, + originalTx *transaction.Transaction, + senderAccount vmcommon.AccountHandler, + executionErr error, +) error { + if txProc.shouldIncreaseNonce(executionErr) { + if check.IfNil(senderAccount) { + return process.ErrNilUserAccount + } + + senderAccount.IncreaseNonce(1) + + err := txProc.accounts.SaveAccount(senderAccount) + if err != nil { + return err + } + } + + return txProc.addNonExecutableLog(executionErr, originalTxHash, originalTx) +} + func (txProc *txProcessor) addNonExecutableLog(executionErr error, originalTxHash []byte, originalTx data.TransactionHandler) error { if !isNonExecutableError(executionErr) { return nil @@ -1146,130 +1315,6 @@ func (txProc *txProcessor) processUserTx( return vmcommon.Ok, nil } -func (txProc *txProcessor) processUserTxOfRelayedV3( - originalTx *transaction.Transaction, - userTx *transaction.Transaction, - relayedNonce uint64, - relayerAddr []byte, - originalTxHash []byte, -) (vmcommon.ReturnCode, error) { - - acntSnd, acntDst, err := txProc.getAccounts(userTx.SndAddr, userTx.RcvAddr) - if err != nil { - errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, big.NewInt(0), originalTxHash, originalTx, err) - if errRemove != nil { - return vmcommon.UserError, errRemove - } - return vmcommon.UserError, txProc.executeFailedRelayedUserTx( - userTx, - relayerAddr, - big.NewInt(0), - relayedNonce, - originalTx, - originalTxHash, - err.Error()) - } - - txType, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(userTx) - err = txProc.checkUserTxOfRelayedV3Values(userTx, acntSnd, acntDst) - if err != nil { - errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, big.NewInt(0), originalTxHash, originalTx, err) - if errRemove != nil { - return vmcommon.UserError, errRemove - } - return vmcommon.UserError, txProc.executeFailedRelayedUserTx( - userTx, - relayerAddr, - big.NewInt(0), - relayedNonce, - originalTx, - originalTxHash, - err.Error()) - } - - scrFromTx, err := txProc.makeSCRFromUserTx(userTx, relayerAddr, big.NewInt(0), originalTxHash) - if err != nil { - return 0, err - } - - returnCode := vmcommon.Ok - switch txType { - case process.MoveBalance: - err = txProc.processMoveBalance(userTx, acntSnd, acntDst, dstShardTxType, originalTxHash, true, true) - case process.SCDeployment: - err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) - if err != nil { - break - } - - returnCode, err = txProc.scProcessor.DeploySmartContract(scrFromTx, acntSnd) - case process.SCInvoking: - err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) - if err != nil { - break - } - - returnCode, err = txProc.scProcessor.ExecuteSmartContractTransaction(scrFromTx, acntSnd, acntDst) - case process.BuiltInFunctionCall: - err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) - if err != nil { - break - } - - returnCode, err = txProc.scProcessor.ExecuteBuiltInFunction(scrFromTx, acntSnd, acntDst) - default: - err = process.ErrWrongTransaction - errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, big.NewInt(0), originalTxHash, originalTx, err) - if errRemove != nil { - return vmcommon.UserError, errRemove - } - return vmcommon.UserError, txProc.executeFailedRelayedUserTx( - userTx, - relayerAddr, - big.NewInt(0), - relayedNonce, - originalTx, - originalTxHash, - err.Error()) - } - - if errors.Is(err, process.ErrInvalidMetaTransaction) || errors.Is(err, process.ErrAccountNotPayable) { - return vmcommon.UserError, txProc.executeFailedRelayedUserTx( - userTx, - relayerAddr, - big.NewInt(0), - relayedNonce, - originalTx, - originalTxHash, - err.Error()) - } - - if errors.Is(err, process.ErrFailedTransaction) { - // in case of failed inner user tx transaction we should just simply return execution failed and - // not failed transaction - as the actual transaction (the relayed we correctly executed) and thus - // it should not lend in the invalid miniblock - return vmcommon.ExecutionFailed, nil - } - - if err != nil { - log.Error("processUserTx", "protocolError", err) - return vmcommon.ExecutionFailed, err - } - - // no need to add the smart contract result From TX to the intermediate transactions in case of error - // returning value is resolved inside smart contract processor or above by executeFailedRelayedUserTx - if returnCode != vmcommon.Ok { - return returnCode, nil - } - - err = txProc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrFromTx}, originalTxHash) - if err != nil { - return 0, err - } - - return vmcommon.Ok, nil -} - func (txProc *baseTxProcessor) isCrossTxFromMe(adrSrc, adrDst []byte) bool { shardForSrc := txProc.shardCoordinator.ComputeId(adrSrc) shardForDst := txProc.shardCoordinator.ComputeId(adrDst) @@ -1384,6 +1429,43 @@ func (txProc *txProcessor) executeFailedRelayedUserTx( return nil } +func (txProc *txProcessor) executeFailedRelayedV3UserTx( + originalTx *transaction.Transaction, + originalTxHash []byte, + errorMsg string, +) error { + + scrForRelayer := &smartContractResult.SmartContractResult{ + Nonce: originalTx.Nonce, + Value: big.NewInt(0), + RcvAddr: originalTx.RelayerAddr, + SndAddr: originalTx.SndAddr, + PrevTxHash: originalTxHash, + OriginalTxHash: originalTxHash, + ReturnMessage: []byte(errorMsg), + } + + err := txProc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrForRelayer}, originalTxHash) + if err != nil { + return err + } + + moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(originalTx) + gasToUse := originalTx.GetGasLimit() - moveBalanceGasLimit + processingUserFee := txProc.economicsFee.ComputeFeeForProcessing(originalTx, gasToUse) + moveBalanceUserFee := txProc.economicsFee.ComputeMoveBalanceFee(originalTx) + totalFee := big.NewInt(0).Add(moveBalanceUserFee, processingUserFee) + + senderShardID := txProc.shardCoordinator.ComputeId(originalTx.SndAddr) + if senderShardID != txProc.shardCoordinator.SelfId() { + totalFee.Sub(totalFee, processingUserFee) + } + + txProc.txFeeHandler.ProcessTransactionFee(totalFee, big.NewInt(0), originalTxHash) + + return txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{originalTx}, originalTxHash) +} + func (txProc *txProcessor) shouldIncreaseNonce(executionErr error) bool { if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedNonceFixFlag) { return true diff --git a/process/transaction/shardProcess_test.go b/process/transaction/shardProcess_test.go index 8db2d4f21cb..f65aadffb5f 100644 --- a/process/transaction/shardProcess_test.go +++ b/process/transaction/shardProcess_test.go @@ -923,7 +923,7 @@ func TestTxProcessor_ProcessMoveBalanceToSmartPayableContract(t *testing.T) { _, err := execTx.ProcessTransaction(&tx) assert.Nil(t, err) - assert.Equal(t, 2, saveAccountCalled) + assert.Equal(t, 3, saveAccountCalled) } func testProcessCheck(t *testing.T, nonce uint64, value *big.Int) { @@ -989,7 +989,7 @@ func TestTxProcessor_ProcessMoveBalancesShouldWork(t *testing.T) { _, err := execTx.ProcessTransaction(&tx) assert.Nil(t, err) - assert.Equal(t, 2, saveAccountCalled) + assert.Equal(t, 3, saveAccountCalled) } func TestTxProcessor_ProcessOkValsShouldWork(t *testing.T) { @@ -1025,7 +1025,7 @@ func TestTxProcessor_ProcessOkValsShouldWork(t *testing.T) { assert.Equal(t, uint64(5), acntSrc.GetNonce()) assert.Equal(t, big.NewInt(29), acntSrc.GetBalance()) assert.Equal(t, big.NewInt(71), acntDst.GetBalance()) - assert.Equal(t, 2, saveAccountCalled) + assert.Equal(t, 3, saveAccountCalled) } func TestTxProcessor_MoveBalanceWithFeesShouldWork(t *testing.T) { @@ -1072,7 +1072,7 @@ func TestTxProcessor_MoveBalanceWithFeesShouldWork(t *testing.T) { assert.Equal(t, uint64(5), acntSrc.GetNonce()) assert.Equal(t, big.NewInt(13), acntSrc.GetBalance()) assert.Equal(t, big.NewInt(71), acntDst.GetBalance()) - assert.Equal(t, 2, saveAccountCalled) + assert.Equal(t, 3, saveAccountCalled) } func TestTxProcessor_ProcessTransactionScDeployTxShouldWork(t *testing.T) { @@ -1324,7 +1324,7 @@ func TestTxProcessor_ProcessTransactionScTxShouldNotBeCalledWhenAdrDstIsNotInNod _, err := execTx.ProcessTransaction(&tx) assert.Nil(t, err) assert.False(t, wasCalled) - assert.Equal(t, 1, saveAccountCalled) + assert.Equal(t, 2, saveAccountCalled) } func TestTxProcessor_ProcessTxFeeIntraShard(t *testing.T) { @@ -2805,7 +2805,7 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { require.NotNil(t, txProcLocal) returnCode, err := txProcLocal.ProcessTransaction(&txCopy) - assert.Equal(t, process.ErrFailedTransaction, err) + assert.Equal(t, process.ErrNotEnoughGas, err) assert.Equal(t, vmcommon.UserError, returnCode) }) } From 28690762fa0c30620ddc481ff59fc2dcfb37800d Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 2 Dec 2024 18:39:18 +0200 Subject: [PATCH 22/74] further fixes after review, treat relayed v3 as normal tx --- factory/disabled/txCoordinator.go | 4 +- .../mock/transactionCoordinatorMock.go | 6 +- .../transactionAPI/apiTransactionProcessor.go | 6 +- .../apiTransactionProcessor_test.go | 8 +- node/node.go | 1 + process/block/preprocess/gasComputation.go | 4 +- .../block/preprocess/gasComputation_test.go | 44 +- process/block/preprocess/transactionsV2.go | 4 +- .../block/preprocess/transactionsV2_test.go | 6 +- process/coordinator/process.go | 2 +- process/coordinator/process_test.go | 8 +- process/coordinator/transactionType.go | 32 +- process/coordinator/transactionType_test.go | 52 ++- process/disabled/txTypeHandler.go | 4 +- .../factory/interceptedTxDataFactory.go | 1 + process/interface.go | 2 +- process/smartContract/process.go | 6 +- process/smartContract/process_test.go | 16 +- .../smartContract/processorV2/processV2.go | 217 +++++---- .../smartContract/processorV2/process_test.go | 16 +- .../smartContract/processorV2/vmInputV2.go | 14 +- process/transaction/baseProcess.go | 6 +- process/transaction/export_test.go | 6 + process/transaction/interceptedTransaction.go | 10 + .../interceptedTransaction_test.go | 58 +++ process/transaction/metaProcess.go | 8 +- process/transaction/metaProcess_test.go | 12 +- process/transaction/shardProcess.go | 421 ++---------------- process/transaction/shardProcess_test.go | 86 ++-- .../transactionEvaluator.go | 2 +- .../transactionEvaluator_test.go | 32 +- testscommon/scProcessorMock.go | 6 +- testscommon/transactionCoordinatorMock.go | 6 +- testscommon/txTypeHandlerMock.go | 6 +- 34 files changed, 441 insertions(+), 671 deletions(-) diff --git a/factory/disabled/txCoordinator.go b/factory/disabled/txCoordinator.go index 9d8002fb034..a5d0dfe330a 100644 --- a/factory/disabled/txCoordinator.go +++ b/factory/disabled/txCoordinator.go @@ -25,8 +25,8 @@ func (txCoordinator *TxCoordinator) CreateReceiptsHash() ([]byte, error) { } // ComputeTransactionType does nothing as it is disabled -func (txCoordinator *TxCoordinator) ComputeTransactionType(_ data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return 0, 0 +func (txCoordinator *TxCoordinator) ComputeTransactionType(_ data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return 0, 0, false } // RequestMiniBlocksAndTransactions does nothing as it is disabled diff --git a/integrationTests/mock/transactionCoordinatorMock.go b/integrationTests/mock/transactionCoordinatorMock.go index c002c52cc0f..29414c117da 100644 --- a/integrationTests/mock/transactionCoordinatorMock.go +++ b/integrationTests/mock/transactionCoordinatorMock.go @@ -12,7 +12,7 @@ import ( // TransactionCoordinatorMock - type TransactionCoordinatorMock struct { - ComputeTransactionTypeCalled func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) + ComputeTransactionTypeCalled func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) RequestMiniBlocksAndTransactionsCalled func(header data.HeaderHandler) RequestBlockTransactionsCalled func(body *block.Body) IsDataPreparedForProcessingCalled func(haveTime func() time.Duration) error @@ -55,9 +55,9 @@ func (tcm *TransactionCoordinatorMock) CreateReceiptsHash() ([]byte, error) { } // ComputeTransactionType - -func (tcm *TransactionCoordinatorMock) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { +func (tcm *TransactionCoordinatorMock) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { if tcm.ComputeTransactionTypeCalled == nil { - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, false } return tcm.ComputeTransactionTypeCalled(tx) diff --git a/node/external/transactionAPI/apiTransactionProcessor.go b/node/external/transactionAPI/apiTransactionProcessor.go index c6c568d46bf..37c4b56383c 100644 --- a/node/external/transactionAPI/apiTransactionProcessor.go +++ b/node/external/transactionAPI/apiTransactionProcessor.go @@ -183,7 +183,11 @@ func (atp *apiTransactionProcessor) PopulateComputedFields(tx *transaction.ApiTr } func (atp *apiTransactionProcessor) populateComputedFieldsProcessingType(tx *transaction.ApiTransactionResult) { - typeOnSource, typeOnDestination := atp.txTypeHandler.ComputeTransactionType(tx.Tx) + typeOnSource, typeOnDestination, isRelayedV3 := atp.txTypeHandler.ComputeTransactionType(tx.Tx) + if isRelayedV3 { + typeOnSource = process.RelayedTxV3 + typeOnDestination = process.RelayedTxV3 + } tx.ProcessingTypeOnSource = typeOnSource.String() tx.ProcessingTypeOnDestination = typeOnDestination.String() } diff --git a/node/external/transactionAPI/apiTransactionProcessor_test.go b/node/external/transactionAPI/apiTransactionProcessor_test.go index e6a7040fe87..52df3f50f82 100644 --- a/node/external/transactionAPI/apiTransactionProcessor_test.go +++ b/node/external/transactionAPI/apiTransactionProcessor_test.go @@ -1303,8 +1303,8 @@ func TestApiTransactionProcessor_GetTransactionPopulatesComputedFields(t *testin }) t.Run("ProcessingType", func(t *testing.T) { - txTypeHandler.ComputeTransactionTypeCalled = func(data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.SCDeployment + txTypeHandler.ComputeTransactionTypeCalled = func(data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.SCDeployment, false } dataPool.Transactions().AddData([]byte{0, 2}, &transaction.Transaction{Nonce: 7, SndAddr: []byte("alice"), RcvAddr: []byte("bob")}, 42, "1") @@ -1347,8 +1347,8 @@ func TestApiTransactionProcessor_PopulateComputedFields(t *testing.T) { require.Nil(t, err) require.NotNil(t, processor) - txTypeHandler.ComputeTransactionTypeCalled = func(data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.SCDeployment + txTypeHandler.ComputeTransactionTypeCalled = func(data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.SCDeployment, false } feeComputer.ComputeTransactionFeeCalled = func(tx *transaction.ApiTransactionResult) *big.Int { diff --git a/node/node.go b/node/node.go index 512d199a531..30fff1e6a78 100644 --- a/node/node.go +++ b/node/node.go @@ -798,6 +798,7 @@ func (n *Node) commonTransactionValidation( enableSignWithTxHash, n.coreComponents.TxSignHasher(), n.coreComponents.TxVersionChecker(), + n.coreComponents.EnableEpochsHandler(), ) if err != nil { return nil, nil, err diff --git a/process/block/preprocess/gasComputation.go b/process/block/preprocess/gasComputation.go index 628c6de455f..f4e6a82b4a9 100644 --- a/process/block/preprocess/gasComputation.go +++ b/process/block/preprocess/gasComputation.go @@ -374,7 +374,7 @@ func (gc *gasComputation) ComputeGasProvidedByTx( return txHandler.GetGasLimit(), txHandler.GetGasLimit(), nil } - txTypeSndShard, txTypeDstShard := gc.txTypeHandler.ComputeTransactionType(txHandler) + txTypeSndShard, txTypeDstShard, _ := gc.txTypeHandler.ComputeTransactionType(txHandler) isSCCall := txTypeDstShard == process.SCDeployment || txTypeDstShard == process.SCInvoking || txTypeDstShard == process.BuiltInFunctionCall @@ -403,7 +403,7 @@ func (gc *gasComputation) computeGasProvidedByTxV1( ) (uint64, uint64, error) { moveBalanceConsumption := gc.economicsFee.ComputeGasLimit(txHandler) - txTypeInShard, _ := gc.txTypeHandler.ComputeTransactionType(txHandler) + txTypeInShard, _, _ := gc.txTypeHandler.ComputeTransactionType(txHandler) isSCCall := txTypeInShard == process.SCDeployment || txTypeInShard == process.SCInvoking || txTypeInShard == process.BuiltInFunctionCall || diff --git a/process/block/preprocess/gasComputation_test.go b/process/block/preprocess/gasComputation_test.go index b59d8b45bf1..f60a7455fa6 100644 --- a/process/block/preprocess/gasComputation_test.go +++ b/process/block/preprocess/gasComputation_test.go @@ -214,8 +214,8 @@ func TestComputeGasProvidedByTx_ShouldWorkWhenTxReceiverAddressIsASmartContractI }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }}, createEnableEpochsHandler(), ) @@ -237,8 +237,8 @@ func TestComputeGasProvidedByTx_ShouldWorkWhenTxReceiverAddressIsASmartContractC }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.SCInvoking, false }}, createEnableEpochsHandler(), ) @@ -260,8 +260,8 @@ func TestComputeGasProvidedByTx_ShouldReturnZeroIf0GasLimit(t *testing.T) { }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.SCInvoking, false }}, createEnableEpochsHandler(), ) @@ -283,8 +283,8 @@ func TestComputeGasProvidedByTx_ShouldReturnGasLimitIfLessThanMoveBalance(t *tes }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.SCInvoking, false }}, createEnableEpochsHandler(), ) @@ -306,8 +306,8 @@ func TestComputeGasProvidedByTx_ShouldReturnGasLimitWhenRelayed(t *testing.T) { }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.RelayedTx, process.RelayedTx + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.RelayedTx, process.RelayedTx, false }}, createEnableEpochsHandler(), ) @@ -329,8 +329,8 @@ func TestComputeGasProvidedByTx_ShouldReturnGasLimitWhenRelayedV2(t *testing.T) }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.RelayedTxV2, process.RelayedTxV2 + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.RelayedTxV2, process.RelayedTxV2, false }}, createEnableEpochsHandler(), ) @@ -413,11 +413,11 @@ func TestComputeGasProvidedByMiniBlock_ShouldWork(t *testing.T) { }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { if core.IsSmartContractAddress(tx.GetRcvAddr()) { - return process.MoveBalance, process.SCInvoking + return process.MoveBalance, process.SCInvoking, false } - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, false }}, createEnableEpochsHandler(), ) @@ -453,11 +453,11 @@ func TestComputeGasProvidedByMiniBlock_ShouldWorkV1(t *testing.T) { }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { if core.IsSmartContractAddress(tx.GetRcvAddr()) { - return process.SCInvoking, process.SCInvoking + return process.SCInvoking, process.SCInvoking, false } - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, false }}, enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) @@ -513,8 +513,8 @@ func TestComputeGasProvidedByTx_ShouldWorkWhenTxReceiverAddressIsASmartContractI }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }}, createEnableEpochsHandler(), ) @@ -536,8 +536,8 @@ func TestComputeGasProvidedByTx_ShouldWorkWhenTxReceiverAddressIsASmartContractC }, }, &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }}, enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) diff --git a/process/block/preprocess/transactionsV2.go b/process/block/preprocess/transactionsV2.go index 6391987983a..eec4dfe21bd 100644 --- a/process/block/preprocess/transactionsV2.go +++ b/process/block/preprocess/transactionsV2.go @@ -561,7 +561,7 @@ func (txs *transactions) getTxAndMbInfo( } numNewTxs := 1 - _, txTypeDstShard := txs.txTypeHandler.ComputeTransactionType(tx) + _, txTypeDstShard, _ := txs.txTypeHandler.ComputeTransactionType(tx) isReceiverSmartContractAddress := txTypeDstShard == process.SCDeployment || txTypeDstShard == process.SCInvoking isCrossShardScCallOrSpecialTx := receiverShardID != txs.shardCoordinator.SelfId() && (isReceiverSmartContractAddress || len(tx.RcvUserName) > 0) @@ -695,7 +695,7 @@ func (txs *transactions) shouldContinueProcessingScheduledTx( mbInfo.senderAddressToSkip = tx.GetSndAddr() - _, txTypeDstShard := txs.txTypeHandler.ComputeTransactionType(tx) + _, txTypeDstShard, _ := txs.txTypeHandler.ComputeTransactionType(tx) isReceiverSmartContractAddress := txTypeDstShard == process.SCDeployment || txTypeDstShard == process.SCInvoking if !isReceiverSmartContractAddress { return nil, nil, false diff --git a/process/block/preprocess/transactionsV2_test.go b/process/block/preprocess/transactionsV2_test.go index 9d4fb1cf686..1c86454ddda 100644 --- a/process/block/preprocess/transactionsV2_test.go +++ b/process/block/preprocess/transactionsV2_test.go @@ -66,11 +66,11 @@ func createTransactionPreprocessor() *transactions { }, EnableEpochsHandler: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, TxTypeHandler: &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { if bytes.Equal(tx.GetRcvAddr(), []byte("smart contract address")) { - return process.MoveBalance, process.SCInvoking + return process.MoveBalance, process.SCInvoking, false } - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, false }, }, ScheduledTxsExecutionHandler: &testscommon.ScheduledTxsExecutionStub{}, diff --git a/process/coordinator/process.go b/process/coordinator/process.go index 8a50d9f0b21..dbc68612649 100644 --- a/process/coordinator/process.go +++ b/process/coordinator/process.go @@ -1622,7 +1622,7 @@ func (tc *transactionCoordinator) checkGasProvidedByMiniBlockInReceiverShard( return process.ErrMissingTransaction } - _, txTypeDstShard := tc.txTypeHandler.ComputeTransactionType(txHandler) + _, txTypeDstShard, _ := tc.txTypeHandler.ComputeTransactionType(txHandler) moveBalanceGasLimit := tc.economicsFee.ComputeGasLimit(txHandler) if txTypeDstShard == process.MoveBalance { gasProvidedByTxInReceiverShard = moveBalanceGasLimit diff --git a/process/coordinator/process_test.go b/process/coordinator/process_test.go index d1dff667cb7..6b7fa57a9fd 100644 --- a/process/coordinator/process_test.go +++ b/process/coordinator/process_test.go @@ -3245,8 +3245,8 @@ func TestTransactionCoordinator_CheckGasProvidedByMiniBlockInReceiverShardShould }, }, TxTypeHandler: &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.SCInvoking, false }, }, TransactionsLogProcessor: &mock.TxLogsProcessorStub{}, @@ -3302,8 +3302,8 @@ func TestTransactionCoordinator_CheckGasProvidedByMiniBlockInReceiverShardShould }, }, TxTypeHandler: &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.SCInvoking, false }, }, TransactionsLogProcessor: &mock.TxLogsProcessorStub{}, diff --git a/process/coordinator/transactionType.go b/process/coordinator/transactionType.go index 77de8a5476a..871d670538c 100644 --- a/process/coordinator/transactionType.go +++ b/process/coordinator/transactionType.go @@ -77,63 +77,61 @@ func NewTxTypeHandler( } // ComputeTransactionType calculates the transaction type -func (tth *txTypeHandler) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { +func (tth *txTypeHandler) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { err := tth.checkTxValidity(tx) if err != nil { - return process.InvalidTransaction, process.InvalidTransaction + return process.InvalidTransaction, process.InvalidTransaction, false } - if common.IsValidRelayedTxV3(tx) { - return process.RelayedTxV3, process.RelayedTxV3 - } + isRelayedV3 := common.IsValidRelayedTxV3(tx) isEmptyAddress := tth.isDestAddressEmpty(tx) if isEmptyAddress { if len(tx.GetData()) > 0 { - return process.SCDeployment, process.SCDeployment + return process.SCDeployment, process.SCDeployment, isRelayedV3 } - return process.InvalidTransaction, process.InvalidTransaction + return process.InvalidTransaction, process.InvalidTransaction, isRelayedV3 } if len(tx.GetData()) == 0 { - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, isRelayedV3 } funcName, args := tth.getFunctionFromArguments(tx.GetData()) isBuiltInFunction := tth.isBuiltInFunctionCall(funcName) if isBuiltInFunction { if tth.isSCCallAfterBuiltIn(funcName, args, tx) { - return process.BuiltInFunctionCall, process.SCInvoking + return process.BuiltInFunctionCall, process.SCInvoking, isRelayedV3 } - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, isRelayedV3 } if isCallOfType(tx, vm.AsynchronousCallBack) { - return process.SCInvoking, process.SCInvoking + return process.SCInvoking, process.SCInvoking, isRelayedV3 } if len(funcName) == 0 { - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, isRelayedV3 } if tth.isRelayedTransactionV1(funcName) { - return process.RelayedTx, process.RelayedTx + return process.RelayedTx, process.RelayedTx, isRelayedV3 // this should never be reached with both relayed v1 and relayed v3 } if tth.isRelayedTransactionV2(funcName) { - return process.RelayedTxV2, process.RelayedTxV2 + return process.RelayedTxV2, process.RelayedTxV2, isRelayedV3 // this should never be reached with both relayed v2 and relayed v3 } isDestInSelfShard := tth.isDestAddressInSelfShard(tx.GetRcvAddr()) if isDestInSelfShard && core.IsSmartContractAddress(tx.GetRcvAddr()) { - return process.SCInvoking, process.SCInvoking + return process.SCInvoking, process.SCInvoking, isRelayedV3 } if core.IsSmartContractAddress(tx.GetRcvAddr()) { - return process.MoveBalance, process.SCInvoking + return process.MoveBalance, process.SCInvoking, isRelayedV3 } - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, isRelayedV3 } func isCallOfType(tx data.TransactionHandler, callType vm.CallType) bool { diff --git a/process/coordinator/transactionType_test.go b/process/coordinator/transactionType_test.go index 705b45c78e8..ef00e924141 100644 --- a/process/coordinator/transactionType_test.go +++ b/process/coordinator/transactionType_test.go @@ -124,9 +124,10 @@ func TestTxTypeHandler_ComputeTransactionTypeNil(t *testing.T) { assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(nil) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(nil) assert.Equal(t, process.InvalidTransaction, txTypeIn) assert.Equal(t, process.InvalidTransaction, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeNilTx(t *testing.T) { @@ -145,9 +146,10 @@ func TestTxTypeHandler_ComputeTransactionTypeNilTx(t *testing.T) { tx.Value = big.NewInt(45) tx = nil - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.InvalidTransaction, txTypeIn) assert.Equal(t, process.InvalidTransaction, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeErrWrongTransaction(t *testing.T) { @@ -165,9 +167,10 @@ func TestTxTypeHandler_ComputeTransactionTypeErrWrongTransaction(t *testing.T) { tx.RcvAddr = nil tx.Value = big.NewInt(45) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.InvalidTransaction, txTypeIn) assert.Equal(t, process.InvalidTransaction, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeScDeployment(t *testing.T) { @@ -186,9 +189,10 @@ func TestTxTypeHandler_ComputeTransactionTypeScDeployment(t *testing.T) { tx.Data = []byte("data") tx.Value = big.NewInt(45) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.SCDeployment, txTypeIn) assert.Equal(t, process.SCDeployment, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeBuiltInFunctionCallNftTransfer(t *testing.T) { @@ -221,9 +225,10 @@ func TestTxTypeHandler_ComputeTransactionTypeBuiltInFunctionCallNftTransfer(t *t tx.Value = big.NewInt(45) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.BuiltInFunctionCall, txTypeIn) assert.Equal(t, process.SCInvoking, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeBuiltInFunctionCallEsdtTransfer(t *testing.T) { @@ -250,9 +255,10 @@ func TestTxTypeHandler_ComputeTransactionTypeBuiltInFunctionCallEsdtTransfer(t * "@" + hex.EncodeToString(big.NewInt(10).Bytes())) tx.Value = big.NewInt(45) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.BuiltInFunctionCall, txTypeIn) assert.Equal(t, process.BuiltInFunctionCall, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeRecv0AddressWrongTransaction(t *testing.T) { @@ -271,9 +277,10 @@ func TestTxTypeHandler_ComputeTransactionTypeRecv0AddressWrongTransaction(t *tes tx.Data = nil tx.Value = big.NewInt(45) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.InvalidTransaction, txTypeIn) assert.Equal(t, process.InvalidTransaction, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeScInvoking(t *testing.T) { @@ -292,9 +299,10 @@ func TestTxTypeHandler_ComputeTransactionTypeScInvoking(t *testing.T) { assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.SCInvoking, txTypeIn) assert.Equal(t, process.SCInvoking, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeMoveBalance(t *testing.T) { @@ -318,9 +326,10 @@ func TestTxTypeHandler_ComputeTransactionTypeMoveBalance(t *testing.T) { assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.MoveBalance, txTypeIn) assert.Equal(t, process.MoveBalance, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeBuiltInFunc(t *testing.T) { @@ -347,9 +356,10 @@ func TestTxTypeHandler_ComputeTransactionTypeBuiltInFunc(t *testing.T) { assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.BuiltInFunctionCall, txTypeIn) assert.Equal(t, process.BuiltInFunctionCall, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeBuiltInFuncNotActiveMoveBalance(t *testing.T) { @@ -378,9 +388,10 @@ func TestTxTypeHandler_ComputeTransactionTypeBuiltInFuncNotActiveMoveBalance(t * assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.MoveBalance, txTypeIn) assert.Equal(t, process.MoveBalance, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeBuiltInFuncNotActiveSCCall(t *testing.T) { @@ -409,9 +420,10 @@ func TestTxTypeHandler_ComputeTransactionTypeBuiltInFuncNotActiveSCCall(t *testi assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.SCInvoking, txTypeIn) assert.Equal(t, process.SCInvoking, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeRelayedFunc(t *testing.T) { @@ -435,9 +447,10 @@ func TestTxTypeHandler_ComputeTransactionTypeRelayedFunc(t *testing.T) { assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.RelayedTx, txTypeIn) assert.Equal(t, process.RelayedTx, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeRelayedV2Func(t *testing.T) { @@ -461,9 +474,10 @@ func TestTxTypeHandler_ComputeTransactionTypeRelayedV2Func(t *testing.T) { assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.RelayedTxV2, txTypeIn) assert.Equal(t, process.RelayedTxV2, txTypeCross) + assert.False(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeRelayedV3(t *testing.T) { @@ -489,9 +503,10 @@ func TestTxTypeHandler_ComputeTransactionTypeRelayedV3(t *testing.T) { assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) - assert.Equal(t, process.RelayedTxV3, txTypeIn) - assert.Equal(t, process.RelayedTxV3, txTypeCross) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) + assert.Equal(t, process.MoveBalance, txTypeIn) + assert.Equal(t, process.MoveBalance, txTypeCross) + assert.True(t, isRelayedV3) } func TestTxTypeHandler_ComputeTransactionTypeForSCRCallBack(t *testing.T) { @@ -516,7 +531,8 @@ func TestTxTypeHandler_ComputeTransactionTypeForSCRCallBack(t *testing.T) { assert.NotNil(t, tth) assert.Nil(t, err) - txTypeIn, txTypeCross := tth.ComputeTransactionType(tx) + txTypeIn, txTypeCross, isRelayedV3 := tth.ComputeTransactionType(tx) assert.Equal(t, process.SCInvoking, txTypeIn) assert.Equal(t, process.SCInvoking, txTypeCross) + assert.False(t, isRelayedV3) } diff --git a/process/disabled/txTypeHandler.go b/process/disabled/txTypeHandler.go index 302e81af555..dd405edff4d 100644 --- a/process/disabled/txTypeHandler.go +++ b/process/disabled/txTypeHandler.go @@ -17,9 +17,9 @@ func NewTxTypeHandler() *txTypeHandler { } // ComputeTransactionType always returns invalid transaction as it is disabled -func (handler *txTypeHandler) ComputeTransactionType(_ data.TransactionHandler) (process.TransactionType, process.TransactionType) { +func (handler *txTypeHandler) ComputeTransactionType(_ data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { log.Warn("disabled txTypeHandler ComputeTransactionType always returns invalid transaction") - return process.InvalidTransaction, process.InvalidTransaction + return process.InvalidTransaction, process.InvalidTransaction, false } // IsInterfaceNil returns true if there is no value under the interface diff --git a/process/interceptors/factory/interceptedTxDataFactory.go b/process/interceptors/factory/interceptedTxDataFactory.go index 563997c5066..0e1a568ad53 100644 --- a/process/interceptors/factory/interceptedTxDataFactory.go +++ b/process/interceptors/factory/interceptedTxDataFactory.go @@ -130,6 +130,7 @@ func (itdf *interceptedTxDataFactory) Create(buff []byte) (process.InterceptedDa itdf.enableEpochsHandler.IsFlagEnabled(common.TransactionSignedWithTxHashFlag), itdf.txSignHasher, itdf.txVersionChecker, + itdf.enableEpochsHandler, ) } diff --git a/process/interface.go b/process/interface.go index 747103f26ca..f7a4dfbd533 100644 --- a/process/interface.go +++ b/process/interface.go @@ -68,7 +68,7 @@ type SmartContractProcessorFacade interface { // TxTypeHandler is an interface to calculate the transaction type type TxTypeHandler interface { - ComputeTransactionType(tx data.TransactionHandler) (TransactionType, TransactionType) + ComputeTransactionType(tx data.TransactionHandler) (TransactionType, TransactionType, bool) IsInterfaceNil() bool } diff --git a/process/smartContract/process.go b/process/smartContract/process.go index 25031dcbf4a..8fbabd38df3 100644 --- a/process/smartContract/process.go +++ b/process/smartContract/process.go @@ -955,7 +955,7 @@ func (sc *scProcessor) doExecuteBuiltInFunction( return sc.finishSCExecution(make([]data.TransactionHandler, 0), txHash, tx, vmOutput, 0) } - _, txTypeOnDst := sc.txTypeHandler.ComputeTransactionType(tx) + _, txTypeOnDst, _ := sc.txTypeHandler.ComputeTransactionType(tx) builtInFuncGasUsed, err := sc.computeBuiltInFuncGasUsed(txTypeOnDst, vmInput.Function, vmInput.GasProvided, vmOutput.GasRemaining, check.IfNil(acntSnd)) log.LogIfError(err, "function", "ExecuteBuiltInFunction.computeBuiltInFuncGasUsed") @@ -1473,7 +1473,7 @@ func (sc *scProcessor) processIfErrorWithAddedLogs( Logs: processIfErrorLogs, }, 0) - txType, _ := sc.txTypeHandler.ComputeTransactionType(tx) + txType, _, _ := sc.txTypeHandler.ComputeTransactionType(tx) isCrossShardMoveBalance := txType == process.MoveBalance && check.IfNil(acntSnd) if isCrossShardMoveBalance && sc.enableEpochsHandler.IsFlagEnabled(common.SCDeployFlag) { // move balance was already consumed in sender shard @@ -2808,7 +2808,7 @@ func (sc *scProcessor) ProcessSmartContractResult(scr *smartContractResult.Smart gasLocked := sc.getGasLockedFromSCR(scr) - txType, _ := sc.txTypeHandler.ComputeTransactionType(scr) + txType, _, _ := sc.txTypeHandler.ComputeTransactionType(scr) switch txType { case process.MoveBalance: err = sc.processSimpleSCR(scr, txHash, dstAcc) diff --git a/process/smartContract/process_test.go b/process/smartContract/process_test.go index bc8caf169f3..b6c81113f45 100644 --- a/process/smartContract/process_test.go +++ b/process/smartContract/process_test.go @@ -3196,8 +3196,8 @@ func TestScProcessor_ProcessSmartContractResultDeploySCShouldError(t *testing.T) arguments.AccountsDB = accountsDB arguments.ShardCoordinator = shardCoordinator arguments.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCDeployment, process.SCDeployment + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCDeployment, process.SCDeployment, false }, } sc, err := NewSmartContractProcessor(arguments) @@ -3257,8 +3257,8 @@ func TestScProcessor_ProcessSmartContractResultExecuteSC(t *testing.T) { }, } arguments.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } sc, err := NewSmartContractProcessor(arguments) @@ -3320,8 +3320,8 @@ func TestScProcessor_ProcessSmartContractResultExecuteSCIfMetaAndBuiltIn(t *test }, } arguments.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }, } enableEpochsHandlerStub := enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.SCDeployFlag) @@ -3394,8 +3394,8 @@ func TestScProcessor_ProcessRelayedSCRValueBackToRelayer(t *testing.T) { }, } arguments.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } sc, err := NewSmartContractProcessor(arguments) diff --git a/process/smartContract/processorV2/processV2.go b/process/smartContract/processorV2/processV2.go index e34f0ac72aa..0dd370cb665 100644 --- a/process/smartContract/processorV2/processV2.go +++ b/process/smartContract/processorV2/processV2.go @@ -603,9 +603,6 @@ func (sc *scProcessor) updateDeveloperRewards( } moveBalanceGasLimit := sc.economicsFee.ComputeGasLimit(tx) - if common.IsValidRelayedTxV3(tx) { - moveBalanceGasLimit -= sc.economicsFee.MinGasLimit() // this was already consumed from the relayer - } if !isSmartContractResult(tx) { usedGasByMainSC, err = core.SafeSubUint64(usedGasByMainSC, moveBalanceGasLimit) if err != nil { @@ -747,9 +744,6 @@ func (sc *scProcessor) computeTotalConsumedFeeAndDevRwd( } moveBalanceGasLimit := sc.economicsFee.ComputeGasLimit(tx) - if common.IsValidRelayedTxV3(tx) { - moveBalanceGasLimit -= sc.economicsFee.MinGasLimit() // this was already consumed from the relayer - } if !isSmartContractResult(tx) { displayConsumedGas := consumedGas consumedGas, err = core.SafeSubUint64(consumedGas, moveBalanceGasLimit) @@ -811,15 +805,17 @@ func (sc *scProcessor) deleteSCRsWithValueZeroGoingToMeta(scrs []data.Transactio } func (sc *scProcessor) saveAccounts(acntSnd, acntDst vmcommon.AccountHandler) error { - if !check.IfNil(acntSnd) { - err := sc.accounts.SaveAccount(acntSnd) - if err != nil { - return err - } + err := sc.saveAccount(acntSnd) + if err != nil { + return err } - if !check.IfNil(acntDst) { - err := sc.accounts.SaveAccount(acntDst) + return sc.saveAccount(acntDst) +} + +func (sc *scProcessor) saveAccount(account vmcommon.AccountHandler) error { + if !check.IfNil(account) { + err := sc.accounts.SaveAccount(account) if err != nil { return err } @@ -937,7 +933,7 @@ func (sc *scProcessor) doExecuteBuiltInFunctionWithoutFailureProcessing( return sc.finishSCExecution(make([]data.TransactionHandler, 0), txHash, tx, vmOutput, 0) } - _, txTypeOnDst := sc.txTypeHandler.ComputeTransactionType(tx) + _, txTypeOnDst, _ := sc.txTypeHandler.ComputeTransactionType(tx) builtInFuncGasUsed, err := sc.computeBuiltInFuncGasUsed(txTypeOnDst, vmInput.Function, vmInput.GasProvided, vmOutput.GasRemaining, check.IfNil(acntSnd)) log.LogIfError(err, "function", "ExecuteBuiltInFunction.computeBuiltInFuncGasUsed") @@ -1521,7 +1517,7 @@ func (sc *scProcessor) processIfErrorWithAddedLogs(acntSnd state.UserAccountHand log.Debug("scProcessor.ProcessIfError() save log", "error", ignorableError.Error()) } - txType, _ := sc.txTypeHandler.ComputeTransactionType(tx) + txType, _, _ := sc.txTypeHandler.ComputeTransactionType(tx) isCrossShardMoveBalance := txType == process.MoveBalance && check.IfNil(acntSnd) if isCrossShardMoveBalance { // move balance was already consumed in sender shard @@ -1683,6 +1679,20 @@ func isRelayedSCR(tx data.TransactionHandler) (*smartContractResult.SmartContrac return nil, false } +func getRelayedValues(tx data.TransactionHandler) ([]byte, *big.Int) { + relayedTx, isRelayed := isRelayedSCR(tx) + if isRelayed { + return relayedTx.RelayerAddr, big.NewInt(0) + } + + if common.IsValidRelayedTxV3(tx) { + relayedTx := tx.(data.RelayedTransactionHandler) + return relayedTx.GetRelayerAddr(), big.NewInt(0) + } + + return nil, nil +} + // refunds the transaction values minus the relayed value to the sender account // in case of failed smart contract execution - gas is consumed, value is sent back func (sc *scProcessor) addBackTxValues( @@ -1927,19 +1937,23 @@ func (sc *scProcessor) processSCPayment(tx data.TransactionHandler, acntSnd stat return err } - cost := sc.economicsFee.ComputeTxFee(tx) - cost = cost.Add(cost, tx.GetValue()) + feePayer, err := sc.getFeePayer(tx, acntSnd) + if err != nil { + return err + } - if common.IsValidRelayedTxV3(tx) { - // for relayed v3, fee was consumed from relayer - cost = tx.GetValue() + fee := sc.economicsFee.ComputeTxFee(tx) + err = feePayer.SubFromBalance(fee) + if err != nil { + return err } - if cost.Cmp(big.NewInt(0)) == 0 { - return nil + err = sc.saveAccount(feePayer) + if err != nil { + return err } - err = acntSnd.SubFromBalance(cost) + err = acntSnd.SubFromBalance(tx.GetValue()) if err != nil { return err } @@ -1947,6 +1961,24 @@ func (sc *scProcessor) processSCPayment(tx data.TransactionHandler, acntSnd stat return nil } +func (sc *scProcessor) getFeePayer(tx data.TransactionHandler, acntSnd state.UserAccountHandler) (state.UserAccountHandler, error) { + if !common.IsValidRelayedTxV3(tx) { + return acntSnd, nil + } + + relayedTx, ok := tx.(data.RelayedTransactionHandler) + if !ok { + return acntSnd, nil + } + + account, err := sc.getAccountFromAddress(relayedTx.GetRelayerAddr()) + if err != nil { + return nil, err + } + + return account, nil +} + func (sc *scProcessor) processVMOutput( vmInput *vmcommon.VMInput, vmOutput *vmcommon.VMOutput, @@ -2268,17 +2300,7 @@ func createBaseSCR( result.CallType = vmData.DirectCall setOriginalTxHash(result, txHash, tx) - relayedTx, isRelayed := isRelayedSCR(tx) - if isRelayed { - result.RelayedValue = big.NewInt(0) - result.RelayerAddr = relayedTx.RelayerAddr - } - - if common.IsValidRelayedTxV3(tx) { - relayedTx := tx.(data.RelayedTransactionHandler) - result.RelayedValue = big.NewInt(0) - result.RelayerAddr = relayedTx.GetRelayerAddr() - } + result.RelayerAddr, result.RelayedValue = getRelayedValues(tx) return result } @@ -2316,17 +2338,8 @@ func (sc *scProcessor) createAsyncCallBackSCRFromVMOutput( OriginalSender: origScr.GetOriginalSender(), } setOriginalTxHash(scr, txHash, tx) - relayedTx, isRelayed := isRelayedSCR(tx) - if isRelayed { - scr.RelayedValue = big.NewInt(0) - scr.RelayerAddr = relayedTx.RelayerAddr - } - if common.IsValidRelayedTxV3(tx) { - relayedTx := tx.(data.RelayedTransactionHandler) - scr.RelayedValue = big.NewInt(0) - scr.RelayerAddr = relayedTx.GetRelayerAddr() - } + scr.RelayerAddr, scr.RelayedValue = getRelayedValues(tx) sc.addVMOutputResultsToSCR(vmOutput, scr) @@ -2591,54 +2604,7 @@ func (sc *scProcessor) createSCRForSenderAndRelayer( rcvAddress = tx.GetRcvAddr() } - var refundGasToRelayerSCR *smartContractResult.SmartContractResult - relayedSCR, isRelayed := isRelayedSCR(tx) - shouldRefundGasToRelayerSCR := isRelayed && callType != vmData.AsynchronousCall && gasRefund.Cmp(zero) > 0 - if shouldRefundGasToRelayerSCR { - senderForRelayerRefund := tx.GetRcvAddr() - if !sc.isSelfShard(tx.GetRcvAddr()) { - senderForRelayerRefund = tx.GetSndAddr() - } - - refundGasToRelayerSCR = &smartContractResult.SmartContractResult{ - Nonce: relayedSCR.Nonce + 1, - Value: big.NewInt(0).Set(gasRefund), - RcvAddr: relayedSCR.RelayerAddr, - SndAddr: senderForRelayerRefund, - PrevTxHash: txHash, - OriginalTxHash: relayedSCR.OriginalTxHash, - GasPrice: tx.GetGasPrice(), - CallType: vmData.DirectCall, - ReturnMessage: []byte("gas refund for relayer"), - OriginalSender: relayedSCR.OriginalSender, - } - gasRemaining = 0 - } - - isRelayedV3 := common.IsValidRelayedTxV3(tx) - shouldRefundGasToRelayerSCR = isRelayedV3 && callType != vmData.AsynchronousCall && gasRefund.Cmp(zero) > 0 - if shouldRefundGasToRelayerSCR { - senderForRelayerRefund := tx.GetRcvAddr() - if !sc.isSelfShard(tx.GetRcvAddr()) { - senderForRelayerRefund = tx.GetSndAddr() - } - - relayedTx := tx.(data.RelayedTransactionHandler) - - refundGasToRelayerSCR = &smartContractResult.SmartContractResult{ - Nonce: tx.GetNonce() + 1, - Value: big.NewInt(0).Set(gasRefund), - RcvAddr: relayedTx.GetRelayerAddr(), - SndAddr: senderForRelayerRefund, - PrevTxHash: txHash, - OriginalTxHash: txHash, - GasPrice: tx.GetGasPrice(), - CallType: vmData.DirectCall, - ReturnMessage: []byte("gas refund for relayer"), - OriginalSender: tx.GetSndAddr(), - } - gasRemaining = 0 - } + refundGasToRelayerSCR := sc.createRefundGasToRelayerSCRIfNeeded(tx, txHash, callType, gasRefund) scTx := &smartContractResult.SmartContractResult{} scTx.Value = big.NewInt(0).Set(storageFreeRefund) @@ -2669,6 +2635,71 @@ func (sc *scProcessor) createSCRForSenderAndRelayer( return scTx, refundGasToRelayerSCR } +func (sc *scProcessor) createRefundGasToRelayerSCRIfNeeded( + tx data.TransactionHandler, + txHash []byte, + callType vmData.CallType, + gasRefund *big.Int, +) *smartContractResult.SmartContractResult { + relayedSCR, isRelayed := isRelayedSCR(tx) + shouldRefundGasToRelayerSCR := isRelayed && callType != vmData.AsynchronousCall && gasRefund.Cmp(zero) > 0 + if shouldRefundGasToRelayerSCR { + return sc.createRefundGasToRelayerSCR( + tx, + relayedSCR.Nonce+1, + relayedSCR.RelayerAddr, + relayedSCR.OriginalSender, + relayedSCR.OriginalTxHash, + txHash, + gasRefund) + } + + isRelayedV3 := common.IsValidRelayedTxV3(tx) + shouldRefundGasToRelayerSCR = isRelayedV3 && callType != vmData.AsynchronousCall && gasRefund.Cmp(zero) > 0 + if shouldRefundGasToRelayerSCR { + relayedTx := tx.(data.RelayedTransactionHandler) + + return sc.createRefundGasToRelayerSCR( + tx, + tx.GetNonce()+1, + relayedTx.GetRelayerAddr(), + tx.GetSndAddr(), + txHash, + txHash, + gasRefund) + } + + return nil +} + +func (sc *scProcessor) createRefundGasToRelayerSCR( + tx data.TransactionHandler, + nonce uint64, + relayerAddr []byte, + originalSender []byte, + prevTxHash []byte, + originalTxHash []byte, + refund *big.Int, +) *smartContractResult.SmartContractResult { + senderForRelayerRefund := tx.GetRcvAddr() + if !sc.isSelfShard(tx.GetRcvAddr()) { + senderForRelayerRefund = tx.GetSndAddr() + } + + return &smartContractResult.SmartContractResult{ + Nonce: nonce, + Value: big.NewInt(0).Set(refund), + RcvAddr: relayerAddr, + SndAddr: senderForRelayerRefund, + PrevTxHash: prevTxHash, + OriginalTxHash: originalTxHash, + GasPrice: tx.GetGasPrice(), + CallType: vmData.DirectCall, + ReturnMessage: []byte("gas refund for relayer"), + OriginalSender: originalSender, + } +} + func addReturnDataToSCR(vmOutput *vmcommon.VMOutput, scTx *smartContractResult.SmartContractResult) { for _, retData := range vmOutput.ReturnData { scTx.Data = append(scTx.Data, []byte("@"+hex.EncodeToString(retData))...) @@ -2768,7 +2799,7 @@ func (sc *scProcessor) ProcessSmartContractResult(scr *smartContractResult.Smart gasLocked := sc.getGasLockedFromSCR(scr) - txType, _ := sc.txTypeHandler.ComputeTransactionType(scr) + txType, _, _ := sc.txTypeHandler.ComputeTransactionType(scr) switch txType { case process.MoveBalance: err = sc.processSimpleSCR(scr, txHash, dstAcc) diff --git a/process/smartContract/processorV2/process_test.go b/process/smartContract/processorV2/process_test.go index 905c18a033d..638e096005e 100644 --- a/process/smartContract/processorV2/process_test.go +++ b/process/smartContract/processorV2/process_test.go @@ -3129,8 +3129,8 @@ func TestScProcessor_ProcessSmartContractResultDeploySCShouldError(t *testing.T) arguments.AccountsDB = accountsDB arguments.ShardCoordinator = shardCoordinator arguments.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCDeployment, process.SCDeployment + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCDeployment, process.SCDeployment, false }, } sc, err := NewSmartContractProcessorV2(arguments) @@ -3190,8 +3190,8 @@ func TestScProcessor_ProcessSmartContractResultExecuteSC(t *testing.T) { }, } arguments.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } sc, err := NewSmartContractProcessorV2(arguments) @@ -3253,8 +3253,8 @@ func TestScProcessor_ProcessSmartContractResultExecuteSCIfMetaAndBuiltIn(t *test }, } arguments.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }, } enableEpochsHandlerStub := enableEpochsHandlerMock.NewEnableEpochsHandlerStub() @@ -3327,8 +3327,8 @@ func TestScProcessor_ProcessRelayedSCRValueBackToRelayer(t *testing.T) { }, } arguments.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } wasSaveLogsCalled := false diff --git a/process/smartContract/processorV2/vmInputV2.go b/process/smartContract/processorV2/vmInputV2.go index 44b20b1bcc3..81dd1f9360c 100644 --- a/process/smartContract/processorV2/vmInputV2.go +++ b/process/smartContract/processorV2/vmInputV2.go @@ -7,7 +7,6 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/vm" - "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" vmcommon "github.com/multiversx/mx-chain-vm-common-go" ) @@ -41,14 +40,7 @@ func (sc *scProcessor) initializeVMInputFromTx(vmInput *vmcommon.VMInput, tx dat vmInput.CallValue = new(big.Int).Set(tx.GetValue()) vmInput.GasPrice = tx.GetGasPrice() - relayedTx, isRelayed := isRelayedSCR(tx) - if isRelayed { - vmInput.RelayerAddr = relayedTx.RelayerAddr - } - if common.IsValidRelayedTxV3(tx) { - relayedTx := tx.(data.RelayedTransactionHandler) - vmInput.RelayerAddr = relayedTx.GetRelayerAddr() - } + vmInput.RelayerAddr, _ = getRelayedValues(tx) vmInput.GasProvided, err = sc.prepareGasProvided(tx) if err != nil { @@ -73,10 +65,6 @@ func (sc *scProcessor) prepareGasProvided(tx data.TransactionHandler) (uint64, e } gasForTxData := sc.economicsFee.ComputeGasLimit(tx) - if common.IsValidRelayedTxV3(tx) { - gasForTxData -= sc.economicsFee.MinGasLimit() // this was already consumed from the relayer - } - if tx.GetGasLimit() < gasForTxData { return 0, process.ErrNotEnoughGas } diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 9aecdd534d4..5f745875547 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -120,7 +120,7 @@ func (txProc *baseTxProcessor) checkTxValues( isUserTxOfRelayed bool, ) error { if common.IsValidRelayedTxV3(tx) { - relayerAccount, _, err := txProc.getAccounts(tx.RelayerAddr, tx.RelayerAddr) + relayerAccount, err := txProc.getAccountFromAddress(tx.RelayerAddr) if err != nil { return err } @@ -244,7 +244,7 @@ func (txProc *baseTxProcessor) getFeePayer( return acntSnd, false, nil } - acntRelayer, _, err := txProc.getAccounts(tx.RelayerAddr, tx.RelayerAddr) + acntRelayer, err := txProc.getAccountFromAddress(tx.RelayerAddr) if err != nil { return nil, true, err } @@ -261,7 +261,7 @@ func (txProc *baseTxProcessor) computeInnerTxFee(tx *transaction.Transaction) *b } func (txProc *baseTxProcessor) computeInnerTxFeeAfterBaseCostFix(tx *transaction.Transaction) *big.Int { - _, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(tx) + _, dstShardTxType, _ := txProc.txTypeHandler.ComputeTransactionType(tx) if dstShardTxType == process.MoveBalance { return txProc.economicsFee.ComputeMoveBalanceFee(tx) } diff --git a/process/transaction/export_test.go b/process/transaction/export_test.go index f6c154dc6d1..9a3f4904cd0 100644 --- a/process/transaction/export_test.go +++ b/process/transaction/export_test.go @@ -6,6 +6,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "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/process" "github.com/multiversx/mx-chain-go/state" vmcommon "github.com/multiversx/mx-chain-vm-common-go" @@ -102,6 +103,11 @@ func (inTx *InterceptedTransaction) CheckMaxGasPrice() error { return inTx.checkMaxGasPrice() } +// SetEnableEpochsHandler sets the internal enable epochs handler +func (inTx *InterceptedTransaction) SetEnableEpochsHandler(handler common.EnableEpochsHandler) { + inTx.enableEpochsHandler = handler +} + // VerifyGuardian calls the un-exported method verifyGuardian func (txProc *txProcessor) VerifyGuardian(tx *transaction.Transaction, account state.UserAccountHandler) error { return txProc.verifyGuardian(tx, account) diff --git a/process/transaction/interceptedTransaction.go b/process/transaction/interceptedTransaction.go index b3c48a0eab2..533a0bf95c9 100644 --- a/process/transaction/interceptedTransaction.go +++ b/process/transaction/interceptedTransaction.go @@ -43,6 +43,7 @@ type InterceptedTransaction struct { sndShard uint32 isForCurrentShard bool enableSignedTxWithHash bool + enableEpochsHandler common.EnableEpochsHandler } // NewInterceptedTransaction returns a new instance of InterceptedTransaction @@ -62,6 +63,7 @@ func NewInterceptedTransaction( enableSignedTxWithHash bool, txSignHasher hashing.Hasher, txVersionChecker process.TxVersionCheckerHandler, + enableEpochsHandler common.EnableEpochsHandler, ) (*InterceptedTransaction, error) { if txBuff == nil { @@ -106,6 +108,9 @@ func NewInterceptedTransaction( if check.IfNil(txVersionChecker) { return nil, process.ErrNilTransactionVersionChecker } + if check.IfNil(enableEpochsHandler) { + return nil, process.ErrNilEnableEpochsHandler + } tx, err := createTx(protoMarshalizer, txBuff) if err != nil { @@ -128,6 +133,7 @@ func NewInterceptedTransaction( enableSignedTxWithHash: enableSignedTxWithHash, txVersionChecker: txVersionChecker, txSignHasher: txSignHasher, + enableEpochsHandler: enableEpochsHandler, } err = inTx.processFields(txBuff) @@ -238,6 +244,10 @@ func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transact return nil } + if !inTx.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsV3Flag) { + return process.ErrRelayedTxV3Disabled + } + err := inTx.integrity(tx) if err != nil { return err diff --git a/process/transaction/interceptedTransaction_test.go b/process/transaction/interceptedTransaction_test.go index 5a95cc15a24..9e63b66d2e9 100644 --- a/process/transaction/interceptedTransaction_test.go +++ b/process/transaction/interceptedTransaction_test.go @@ -15,6 +15,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" dataTransaction "github.com/multiversx/mx-chain-core-go/data/transaction" "github.com/multiversx/mx-chain-crypto-go" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/interceptors" "github.com/multiversx/mx-chain-go/process/mock" @@ -22,6 +23,7 @@ import ( "github.com/multiversx/mx-chain-go/process/transaction" "github.com/multiversx/mx-chain-go/testscommon" "github.com/multiversx/mx-chain-go/testscommon/economicsmocks" + "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" logger "github.com/multiversx/mx-chain-logger-go" @@ -115,6 +117,7 @@ func createInterceptedTxWithTxFeeHandlerAndVersionChecker(tx *dataTransaction.Tr false, &hashingMocks.HasherMock{}, txVerChecker, + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) } @@ -158,6 +161,7 @@ func createInterceptedTxFromPlainTx(tx *dataTransaction.Transaction, txFeeHandle false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) } @@ -206,6 +210,7 @@ func createInterceptedTxFromPlainTxWithArgParser(tx *dataTransaction.Transaction false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(tx.Version), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.RelayedTransactionsV3Flag), ) } @@ -230,6 +235,7 @@ func TestNewInterceptedTransaction_NilBufferShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -255,6 +261,7 @@ func TestNewInterceptedTransaction_NilArgsParser(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -280,6 +287,7 @@ func TestNewInterceptedTransaction_NilVersionChecker(t *testing.T) { false, &hashingMocks.HasherMock{}, nil, + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -305,6 +313,7 @@ func TestNewInterceptedTransaction_NilMarshalizerShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -330,6 +339,7 @@ func TestNewInterceptedTransaction_NilSignMarshalizerShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -355,6 +365,7 @@ func TestNewInterceptedTransaction_NilHasherShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -380,6 +391,7 @@ func TestNewInterceptedTransaction_NilKeyGenShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -405,6 +417,7 @@ func TestNewInterceptedTransaction_NilSignerShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -430,6 +443,7 @@ func TestNewInterceptedTransaction_NilPubkeyConverterShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -455,6 +469,7 @@ func TestNewInterceptedTransaction_NilCoordinatorShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -480,6 +495,7 @@ func TestNewInterceptedTransaction_NilFeeHandlerShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -505,6 +521,7 @@ func TestNewInterceptedTransaction_NilWhiteListerVerifiedTxsShouldErr(t *testing false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -530,6 +547,7 @@ func TestNewInterceptedTransaction_InvalidChainIDShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -555,12 +573,39 @@ func TestNewInterceptedTransaction_NilTxSignHasherShouldErr(t *testing.T) { false, nil, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) assert.Equal(t, process.ErrNilHasher, err) } +func TestNewInterceptedTransaction_NilEnableEpochsHandlerShouldErr(t *testing.T) { + t.Parallel() + + txi, err := transaction.NewInterceptedTransaction( + make([]byte, 0), + &mock.MarshalizerMock{}, + &mock.MarshalizerMock{}, + &hashingMocks.HasherMock{}, + &mock.SingleSignKeyGenMock{}, + &mock.SignerMock{}, + createMockPubKeyConverter(), + mock.NewOneShardCoordinatorMock(), + &economicsmocks.EconomicsHandlerStub{}, + &testscommon.WhiteListHandlerStub{}, + &testscommon.ArgumentParserMock{}, + []byte("chainID"), + false, + &hashingMocks.HasherMock{}, + versioning.NewTxVersionChecker(1), + nil, + ) + + assert.Nil(t, txi) + assert.Equal(t, process.ErrNilEnableEpochsHandler, err) +} + func TestNewInterceptedTransaction_UnmarshalingTxFailsShouldErr(t *testing.T) { t.Parallel() @@ -586,6 +631,7 @@ func TestNewInterceptedTransaction_UnmarshalingTxFailsShouldErr(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, txi) @@ -1056,6 +1102,7 @@ func TestInterceptedTransaction_CheckValiditySignedWithHashButNotEnabled(t *test false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) err := txi.CheckValidity() @@ -1116,6 +1163,7 @@ func TestInterceptedTransaction_CheckValiditySignedWithHashShouldWork(t *testing true, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) err := txi.CheckValidity() @@ -1201,6 +1249,7 @@ func TestInterceptedTransaction_ScTxDeployRecvShardIdShouldBeSendersShardId(t *t false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Nil(t, err) @@ -1340,6 +1389,7 @@ func TestInterceptedTransaction_CheckValiditySecondTimeDoesNotVerifySig(t *testi false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) require.Nil(t, err) @@ -1529,6 +1579,12 @@ func TestInterceptedTransaction_CheckValidityOfRelayedTxV3(t *testing.T) { tx.Signature = sigOk tx.RelayerSignature = sigOk + // flag not active should error + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + txi.SetEnableEpochsHandler(enableEpochsHandlerMock.NewEnableEpochsHandlerStub()) + err = txi.CheckValidity() + assert.Equal(t, process.ErrRelayedTxV3Disabled, err) + // sender in different shard than relayer should fail tx.RelayerAddr = bytes.Repeat([]byte("a"), len(relayerAddress)) txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) @@ -1698,6 +1754,7 @@ func TestInterceptedTransaction_Fee(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(0), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) assert.Equal(t, big.NewInt(0), txin.Fee()) @@ -1741,6 +1798,7 @@ func TestInterceptedTransaction_String(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(0), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), ) expectedFormat := fmt.Sprintf( diff --git a/process/transaction/metaProcess.go b/process/transaction/metaProcess.go index 577b9c963fb..090d4ad89e4 100644 --- a/process/transaction/metaProcess.go +++ b/process/transaction/metaProcess.go @@ -135,13 +135,7 @@ func (txProc *metaTxProcessor) ProcessTransaction(tx *transaction.Transaction) ( return 0, err } - txCopy := *tx - txType, _ := txProc.txTypeHandler.ComputeTransactionType(tx) - if txType == process.RelayedTxV3 { - // extract the inner transaction in order to get the proper user tx type - txCopy.RelayerSignature = nil - txType, _ = txProc.txTypeHandler.ComputeTransactionType(&txCopy) - } + txType, _, _ := txProc.txTypeHandler.ComputeTransactionType(tx) switch txType { case process.SCDeployment: return txProc.processSCDeployment(tx, tx.SndAddr) diff --git a/process/transaction/metaProcess_test.go b/process/transaction/metaProcess_test.go index eaaa1382d2e..42a04260077 100644 --- a/process/transaction/metaProcess_test.go +++ b/process/transaction/metaProcess_test.go @@ -277,8 +277,8 @@ func TestMetaTxProcessor_ProcessTransactionScTxShouldWork(t *testing.T) { args.Accounts = adb args.ScProcessor = scProcessorMock args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } txProc, _ := txproc.NewMetaTxProcessor(args) @@ -323,8 +323,8 @@ func TestMetaTxProcessor_ProcessTransactionScTxShouldReturnErrWhenExecutionFails args.Accounts = adb args.ScProcessor = scProcessorMock args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } txProc, _ := txproc.NewMetaTxProcessor(args) @@ -439,8 +439,8 @@ func TestMetaTxProcessor_ProcessTransactionBuiltInCallTxShouldWork(t *testing.T) args.Accounts = adb args.ScProcessor = scProcessorMock args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }, } enableEpochsHandlerStub := enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.ESDTFlag) diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 5091fe71ba6..354ff22ef08 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -196,7 +196,7 @@ func (txProc *txProcessor) ProcessTransaction(tx *transaction.Transaction) (vmco txProc.pubkeyConv, ) - txType, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(tx) + txType, dstShardTxType, isRelayedV3 := txProc.txTypeHandler.ComputeTransactionType(tx) err = txProc.checkTxValues(tx, acntSnd, acntDst, false) if err != nil { if errors.Is(err, process.ErrInsufficientFunds) { @@ -223,9 +223,16 @@ func (txProc *txProcessor) ProcessTransaction(tx *transaction.Transaction) (vmco return vmcommon.UserError, err } + if isRelayedV3 { + err = txProc.verifyRelayedTxV3(tx) + if err != nil { + return vmcommon.UserError, err + } + } + switch txType { case process.MoveBalance: - err = txProc.processMoveBalance(tx, acntSnd, acntDst, dstShardTxType, nil, false, false) + err = txProc.processMoveBalance(tx, acntSnd, acntDst, dstShardTxType, nil, false) if err != nil { return vmcommon.UserError, txProc.executeAfterFailedMoveBalanceTransaction(tx, err) } @@ -240,8 +247,6 @@ func (txProc *txProcessor) ProcessTransaction(tx *transaction.Transaction) (vmco return txProc.processRelayedTx(tx, acntSnd, acntDst) case process.RelayedTxV2: return txProc.processRelayedTxV2(tx, acntSnd, acntDst) - case process.RelayedTxV3: - return txProc.processRelayedTxV3(tx) } return vmcommon.UserError, txProc.executingFailedTransaction(tx, acntSnd, process.ErrWrongTransaction) @@ -351,75 +356,16 @@ func (txProc *txProcessor) executingFailedTransaction( return process.ErrFailedTransaction } -func (txProc *txProcessor) executingFailedTransactionRelayedV3( - tx *transaction.Transaction, - acntSnd state.UserAccountHandler, - relayerAccount state.UserAccountHandler, - txError error, -) error { - if check.IfNil(relayerAccount) { - return nil - } - if check.IfNil(acntSnd) { - return nil - } - - txFee := txProc.economicsFee.ComputeTxFee(tx) - err := relayerAccount.SubFromBalance(txFee) - if err != nil { - return err - } - - txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) - if err != nil { - return err - } - - acntSnd.IncreaseNonce(1) - err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}, txHash) - if err != nil { - return err - } - - log.Trace("executingFailedTransactionRelayedV3", "fail reason(error)", txError, "tx hash", txHash) - - rpt := &receipt.Receipt{ - Value: big.NewInt(0).Set(txFee), - SndAddr: relayerAccount.AddressBytes(), - Data: []byte(txError.Error()), - TxHash: txHash, - } - - err = txProc.receiptForwarder.AddIntermediateTransactions([]data.TransactionHandler{rpt}, txHash) - if err != nil { - return err - } - - txProc.txFeeHandler.ProcessTransactionFee(txFee, big.NewInt(0), txHash) - - err = txProc.accounts.SaveAccount(relayerAccount) - if err != nil { - return err - } - - err = txProc.accounts.SaveAccount(acntSnd) - if err != nil { - return err - } - - return process.ErrFailedTransaction -} - func (txProc *txProcessor) createReceiptWithReturnedGas( txHash []byte, tx *transaction.Transaction, - acntSnd state.UserAccountHandler, + feePayer state.UserAccountHandler, moveBalanceCost *big.Int, totalProvided *big.Int, destShardTxType process.TransactionType, isUserTxOfRelayed bool, ) error { - if check.IfNil(acntSnd) || isUserTxOfRelayed { + if check.IfNil(feePayer) || isUserTxOfRelayed { return nil } shouldCreateReceiptBackwardCompatible := !txProc.enableEpochsHandler.IsFlagEnabled(common.MetaProtectionFlag) && core.IsSmartContractAddress(tx.RcvAddr) @@ -436,38 +382,33 @@ func (txProc *txProcessor) createReceiptWithReturnedGas( rpt := &receipt.Receipt{ Value: big.NewInt(0).Set(refundValue), - SndAddr: tx.SndAddr, + SndAddr: feePayer.AddressBytes(), Data: []byte(RefundGasMessage), TxHash: txHash, } - err := txProc.receiptForwarder.AddIntermediateTransactions([]data.TransactionHandler{rpt}, txHash) - if err != nil { - return err - } - - return nil + return txProc.receiptForwarder.AddIntermediateTransactions([]data.TransactionHandler{rpt}, txHash) } func (txProc *txProcessor) processTxFee( tx *transaction.Transaction, - acntSnd, acntDst state.UserAccountHandler, + feePayer, acntDst state.UserAccountHandler, dstShardTxType process.TransactionType, isUserTxOfRelayed bool, ) (*big.Int, *big.Int, error) { - if check.IfNil(acntSnd) { + if check.IfNil(feePayer) { return big.NewInt(0), big.NewInt(0), nil } if isUserTxOfRelayed { totalCost := txProc.computeInnerTxFee(tx) - err := acntSnd.SubFromBalance(totalCost) + err := feePayer.SubFromBalance(totalCost) if err != nil { return nil, nil, err } - err = txProc.accounts.SaveAccount(acntSnd) + err = txProc.accounts.SaveAccount(feePayer) if err != nil { return nil, nil, err } @@ -496,76 +437,23 @@ func (txProc *txProcessor) processTxFee( if dstShardTxType != process.MoveBalance || (!txProc.enableEpochsHandler.IsFlagEnabled(common.MetaProtectionFlag) && isCrossShardSCCall) { - err := acntSnd.SubFromBalance(totalCost) - if err != nil { - return nil, nil, err - } - - err = txProc.accounts.SaveAccount(acntSnd) + err := feePayer.SubFromBalance(totalCost) if err != nil { return nil, nil, err } } else { - err := acntSnd.SubFromBalance(moveBalanceFee) + err := feePayer.SubFromBalance(moveBalanceFee) if err != nil { return nil, nil, err } - - err = txProc.accounts.SaveAccount(acntSnd) - if err != nil { - return nil, nil, err - } - } - - return moveBalanceFee, totalCost, nil -} - -func (txProc *txProcessor) processTxFeeOfRelayedV3( - tx *transaction.Transaction, - txHash []byte, - relayerAccount state.UserAccountHandler, - destinationAccount state.UserAccountHandler, - dstShardTxType process.TransactionType, -) error { - if check.IfNil(relayerAccount) { - return nil - } - - moveBalanceFee := txProc.economicsFee.ComputeMoveBalanceFee(tx) - totalCost := txProc.economicsFee.ComputeTxFee(tx) - - if !txProc.enableEpochsHandler.IsFlagEnabled(common.PenalizedTooMuchGasFlag) { - totalCost = core.SafeMul(tx.GasLimit, tx.GasPrice) } - isCrossShardSCCall := check.IfNil(destinationAccount) && len(tx.GetData()) > 0 && core.IsSmartContractAddress(tx.GetRcvAddr()) - if dstShardTxType != process.MoveBalance || - (!txProc.enableEpochsHandler.IsFlagEnabled(common.MetaProtectionFlag) && isCrossShardSCCall) { - - err := relayerAccount.SubFromBalance(totalCost) - if err != nil { - return err - } - - err = txProc.accounts.SaveAccount(relayerAccount) - if err != nil { - return err - } - } else { - err := relayerAccount.SubFromBalance(moveBalanceFee) - if err != nil { - return err - } - - txProc.txFeeHandler.ProcessTransactionFee(moveBalanceFee, big.NewInt(0), txHash) - - err = txProc.accounts.SaveAccount(relayerAccount) - if err != nil { - return err - } + err := txProc.accounts.SaveAccount(feePayer) + if err != nil { + return nil, nil, err } - return nil + return moveBalanceFee, totalCost, nil } func (txProc *txProcessor) checkIfValidTxToMetaChain(tx *transaction.Transaction) error { @@ -596,10 +484,13 @@ func (txProc *txProcessor) processMoveBalance( destShardTxType process.TransactionType, originalTxHash []byte, isUserTxOfRelayed bool, - isUserTxOfRelayedV3 bool, ) error { - moveBalanceCost, totalCost, err := txProc.processTxFee(tx, acntSrc, acntDst, destShardTxType, isUserTxOfRelayed) + feePayer, _, err := txProc.getFeePayer(tx, acntSrc) + if err != nil { + return nil + } + moveBalanceCost, totalCost, err := txProc.processTxFee(tx, feePayer, acntDst, destShardTxType, isUserTxOfRelayed) if err != nil { return err } @@ -659,14 +550,7 @@ func (txProc *txProcessor) processMoveBalance( } txHash := originalTxHash - if !isUserTxOfRelayedV3 { - txHash, err = core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) - if err != nil { - return err - } - } - - err = txProc.createReceiptWithReturnedGas(txHash, tx, acntSrc, moveBalanceCost, totalCost, destShardTxType, isUserTxOfRelayed) + err = txProc.createReceiptWithReturnedGas(txHash, tx, feePayer, moveBalanceCost, totalCost, destShardTxType, isUserTxOfRelayed) if err != nil { return err } @@ -680,76 +564,6 @@ func (txProc *txProcessor) processMoveBalance( return nil } -func (txProc *txProcessor) processMoveBalanceOfRelayedV3( - tx *transaction.Transaction, - senderAccount state.UserAccountHandler, - destinationAccount state.UserAccountHandler, - relayerAccount state.UserAccountHandler, - destShardTxType process.TransactionType, - originalTxHash []byte, -) error { - err := txProc.processTxFeeOfRelayedV3(tx, originalTxHash, relayerAccount, destinationAccount, destShardTxType) - if err != nil { - return err - } - - // is sender address in node shard - if !check.IfNil(senderAccount) { - senderAccount.IncreaseNonce(1) - err = senderAccount.SubFromBalance(tx.Value) - if err != nil { - return err - } - - err = txProc.accounts.SaveAccount(senderAccount) - if err != nil { - return err - } - } - - isPayable, err := txProc.scProcessor.IsPayable(tx.SndAddr, tx.RcvAddr) - if err != nil { - errRefund := txProc.revertConsumedValueFromSender(tx, senderAccount, true) - if errRefund != nil { - log.Error("failed to return funds to sender after check if receiver is payable", "error", errRefund) - } - return err - } - if !isPayable { - err = txProc.revertConsumedValueFromSender(tx, senderAccount, true) - if err != nil { - log.Error("failed to return funds to sender while transferring to non payable sc", "error", err) - } - - return process.ErrAccountNotPayable - } - - err = txProc.checkIfValidTxToMetaChain(tx) - if err != nil { - errLocal := txProc.revertConsumedValueFromSender(tx, senderAccount, true) - if errLocal != nil { - log.Error("failed to return funds to sender while sending invalid tx to metachain", "error", errLocal) - } - - return err - } - - // is receiver address in node shard - if !check.IfNil(destinationAccount) { - err = destinationAccount.AddToBalance(tx.Value) - if err != nil { - return err - } - - err = txProc.accounts.SaveAccount(destinationAccount) - if err != nil { - return err - } - } - - return nil -} - func (txProc *txProcessor) revertConsumedValueFromSender( tx *transaction.Transaction, acntSrc state.UserAccountHandler, @@ -806,88 +620,6 @@ func makeUserTxFromRelayedTxV2Args(args [][]byte) *transaction.Transaction { return userTx } -func (txProc *txProcessor) finishExecutionOfRelayedTxV3( - relayerAccount state.UserAccountHandler, - tx *transaction.Transaction, - userTx *transaction.Transaction, -) (vmcommon.ReturnCode, error) { - txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) - if err != nil { - return 0, err - } - - senderAccount, destinationAccount, err := txProc.getAccounts(tx.SndAddr, tx.RcvAddr) - if err != nil { - errRemove := txProc.increaseSenderNonceIfNeededAndLog(txHash, tx, senderAccount, err) - if errRemove != nil { - return vmcommon.UserError, errRemove - } - return vmcommon.UserError, txProc.executeFailedRelayedV3UserTx( - tx, - txHash, - err.Error()) - } - - txType, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(userTx) - returnCode := vmcommon.Ok - switch txType { - case process.MoveBalance: - err = txProc.processMoveBalanceOfRelayedV3(tx, senderAccount, destinationAccount, relayerAccount, dstShardTxType, txHash) - case process.SCDeployment: - err = txProc.processTxFeeOfRelayedV3(tx, txHash, relayerAccount, destinationAccount, dstShardTxType) - if err != nil { - break - } - - returnCode, err = txProc.scProcessor.DeploySmartContract(tx, destinationAccount) - case process.SCInvoking: - err = txProc.processTxFeeOfRelayedV3(tx, txHash, relayerAccount, destinationAccount, dstShardTxType) - if err != nil { - break - } - - returnCode, err = txProc.scProcessor.ExecuteSmartContractTransaction(tx, senderAccount, destinationAccount) - case process.BuiltInFunctionCall: - err = txProc.processTxFeeOfRelayedV3(tx, txHash, relayerAccount, destinationAccount, dstShardTxType) - if err != nil { - break - } - - returnCode, err = txProc.scProcessor.ExecuteBuiltInFunction(tx, senderAccount, destinationAccount) - default: - err = process.ErrWrongTransaction - errRemove := txProc.increaseSenderNonceIfNeededAndLog(txHash, tx, senderAccount, err) - if errRemove != nil { - return vmcommon.UserError, errRemove - } - return vmcommon.UserError, txProc.executeFailedRelayedV3UserTx( - tx, - txHash, - err.Error()) - } - - if errors.Is(err, process.ErrInvalidMetaTransaction) || errors.Is(err, process.ErrAccountNotPayable) { - return vmcommon.UserError, txProc.executeFailedRelayedV3UserTx( - tx, - txHash, - err.Error()) - } - - if errors.Is(err, process.ErrFailedTransaction) { - // in case of failed inner user tx transaction we should just simply return execution failed and - // not failed transaction - as the actual transaction (the relayed we correctly executed) and thus - // it should not lend in the invalid miniblock - return vmcommon.ExecutionFailed, nil - } - - if err != nil { - log.Error("processUserTx", "protocolError", err) - return vmcommon.ExecutionFailed, err - } - - return returnCode, err -} - func (txProc *txProcessor) finishExecutionOfRelayedTx( relayerAcnt, acntDst state.UserAccountHandler, tx *transaction.Transaction, @@ -969,39 +701,29 @@ func (txProc *txProcessor) addFeeAndValueToDest(acntDst state.UserAccountHandler return txProc.accounts.SaveAccount(acntDst) } -func (txProc *txProcessor) processRelayedTxV3(tx *transaction.Transaction) (vmcommon.ReturnCode, error) { - relayerAccount, sndAccount, err := txProc.getAccounts(tx.RelayerAddr, tx.SndAddr) - if err != nil { - return 0, err - } - +func (txProc *txProcessor) verifyRelayedTxV3(tx *transaction.Transaction) error { if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsV3Flag) { - return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrRelayedTxV3Disabled) + return fmt.Errorf("%w, %s", process.ErrTransactionNotExecutable, process.ErrRelayedTxV3Disabled) } if !txProc.shardCoordinator.SameShard(tx.RelayerAddr, tx.SndAddr) { - return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrShardIdMissmatch) + return fmt.Errorf("%w, %s", process.ErrTransactionNotExecutable, process.ErrShardIdMissmatch) } - if !check.IfNil(relayerAccount) && relayerAccount.IsGuarded() { - return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrGuardedRelayerNotAllowed) + if bytes.Equal(tx.RelayerAddr, tx.GuardianAddr) { + return fmt.Errorf("%w, %s", process.ErrTransactionNotExecutable, process.ErrRelayedByGuardianNotAllowed) } - if bytes.Equal(tx.RelayerAddr, tx.GuardianAddr) { - return vmcommon.UserError, txProc.executingFailedTransactionRelayedV3(tx, sndAccount, relayerAccount, process.ErrRelayedByGuardianNotAllowed) + relayerAccount, err := txProc.getAccountFromAddress(tx.RelayerAddr) + if err != nil { + return fmt.Errorf("%w, %s", process.ErrTransactionNotExecutable, err) } - userTx := *tx - // remove relayer signature for tx type handler - // hash of this user tx won't be computed/used, but the originalTxHash - userTx.RelayerSignature = nil - minGasLimit := txProc.economicsFee.MinGasLimit() - userTx.GasLimit = userTx.GasLimit - minGasLimit - if userTx.GasLimit < txProc.economicsFee.ComputeGasLimit(&userTx) { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAccount, process.ErrInsufficientGasLimitInTx) + if !check.IfNil(relayerAccount) && relayerAccount.IsGuarded() { + return fmt.Errorf("%w, %s", process.ErrTransactionNotExecutable, process.ErrGuardedRelayerNotAllowed) } - return txProc.finishExecutionOfRelayedTxV3(relayerAccount, tx, &userTx) + return nil } func (txProc *txProcessor) processRelayedTxV2( @@ -1133,28 +855,6 @@ func (txProc *txProcessor) removeValueAndConsumedFeeFromUser( return nil } -func (txProc *txProcessor) increaseSenderNonceIfNeededAndLog( - originalTxHash []byte, - originalTx *transaction.Transaction, - senderAccount vmcommon.AccountHandler, - executionErr error, -) error { - if txProc.shouldIncreaseNonce(executionErr) { - if check.IfNil(senderAccount) { - return process.ErrNilUserAccount - } - - senderAccount.IncreaseNonce(1) - - err := txProc.accounts.SaveAccount(senderAccount) - if err != nil { - return err - } - } - - return txProc.addNonExecutableLog(executionErr, originalTxHash, originalTx) -} - func (txProc *txProcessor) addNonExecutableLog(executionErr error, originalTxHash []byte, originalTx data.TransactionHandler) error { if !isNonExecutableError(executionErr) { return nil @@ -1215,7 +915,7 @@ func (txProc *txProcessor) processUserTx( err.Error()) } - txType, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(userTx) + txType, dstShardTxType, _ := txProc.txTypeHandler.ComputeTransactionType(userTx) err = txProc.checkTxValues(userTx, acntSnd, acntDst, true) if err != nil { errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, relayedTxValue, originalTxHash, originalTx, err) @@ -1240,7 +940,7 @@ func (txProc *txProcessor) processUserTx( returnCode := vmcommon.Ok switch txType { case process.MoveBalance: - err = txProc.processMoveBalance(userTx, acntSnd, acntDst, dstShardTxType, originalTxHash, true, false) + err = txProc.processMoveBalance(userTx, acntSnd, acntDst, dstShardTxType, originalTxHash, true) case process.SCDeployment: err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) if err != nil { @@ -1429,43 +1129,6 @@ func (txProc *txProcessor) executeFailedRelayedUserTx( return nil } -func (txProc *txProcessor) executeFailedRelayedV3UserTx( - originalTx *transaction.Transaction, - originalTxHash []byte, - errorMsg string, -) error { - - scrForRelayer := &smartContractResult.SmartContractResult{ - Nonce: originalTx.Nonce, - Value: big.NewInt(0), - RcvAddr: originalTx.RelayerAddr, - SndAddr: originalTx.SndAddr, - PrevTxHash: originalTxHash, - OriginalTxHash: originalTxHash, - ReturnMessage: []byte(errorMsg), - } - - err := txProc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrForRelayer}, originalTxHash) - if err != nil { - return err - } - - moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(originalTx) - gasToUse := originalTx.GetGasLimit() - moveBalanceGasLimit - processingUserFee := txProc.economicsFee.ComputeFeeForProcessing(originalTx, gasToUse) - moveBalanceUserFee := txProc.economicsFee.ComputeMoveBalanceFee(originalTx) - totalFee := big.NewInt(0).Add(moveBalanceUserFee, processingUserFee) - - senderShardID := txProc.shardCoordinator.ComputeId(originalTx.SndAddr) - if senderShardID != txProc.shardCoordinator.SelfId() { - totalFee.Sub(totalFee, processingUserFee) - } - - txProc.txFeeHandler.ProcessTransactionFee(totalFee, big.NewInt(0), originalTxHash) - - return txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{originalTx}, originalTxHash) -} - func (txProc *txProcessor) shouldIncreaseNonce(executionErr error) bool { if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedNonceFixFlag) { return true diff --git a/process/transaction/shardProcess_test.go b/process/transaction/shardProcess_test.go index f65aadffb5f..905a6fc967b 100644 --- a/process/transaction/shardProcess_test.go +++ b/process/transaction/shardProcess_test.go @@ -1111,8 +1111,8 @@ func TestTxProcessor_ProcessTransactionScDeployTxShouldWork(t *testing.T) { args.Accounts = adb args.ScProcessor = scProcessorMock args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType process.TransactionType, destinationTransactionType process.TransactionType) { - return process.SCDeployment, process.SCDeployment + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType process.TransactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.SCDeployment, process.SCDeployment, false }, } execTx, _ := txproc.NewTxProcessor(args) @@ -1159,8 +1159,8 @@ func TestTxProcessor_ProcessTransactionBuiltInFunctionCallShouldWork(t *testing. args.Accounts = adb args.ScProcessor = scProcessorMock args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }, } execTx, _ := txproc.NewTxProcessor(args) @@ -1207,8 +1207,8 @@ func TestTxProcessor_ProcessTransactionScTxShouldWork(t *testing.T) { args.Accounts = adb args.ScProcessor = scProcessorMock args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } execTx, _ := txproc.NewTxProcessor(args) @@ -1253,8 +1253,8 @@ func TestTxProcessor_ProcessTransactionScTxShouldReturnErrWhenExecutionFails(t * args.Accounts = adb args.ScProcessor = scProcessorMock args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } execTx, _ := txproc.NewTxProcessor(args) @@ -1573,8 +1573,8 @@ func TestTxProcessor_ProcessTransactionShouldReturnErrForInvalidMetaTx(t *testin }, } args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.MoveBalance + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.MoveBalance, false }, } args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.MetaProtectionFlag) @@ -1621,8 +1621,8 @@ func TestTxProcessor_ProcessTransactionShouldTreatAsInvalidTxIfTxTypeIsWrong(t * }, } args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.InvalidTransaction, process.InvalidTransaction + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.InvalidTransaction, process.InvalidTransaction, false }, } execTx, _ := txproc.NewTxProcessor(args) @@ -2181,8 +2181,8 @@ func TestTxProcessor_ProcessRelayedTransactionArgsParserErrorShouldError(t *test return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.RelayedTx, process.RelayedTx + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.RelayedTx, process.RelayedTx, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -2244,8 +2244,8 @@ func TestTxProcessor_ProcessRelayedTransactionMultipleArgumentsShouldError(t *te return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.RelayedTx, process.RelayedTx + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.RelayedTx, process.RelayedTx, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -2307,8 +2307,8 @@ func TestTxProcessor_ProcessRelayedTransactionFailUnMarshalInnerShouldError(t *t return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.RelayedTx, process.RelayedTx + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.RelayedTx, process.RelayedTx, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -2370,8 +2370,8 @@ func TestTxProcessor_ProcessRelayedTransactionDifferentSenderInInnerTxThanReceiv return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.RelayedTx, process.RelayedTx + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.RelayedTx, process.RelayedTx, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -2433,8 +2433,8 @@ func TestTxProcessor_ProcessRelayedTransactionSmallerValueInnerTxShouldError(t * return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.RelayedTx, process.RelayedTx + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.RelayedTx, process.RelayedTx, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -2496,8 +2496,8 @@ func TestTxProcessor_ProcessRelayedTransactionGasPriceMismatchShouldError(t *tes return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.RelayedTx, process.RelayedTx + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.RelayedTx, process.RelayedTx, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -2559,8 +2559,8 @@ func TestTxProcessor_ProcessRelayedTransactionGasLimitMismatchShouldError(t *tes return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.RelayedTx, process.RelayedTx + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.RelayedTx, process.RelayedTx, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -2912,8 +2912,8 @@ func TestTxProcessor_ProcessUserTxOfTypeRelayedShouldError(t *testing.T) { return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.RelayedTx, process.RelayedTx + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.RelayedTx, process.RelayedTx, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -2975,8 +2975,8 @@ func TestTxProcessor_ProcessUserTxOfTypeMoveBalanceShouldWork(t *testing.T) { return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.MoveBalance, process.MoveBalance + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.MoveBalance, process.MoveBalance, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -3038,8 +3038,8 @@ func TestTxProcessor_ProcessUserTxOfTypeSCDeploymentShouldWork(t *testing.T) { return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.SCDeployment, process.SCDeployment + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.SCDeployment, process.SCDeployment, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -3101,8 +3101,8 @@ func TestTxProcessor_ProcessUserTxOfTypeSCInvokingShouldWork(t *testing.T) { return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.SCInvoking, process.SCInvoking + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.SCInvoking, process.SCInvoking, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -3164,8 +3164,8 @@ func TestTxProcessor_ProcessUserTxOfTypeBuiltInFunctionCallShouldWork(t *testing return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -3231,8 +3231,8 @@ func TestTxProcessor_ProcessUserTxErrNotPayableShouldFailRelayTx(t *testing.T) { return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.MoveBalance, process.MoveBalance + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.MoveBalance, process.MoveBalance, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -3300,8 +3300,8 @@ func TestTxProcessor_ProcessUserTxFailedBuiltInFunctionCall(t *testing.T) { return nil, errors.New("failure") } args.Accounts = adb - args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (transactionType, destinationTransactionType process.TransactionType, isRelayedV3 bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }} execTx, _ := txproc.NewTxProcessor(args) @@ -3522,13 +3522,13 @@ func TestTxProcessor_ProcessMoveBalanceToNonPayableContract(t *testing.T) { args.SignMarshalizer = &marshaller cnt := 0 args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { cnt++ if cnt == 1 { - return process.RelayedTx, process.RelayedTx + return process.RelayedTx, process.RelayedTx, false } - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, false }, } args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub( diff --git a/process/transactionEvaluator/transactionEvaluator.go b/process/transactionEvaluator/transactionEvaluator.go index 9e61d138419..c2e566490ef 100644 --- a/process/transactionEvaluator/transactionEvaluator.go +++ b/process/transactionEvaluator/transactionEvaluator.go @@ -111,7 +111,7 @@ func (ate *apiTransactionEvaluator) ComputeTransactionGasLimit(tx *transaction.T ate.mutExecution.Unlock() }() - txTypeOnSender, txTypeOnDestination := ate.txTypeHandler.ComputeTransactionType(tx) + txTypeOnSender, txTypeOnDestination, _ := ate.txTypeHandler.ComputeTransactionType(tx) if txTypeOnSender == process.MoveBalance && txTypeOnDestination == process.MoveBalance { return ate.computeMoveBalanceCost(tx), nil } diff --git a/process/transactionEvaluator/transactionEvaluator_test.go b/process/transactionEvaluator/transactionEvaluator_test.go index f36a5388777..bfcbf97f787 100644 --- a/process/transactionEvaluator/transactionEvaluator_test.go +++ b/process/transactionEvaluator/transactionEvaluator_test.go @@ -114,8 +114,8 @@ func TestComputeTransactionGasLimit_MoveBalance(t *testing.T) { args := createArgs() args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.MoveBalance + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.MoveBalance, false }, } args.FeeHandler = &economicsmocks.EconomicsHandlerStub{ @@ -153,8 +153,8 @@ func TestComputeTransactionGasLimit_MoveBalanceInvalidNonceShouldStillComputeCos args := createArgs() args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.MoveBalance, process.MoveBalance + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.MoveBalance, false }, } args.FeeHandler = &economicsmocks.EconomicsHandlerStub{ @@ -187,8 +187,8 @@ func TestComputeTransactionGasLimit_BuiltInFunction(t *testing.T) { consumedGasUnits := uint64(4000) args := createArgs() args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }, } args.FeeHandler = &economicsmocks.EconomicsHandlerStub{ @@ -223,8 +223,8 @@ func TestComputeTransactionGasLimit_BuiltInFunctionShouldErr(t *testing.T) { localErr := errors.New("local err") args := createArgs() args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }, } args.FeeHandler = &economicsmocks.EconomicsHandlerStub{ @@ -253,8 +253,8 @@ func TestComputeTransactionGasLimit_BuiltInFunctionShouldErr(t *testing.T) { func TestComputeTransactionGasLimit_NilVMOutput(t *testing.T) { args := createArgs() args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }, } args.FeeHandler = &economicsmocks.EconomicsHandlerStub{ @@ -284,8 +284,8 @@ func TestComputeTransactionGasLimit_NilVMOutput(t *testing.T) { func TestComputeTransactionGasLimit_RetCodeNotOk(t *testing.T) { args := createArgs() args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.BuiltInFunctionCall, process.BuiltInFunctionCall + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.BuiltInFunctionCall, process.BuiltInFunctionCall, false }, } args.FeeHandler = &economicsmocks.EconomicsHandlerStub{ @@ -321,8 +321,8 @@ func TestTransactionEvaluator_RelayedTxShouldErr(t *testing.T) { args := createArgs() args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.RelayedTx, process.RelayedTx + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.RelayedTx, process.RelayedTx, false }, } tce, _ := NewAPITransactionEvaluator(args) @@ -386,8 +386,8 @@ func TestApiTransactionEvaluator_ComputeTransactionGasLimit(t *testing.T) { _ = args.BlockChain.SetCurrentBlockHeaderAndRootHash(&block.Header{Nonce: expectedNonce}, []byte("test")) args.TxTypeHandler = &testscommon.TxTypeHandlerMock{ - ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { - return process.SCInvoking, process.SCInvoking + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.SCInvoking, process.SCInvoking, false }, } args.TxSimulator = &mock.TransactionSimulatorStub{ diff --git a/testscommon/scProcessorMock.go b/testscommon/scProcessorMock.go index 95e515b2950..ec96eb4c732 100644 --- a/testscommon/scProcessorMock.go +++ b/testscommon/scProcessorMock.go @@ -10,7 +10,7 @@ import ( // SCProcessorMock - type SCProcessorMock struct { - ComputeTransactionTypeCalled func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) + ComputeTransactionTypeCalled func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) ExecuteSmartContractTransactionCalled func(tx data.TransactionHandler, acntSrc, acntDst state.UserAccountHandler) (vmcommon.ReturnCode, error) ExecuteBuiltInFunctionCalled func(tx data.TransactionHandler, acntSrc, acntDst state.UserAccountHandler) (vmcommon.ReturnCode, error) DeploySmartContractCalled func(tx data.TransactionHandler, acntSrc state.UserAccountHandler) (vmcommon.ReturnCode, error) @@ -45,9 +45,9 @@ func (sc *SCProcessorMock) ProcessIfError( } // ComputeTransactionType - -func (sc *SCProcessorMock) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { +func (sc *SCProcessorMock) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { if sc.ComputeTransactionTypeCalled == nil { - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, false } return sc.ComputeTransactionTypeCalled(tx) diff --git a/testscommon/transactionCoordinatorMock.go b/testscommon/transactionCoordinatorMock.go index a1889b0b753..4aeac14dcff 100644 --- a/testscommon/transactionCoordinatorMock.go +++ b/testscommon/transactionCoordinatorMock.go @@ -12,7 +12,7 @@ import ( // TransactionCoordinatorMock - type TransactionCoordinatorMock struct { - ComputeTransactionTypeCalled func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) + ComputeTransactionTypeCalled func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) RequestMiniBlocksAndTransactionsCalled func(header data.HeaderHandler) RequestBlockTransactionsCalled func(body *block.Body) IsDataPreparedForProcessingCalled func(haveTime func() time.Duration) error @@ -57,9 +57,9 @@ func (tcm *TransactionCoordinatorMock) CreateReceiptsHash() ([]byte, error) { } // ComputeTransactionType - -func (tcm *TransactionCoordinatorMock) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { +func (tcm *TransactionCoordinatorMock) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { if tcm.ComputeTransactionTypeCalled == nil { - return 0, 0 + return 0, 0, false } return tcm.ComputeTransactionTypeCalled(tx) diff --git a/testscommon/txTypeHandlerMock.go b/testscommon/txTypeHandlerMock.go index 18a5a136477..bd08cc01c20 100644 --- a/testscommon/txTypeHandlerMock.go +++ b/testscommon/txTypeHandlerMock.go @@ -7,13 +7,13 @@ import ( // TxTypeHandlerMock - type TxTypeHandlerMock struct { - ComputeTransactionTypeCalled func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) + ComputeTransactionTypeCalled func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) } // ComputeTransactionType - -func (th *TxTypeHandlerMock) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { +func (th *TxTypeHandlerMock) ComputeTransactionType(tx data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { if th.ComputeTransactionTypeCalled == nil { - return process.MoveBalance, process.MoveBalance + return process.MoveBalance, process.MoveBalance, false } return th.ComputeTransactionTypeCalled(tx) From 980496da00aca10ce7bc2028bd3f87b625396426 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 2 Dec 2024 18:52:06 +0200 Subject: [PATCH 23/74] fix tests --- node/node_test.go | 2 +- process/transaction/shardProcess_test.go | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/node/node_test.go b/node/node_test.go index 48c1b115091..748749f5062 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -5307,7 +5307,7 @@ func getDefaultCoreComponents() *nodeMockFactory.CoreComponentsMock { StartTime: time.Time{}, EpochChangeNotifier: &epochNotifier.EpochNotifierStub{}, TxVersionCheckHandler: versioning.NewTxVersionChecker(0), - EnableEpochsHandlerField: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + EnableEpochsHandlerField: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.RelayedTransactionsV3Flag), } } diff --git a/process/transaction/shardProcess_test.go b/process/transaction/shardProcess_test.go index 905a6fc967b..75adbf3f3b9 100644 --- a/process/transaction/shardProcess_test.go +++ b/process/transaction/shardProcess_test.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "math/big" + "strings" "testing" "github.com/multiversx/mx-chain-core-go/core" @@ -2732,7 +2733,8 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { txCopy := *tx txCopy.Nonce = acntSrc.GetNonce() returnCode, err := txProcLocal.ProcessTransaction(&txCopy) - assert.Equal(t, process.ErrFailedTransaction, err) + assert.True(t, errors.Is(err, process.ErrTransactionNotExecutable)) + assert.True(t, strings.Contains(err.Error(), process.ErrRelayedTxV3Disabled.Error())) assert.Equal(t, vmcommon.UserError, returnCode) }) t.Run("relayer not in the same shard with the sender should error", func(t *testing.T) { @@ -2748,7 +2750,8 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { txCopy := *tx txCopy.Nonce = acntSrc.GetNonce() returnCode, err := txProcLocal.ProcessTransaction(&txCopy) - assert.Equal(t, process.ErrFailedTransaction, err) + assert.True(t, errors.Is(err, process.ErrTransactionNotExecutable)) + assert.True(t, strings.Contains(err.Error(), process.ErrShardIdMissmatch.Error())) assert.Equal(t, vmcommon.UserError, returnCode) }) t.Run("guarded relayer account should error", func(t *testing.T) { @@ -2781,7 +2784,8 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { txCopy := *tx txCopy.Nonce = acntSrc.GetNonce() returnCode, err := txProcLocal.ProcessTransaction(&txCopy) - assert.Equal(t, process.ErrFailedTransaction, err) + assert.True(t, errors.Is(err, process.ErrTransactionNotExecutable)) + assert.True(t, strings.Contains(err.Error(), process.ErrGuardedRelayerNotAllowed.Error())) assert.Equal(t, vmcommon.UserError, returnCode) }) t.Run("same guardian and relayer should error", func(t *testing.T) { @@ -2789,7 +2793,8 @@ func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { txCopy.Nonce = acntSrc.GetNonce() txCopy.GuardianAddr = txCopy.RelayerAddr returnCode, err := txProc.ProcessTransaction(&txCopy) - assert.Equal(t, process.ErrFailedTransaction, err) + assert.True(t, errors.Is(err, process.ErrTransactionNotExecutable)) + assert.True(t, strings.Contains(err.Error(), process.ErrRelayedByGuardianNotAllowed.Error())) assert.Equal(t, vmcommon.UserError, returnCode) }) t.Run("insufficient gas limit should error", func(t *testing.T) { From edc0ff3e0214bb9ad521c5f93e2a48eca06efe10 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 3 Dec 2024 20:15:53 +0200 Subject: [PATCH 24/74] fixes after review --- common/common.go | 14 +++- common/common_test.go | 31 ++++++++- .../transactionsFeeProcessor.go | 2 +- process/coordinator/transactionType.go | 2 +- process/dataValidators/txValidator.go | 2 +- process/economics/economicsData.go | 2 +- process/errors.go | 3 + .../smartContract/processorV2/processV2.go | 6 +- process/transaction/baseProcess.go | 68 ++++++++----------- process/transaction/interceptedTransaction.go | 6 +- .../interceptedTransaction_test.go | 7 ++ 11 files changed, 95 insertions(+), 48 deletions(-) diff --git a/common/common.go b/common/common.go index 136c449d87d..c1e565043ad 100644 --- a/common/common.go +++ b/common/common.go @@ -2,7 +2,7 @@ package common import "github.com/multiversx/mx-chain-core-go/data" -// IsValidRelayedTxV3 returns true if the provided transaction a valid transaction of type relayed v3 +// IsValidRelayedTxV3 returns true if the provided transaction is a valid transaction of type relayed v3 func IsValidRelayedTxV3(tx data.TransactionHandler) bool { relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler) if !isRelayedV3 { @@ -12,3 +12,15 @@ func IsValidRelayedTxV3(tx data.TransactionHandler) bool { hasValidRelayerSignature := len(relayedTx.GetRelayerSignature()) == len(relayedTx.GetSignature()) && len(relayedTx.GetRelayerSignature()) > 0 return hasValidRelayer && hasValidRelayerSignature } + +// IsRelayedTxV3 returns true if the provided transaction is a transaction of type relayed v3, without any further checks +func IsRelayedTxV3(tx data.TransactionHandler) bool { + relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler) + if !isRelayedV3 { + return false + } + + hasRelayer := len(relayedTx.GetRelayerAddr()) > 0 + hasRelayerSignature := len(relayedTx.GetRelayerSignature()) > 0 + return hasRelayer || hasRelayerSignature +} diff --git a/common/common_test.go b/common/common_test.go index 1786a9d9421..5a0ec53a21f 100644 --- a/common/common_test.go +++ b/common/common_test.go @@ -9,11 +9,12 @@ import ( "github.com/stretchr/testify/require" ) -func TestIsRelayedTxV3(t *testing.T) { +func TestIsValidRelayedTxV3(t *testing.T) { t.Parallel() scr := &smartContractResult.SmartContractResult{} require.False(t, IsValidRelayedTxV3(scr)) + require.False(t, IsRelayedTxV3(scr)) notRelayedTxV3 := &transaction.Transaction{ Nonce: 1, @@ -25,6 +26,33 @@ func TestIsRelayedTxV3(t *testing.T) { Signature: []byte("signature"), } require.False(t, IsValidRelayedTxV3(notRelayedTxV3)) + require.False(t, IsRelayedTxV3(notRelayedTxV3)) + + invalidRelayedTxV3 := &transaction.Transaction{ + Nonce: 1, + Value: big.NewInt(100), + RcvAddr: []byte("receiver"), + SndAddr: []byte("sender0"), + GasPrice: 100, + GasLimit: 10, + Signature: []byte("signature"), + RelayerAddr: []byte("relayer"), + } + require.False(t, IsValidRelayedTxV3(invalidRelayedTxV3)) + require.True(t, IsRelayedTxV3(invalidRelayedTxV3)) + + invalidRelayedTxV3 = &transaction.Transaction{ + Nonce: 1, + Value: big.NewInt(100), + RcvAddr: []byte("receiver"), + SndAddr: []byte("sender0"), + GasPrice: 100, + GasLimit: 10, + Signature: []byte("signature"), + RelayerSignature: []byte("signature"), + } + require.False(t, IsValidRelayedTxV3(invalidRelayedTxV3)) + require.True(t, IsRelayedTxV3(invalidRelayedTxV3)) relayedTxV3 := &transaction.Transaction{ Nonce: 1, @@ -38,4 +66,5 @@ func TestIsRelayedTxV3(t *testing.T) { RelayerSignature: []byte("signature"), } require.True(t, IsValidRelayedTxV3(relayedTxV3)) + require.True(t, IsRelayedTxV3(relayedTxV3)) } diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index bbe1979b1b6..1d184f28152 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -272,7 +272,7 @@ func (tep *transactionsFeeProcessor) setGasUsedAndFeeBasedOnRefundValue( epoch uint32, ) { isValidUserTxAfterBaseCostActivation := !check.IfNil(userTx) && tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) - if isValidUserTxAfterBaseCostActivation && !common.IsValidRelayedTxV3(txWithResults.GetTxHandler()) { + if isValidUserTxAfterBaseCostActivation && !common.IsRelayedTxV3(txWithResults.GetTxHandler()) { gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(userTx, refund) tx := txWithResults.GetTxHandler() diff --git a/process/coordinator/transactionType.go b/process/coordinator/transactionType.go index 871d670538c..45097d89c50 100644 --- a/process/coordinator/transactionType.go +++ b/process/coordinator/transactionType.go @@ -83,7 +83,7 @@ func (tth *txTypeHandler) ComputeTransactionType(tx data.TransactionHandler) (pr return process.InvalidTransaction, process.InvalidTransaction, false } - isRelayedV3 := common.IsValidRelayedTxV3(tx) + isRelayedV3 := common.IsRelayedTxV3(tx) isEmptyAddress := tth.isDestAddressEmpty(tx) if isEmptyAddress { diff --git a/process/dataValidators/txValidator.go b/process/dataValidators/txValidator.go index 414ce52c5b6..1e0c67ee007 100644 --- a/process/dataValidators/txValidator.go +++ b/process/dataValidators/txValidator.go @@ -109,7 +109,7 @@ func (txv *txValidator) getFeePayerAccount( payerAccount := accountHandler tx := interceptedTx.Transaction() - if common.IsValidRelayedTxV3(tx) { + if common.IsRelayedTxV3(tx) { relayedTx := tx.(data.RelayedTransactionHandler) payerAddress = relayedTx.GetRelayerAddr() relayerAccount, err := txv.accounts.GetExistingAccount(payerAddress) diff --git a/process/economics/economicsData.go b/process/economics/economicsData.go index 1e4ebe57454..dfce9d5a6f6 100644 --- a/process/economics/economicsData.go +++ b/process/economics/economicsData.go @@ -611,7 +611,7 @@ func (ed *economicsData) ComputeGasLimitBasedOnBalanceInEpoch(tx data.Transactio // getExtraGasLimitRelayedTx returns extra gas limit for relayed tx in a specific epoch func (ed *economicsData) getExtraGasLimitRelayedTx(txInstance *transaction.Transaction, epoch uint32) uint64 { - if common.IsValidRelayedTxV3(txInstance) { + if common.IsRelayedTxV3(txInstance) { return ed.MinGasLimitInEpoch(epoch) } diff --git a/process/errors.go b/process/errors.go index cd508052e61..feec446e096 100644 --- a/process/errors.go +++ b/process/errors.go @@ -1238,3 +1238,6 @@ var ErrGuardedRelayerNotAllowed = errors.New("guarded relayer not allowed") // ErrRelayedByGuardianNotAllowed signals that the provided guardian is also the relayer var ErrRelayedByGuardianNotAllowed = errors.New("relayed by guardian not allowed") + +// ErrInvalidRelayedTxV3 signals that an invalid relayed tx v3 has been provided +var ErrInvalidRelayedTxV3 = errors.New("invalid relayed transaction") diff --git a/process/smartContract/processorV2/processV2.go b/process/smartContract/processorV2/processV2.go index 0dd370cb665..7ac5d505c74 100644 --- a/process/smartContract/processorV2/processV2.go +++ b/process/smartContract/processorV2/processV2.go @@ -1685,7 +1685,7 @@ func getRelayedValues(tx data.TransactionHandler) ([]byte, *big.Int) { return relayedTx.RelayerAddr, big.NewInt(0) } - if common.IsValidRelayedTxV3(tx) { + if common.IsRelayedTxV3(tx) { relayedTx := tx.(data.RelayedTransactionHandler) return relayedTx.GetRelayerAddr(), big.NewInt(0) } @@ -1962,7 +1962,7 @@ func (sc *scProcessor) processSCPayment(tx data.TransactionHandler, acntSnd stat } func (sc *scProcessor) getFeePayer(tx data.TransactionHandler, acntSnd state.UserAccountHandler) (state.UserAccountHandler, error) { - if !common.IsValidRelayedTxV3(tx) { + if !common.IsRelayedTxV3(tx) { return acntSnd, nil } @@ -2654,7 +2654,7 @@ func (sc *scProcessor) createRefundGasToRelayerSCRIfNeeded( gasRefund) } - isRelayedV3 := common.IsValidRelayedTxV3(tx) + isRelayedV3 := common.IsRelayedTxV3(tx) shouldRefundGasToRelayerSCR = isRelayedV3 && callType != vmData.AsynchronousCall && gasRefund.Cmp(zero) > 0 if shouldRefundGasToRelayerSCR { relayedTx := tx.(data.RelayedTransactionHandler) diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 5f745875547..1cb90d3bd2a 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -119,7 +119,11 @@ func (txProc *baseTxProcessor) checkTxValues( acntSnd, acntDst state.UserAccountHandler, isUserTxOfRelayed bool, ) error { - if common.IsValidRelayedTxV3(tx) { + if check.IfNil(acntSnd) { + return nil + } + + if common.IsRelayedTxV3(tx) { relayerAccount, err := txProc.getAccountFromAddress(tx.RelayerAddr) if err != nil { return err @@ -128,24 +132,7 @@ func (txProc *baseTxProcessor) checkTxValues( return txProc.checkUserTxOfRelayedV3Values(tx, acntSnd, acntDst, relayerAccount) } - err := txProc.verifyGuardian(tx, acntSnd) - if err != nil { - return err - } - err = txProc.checkUserNames(tx, acntSnd, acntDst) - if err != nil { - return err - } - if check.IfNil(acntSnd) { - return nil - } - if acntSnd.GetNonce() < tx.Nonce { - return process.ErrHigherNonceInTransaction - } - if acntSnd.GetNonce() > tx.Nonce { - return process.ErrLowerNonceInTransaction - } - err = txProc.economicsFee.CheckValidityTxValues(tx) + err := txProc.checkTxCommon(tx, acntSnd, acntDst) if err != nil { return err } @@ -189,24 +176,7 @@ func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( destinationAccount state.UserAccountHandler, relayerAccount state.UserAccountHandler, ) error { - err := txProc.verifyGuardian(tx, senderAccount) - if err != nil { - return err - } - err = txProc.checkUserNames(tx, senderAccount, destinationAccount) - if err != nil { - return err - } - if check.IfNil(senderAccount) { - return nil - } - if senderAccount.GetNonce() < tx.Nonce { - return process.ErrHigherNonceInTransaction - } - if senderAccount.GetNonce() > tx.Nonce { - return process.ErrLowerNonceInTransaction - } - err = txProc.economicsFee.CheckValidityTxValues(tx) + err := txProc.checkTxCommon(tx, senderAccount, destinationAccount) if err != nil { return err } @@ -236,11 +206,33 @@ func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( return nil } +func (txProc *baseTxProcessor) checkTxCommon( + tx *transaction.Transaction, + senderAccount state.UserAccountHandler, + destinationAccount state.UserAccountHandler, +) error { + err := txProc.verifyGuardian(tx, senderAccount) + if err != nil { + return err + } + err = txProc.checkUserNames(tx, senderAccount, destinationAccount) + if err != nil { + return err + } + if senderAccount.GetNonce() < tx.Nonce { + return process.ErrHigherNonceInTransaction + } + if senderAccount.GetNonce() > tx.Nonce { + return process.ErrLowerNonceInTransaction + } + return txProc.economicsFee.CheckValidityTxValues(tx) +} + func (txProc *baseTxProcessor) getFeePayer( tx *transaction.Transaction, acntSnd state.UserAccountHandler, ) (state.UserAccountHandler, bool, error) { - if !common.IsValidRelayedTxV3(tx) { + if !common.IsRelayedTxV3(tx) { return acntSnd, false, nil } diff --git a/process/transaction/interceptedTransaction.go b/process/transaction/interceptedTransaction.go index 533a0bf95c9..53722cad96f 100644 --- a/process/transaction/interceptedTransaction.go +++ b/process/transaction/interceptedTransaction.go @@ -240,7 +240,7 @@ func isRelayedTx(funcName string) bool { } func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transaction) error { - if !common.IsValidRelayedTxV3(tx) { + if !common.IsRelayedTxV3(tx) { return nil } @@ -248,6 +248,10 @@ func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transact return process.ErrRelayedTxV3Disabled } + if !common.IsValidRelayedTxV3(tx) { + return process.ErrInvalidRelayedTxV3 + } + err := inTx.integrity(tx) if err != nil { return err diff --git a/process/transaction/interceptedTransaction_test.go b/process/transaction/interceptedTransaction_test.go index 9e63b66d2e9..7459e586241 100644 --- a/process/transaction/interceptedTransaction_test.go +++ b/process/transaction/interceptedTransaction_test.go @@ -1585,7 +1585,14 @@ func TestInterceptedTransaction_CheckValidityOfRelayedTxV3(t *testing.T) { err = txi.CheckValidity() assert.Equal(t, process.ErrRelayedTxV3Disabled, err) + // invalid relayed v3 should error + tx.RelayerSignature = nil + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + err = txi.CheckValidity() + assert.Equal(t, process.ErrInvalidRelayedTxV3, err) + // sender in different shard than relayer should fail + tx.RelayerSignature = sigOk tx.RelayerAddr = bytes.Repeat([]byte("a"), len(relayerAddress)) txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) err = txi.CheckValidity() From 33568e5874f7963035d57b3f8309e32b14c8fc14 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 3 Dec 2024 20:53:57 +0200 Subject: [PATCH 25/74] reverted common code in order to keep old logic on errors --- process/transaction/baseProcess.go | 63 +++++++++++++++++------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 1cb90d3bd2a..c86c60339ff 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -119,9 +119,6 @@ func (txProc *baseTxProcessor) checkTxValues( acntSnd, acntDst state.UserAccountHandler, isUserTxOfRelayed bool, ) error { - if check.IfNil(acntSnd) { - return nil - } if common.IsRelayedTxV3(tx) { relayerAccount, err := txProc.getAccountFromAddress(tx.RelayerAddr) @@ -132,7 +129,24 @@ func (txProc *baseTxProcessor) checkTxValues( return txProc.checkUserTxOfRelayedV3Values(tx, acntSnd, acntDst, relayerAccount) } - err := txProc.checkTxCommon(tx, acntSnd, acntDst) + err := txProc.verifyGuardian(tx, acntSnd) + if err != nil { + return err + } + err = txProc.checkUserNames(tx, acntSnd, acntDst) + if err != nil { + return err + } + if check.IfNil(acntSnd) { + return nil + } + if acntSnd.GetNonce() < tx.Nonce { + return process.ErrHigherNonceInTransaction + } + if acntSnd.GetNonce() > tx.Nonce { + return process.ErrLowerNonceInTransaction + } + err = txProc.economicsFee.CheckValidityTxValues(tx) if err != nil { return err } @@ -176,7 +190,24 @@ func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( destinationAccount state.UserAccountHandler, relayerAccount state.UserAccountHandler, ) error { - err := txProc.checkTxCommon(tx, senderAccount, destinationAccount) + err := txProc.verifyGuardian(tx, senderAccount) + if err != nil { + return err + } + err = txProc.checkUserNames(tx, senderAccount, destinationAccount) + if err != nil { + return err + } + if check.IfNil(senderAccount) { + return nil + } + if senderAccount.GetNonce() < tx.Nonce { + return process.ErrHigherNonceInTransaction + } + if senderAccount.GetNonce() > tx.Nonce { + return process.ErrLowerNonceInTransaction + } + err = txProc.economicsFee.CheckValidityTxValues(tx) if err != nil { return err } @@ -206,28 +237,6 @@ func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( return nil } -func (txProc *baseTxProcessor) checkTxCommon( - tx *transaction.Transaction, - senderAccount state.UserAccountHandler, - destinationAccount state.UserAccountHandler, -) error { - err := txProc.verifyGuardian(tx, senderAccount) - if err != nil { - return err - } - err = txProc.checkUserNames(tx, senderAccount, destinationAccount) - if err != nil { - return err - } - if senderAccount.GetNonce() < tx.Nonce { - return process.ErrHigherNonceInTransaction - } - if senderAccount.GetNonce() > tx.Nonce { - return process.ErrLowerNonceInTransaction - } - return txProc.economicsFee.CheckValidityTxValues(tx) -} - func (txProc *baseTxProcessor) getFeePayer( tx *transaction.Transaction, acntSnd state.UserAccountHandler, From 0ac7c165c38fb73711e5c771cdadff5deb4a93f3 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Wed, 4 Dec 2024 12:07:27 +0200 Subject: [PATCH 26/74] use proper prevTxHash in case of relayed v1 and v2 --- process/smartContract/processorV2/processV2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/smartContract/processorV2/processV2.go b/process/smartContract/processorV2/processV2.go index 7ac5d505c74..31513ecea3b 100644 --- a/process/smartContract/processorV2/processV2.go +++ b/process/smartContract/processorV2/processV2.go @@ -2649,8 +2649,8 @@ func (sc *scProcessor) createRefundGasToRelayerSCRIfNeeded( relayedSCR.Nonce+1, relayedSCR.RelayerAddr, relayedSCR.OriginalSender, - relayedSCR.OriginalTxHash, txHash, + relayedSCR.OriginalTxHash, gasRefund) } From d744ac4e4f139f7c588777cf796ce5c263092ab7 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 5 Dec 2024 11:56:04 +0200 Subject: [PATCH 27/74] fix transaction/pool endpoint issues --- .../transactionAPI/apiTransactionProcessor.go | 4 ++-- .../apiTransactionProcessor_test.go | 15 ++++++++++++++- node/external/transactionAPI/fieldsHandler.go | 5 ++++- .../external/transactionAPI/fieldsHandler_test.go | 2 ++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/node/external/transactionAPI/apiTransactionProcessor.go b/node/external/transactionAPI/apiTransactionProcessor.go index c67ad1cb445..2bd448829d1 100644 --- a/node/external/transactionAPI/apiTransactionProcessor.go +++ b/node/external/transactionAPI/apiTransactionProcessor.go @@ -394,8 +394,8 @@ func (atp *apiTransactionProcessor) getFieldGettersForTx(wrappedTx *txcache.Wrap rcvUsernameField: wrappedTx.Tx.GetRcvUserName(), dataField: wrappedTx.Tx.GetData(), valueField: getTxValue(wrappedTx), - senderShardID: wrappedTx.SenderShardID, - receiverShardID: wrappedTx.ReceiverShardID, + senderShardID: atp.shardCoordinator.ComputeId(wrappedTx.Tx.GetSndAddr()), + receiverShardID: atp.shardCoordinator.ComputeId(wrappedTx.Tx.GetRcvAddr()), } guardedTx, isGuardedTx := wrappedTx.Tx.(data.GuardedTransactionHandler) diff --git a/node/external/transactionAPI/apiTransactionProcessor_test.go b/node/external/transactionAPI/apiTransactionProcessor_test.go index e6a7040fe87..0282a6895ac 100644 --- a/node/external/transactionAPI/apiTransactionProcessor_test.go +++ b/node/external/transactionAPI/apiTransactionProcessor_test.go @@ -933,6 +933,9 @@ func TestApiTransactionProcessor_GetTransactionsPoolForSender(t *testing.T) { NumberOfShardsCalled: func() uint32 { return 1 }, + ComputeIdCalled: func(address []byte) uint32 { + return 1 // force to return different from 0 + }, } atp, err := NewAPITransactionProcessor(args) require.NoError(t, err) @@ -945,7 +948,17 @@ func TestApiTransactionProcessor_GetTransactionsPoolForSender(t *testing.T) { for i, tx := range res.Transactions { require.Equal(t, expectedHashes[i], tx.TxFields[hashField]) require.Equal(t, expectedValues[i], tx.TxFields[valueField]) - require.Equal(t, sender, tx.TxFields["sender"]) + require.Equal(t, sender, tx.TxFields[senderField]) + require.Equal(t, uint32(1), tx.TxFields[senderShardID]) + require.Equal(t, uint32(1), tx.TxFields[senderShardID]) + } + + res, err = atp.GetTransactionsPoolForSender(sender, "sender,value") // no hash, should be by default + require.NoError(t, err) + for i, tx := range res.Transactions { + require.Equal(t, expectedHashes[i], tx.TxFields[hashField]) + require.Equal(t, expectedValues[i], tx.TxFields[valueField]) + require.Equal(t, sender, tx.TxFields[senderField]) } // if no tx is found in pool for a sender, it isn't an error, but return empty slice diff --git a/node/external/transactionAPI/fieldsHandler.go b/node/external/transactionAPI/fieldsHandler.go index 4f837968cb7..4102d9ffc61 100644 --- a/node/external/transactionAPI/fieldsHandler.go +++ b/node/external/transactionAPI/fieldsHandler.go @@ -38,8 +38,11 @@ func newFieldsHandler(parameters string) fieldsHandler { } parameters = strings.ToLower(parameters) + fieldsMap := sliceToMap(strings.Split(parameters, separator)) + fieldsMap[hashField] = struct{}{} // hashField should always be returned + return fieldsHandler{ - fieldsMap: sliceToMap(strings.Split(parameters, separator)), + fieldsMap: fieldsMap, } } diff --git a/node/external/transactionAPI/fieldsHandler_test.go b/node/external/transactionAPI/fieldsHandler_test.go index fab3b3a41d9..0be9d0124b3 100644 --- a/node/external/transactionAPI/fieldsHandler_test.go +++ b/node/external/transactionAPI/fieldsHandler_test.go @@ -20,9 +20,11 @@ func Test_newFieldsHandler(t *testing.T) { for _, field := range splitFields { require.True(t, fh.IsFieldSet(field), fmt.Sprintf("field %s is not set", field)) } + require.True(t, fh.IsFieldSet(hashField), fmt.Sprintf("hashField should have been returned by default")) fh = newFieldsHandler("*") for _, field := range splitFields { require.True(t, fh.IsFieldSet(field)) } + require.True(t, fh.IsFieldSet(hashField), fmt.Sprintf("hashField should have been returned by default")) } From 9ac1370cac952b953b920d5da4b71d7009bd9636 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 5 Dec 2024 12:07:30 +0200 Subject: [PATCH 28/74] fix linter --- node/external/transactionAPI/fieldsHandler_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/external/transactionAPI/fieldsHandler_test.go b/node/external/transactionAPI/fieldsHandler_test.go index 0be9d0124b3..75b3ae6f81a 100644 --- a/node/external/transactionAPI/fieldsHandler_test.go +++ b/node/external/transactionAPI/fieldsHandler_test.go @@ -20,11 +20,11 @@ func Test_newFieldsHandler(t *testing.T) { for _, field := range splitFields { require.True(t, fh.IsFieldSet(field), fmt.Sprintf("field %s is not set", field)) } - require.True(t, fh.IsFieldSet(hashField), fmt.Sprintf("hashField should have been returned by default")) + require.True(t, fh.IsFieldSet(hashField), "hashField should have been returned by default") fh = newFieldsHandler("*") for _, field := range splitFields { require.True(t, fh.IsFieldSet(field)) } - require.True(t, fh.IsFieldSet(hashField), fmt.Sprintf("hashField should have been returned by default")) + require.True(t, fh.IsFieldSet(hashField), "hashField should have been returned by default") } From 05204b425bc7414e70820c2738dc218abe4f83ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 5 Dec 2024 12:55:30 +0200 Subject: [PATCH 29/74] Export selection session. --- process/block/preprocess/selectionSession.go | 18 +++++----- .../block/preprocess/selectionSession_test.go | 36 +++++++++---------- process/block/preprocess/transactions.go | 6 ++-- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/process/block/preprocess/selectionSession.go b/process/block/preprocess/selectionSession.go index c5c16a56cde..7e3b35687a1 100644 --- a/process/block/preprocess/selectionSession.go +++ b/process/block/preprocess/selectionSession.go @@ -21,22 +21,24 @@ type selectionSession struct { ephemeralAccountsCache map[string]vmcommon.AccountHandler } -type argsSelectionSession struct { - accountsAdapter state.AccountsAdapter - transactionsProcessor process.TransactionProcessor +// ArgsSelectionSession holds the arguments for creating a new selection session. +type ArgsSelectionSession struct { + AccountsAdapter state.AccountsAdapter + TransactionsProcessor process.TransactionProcessor } -func newSelectionSession(args argsSelectionSession) (*selectionSession, error) { - if check.IfNil(args.accountsAdapter) { +// NewSelectionSession creates a new selection session. +func NewSelectionSession(args ArgsSelectionSession) (*selectionSession, error) { + if check.IfNil(args.AccountsAdapter) { return nil, process.ErrNilAccountsAdapter } - if check.IfNil(args.transactionsProcessor) { + if check.IfNil(args.TransactionsProcessor) { return nil, process.ErrNilTxProcessor } return &selectionSession{ - accountsAdapter: args.accountsAdapter, - transactionsProcessor: args.transactionsProcessor, + accountsAdapter: args.AccountsAdapter, + transactionsProcessor: args.TransactionsProcessor, ephemeralAccountsCache: make(map[string]vmcommon.AccountHandler), }, nil } diff --git a/process/block/preprocess/selectionSession_test.go b/process/block/preprocess/selectionSession_test.go index fc46d5ced15..939da698cd1 100644 --- a/process/block/preprocess/selectionSession_test.go +++ b/process/block/preprocess/selectionSession_test.go @@ -17,23 +17,23 @@ import ( func TestNewSelectionSession(t *testing.T) { t.Parallel() - session, err := newSelectionSession(argsSelectionSession{ - accountsAdapter: nil, - transactionsProcessor: &testscommon.TxProcessorStub{}, + session, err := NewSelectionSession(ArgsSelectionSession{ + AccountsAdapter: nil, + TransactionsProcessor: &testscommon.TxProcessorStub{}, }) require.Nil(t, session) require.ErrorIs(t, err, process.ErrNilAccountsAdapter) - session, err = newSelectionSession(argsSelectionSession{ - accountsAdapter: &stateMock.AccountsStub{}, - transactionsProcessor: nil, + session, err = NewSelectionSession(ArgsSelectionSession{ + AccountsAdapter: &stateMock.AccountsStub{}, + TransactionsProcessor: nil, }) require.Nil(t, session) require.ErrorIs(t, err, process.ErrNilTxProcessor) - session, err = newSelectionSession(argsSelectionSession{ - accountsAdapter: &stateMock.AccountsStub{}, - transactionsProcessor: &testscommon.TxProcessorStub{}, + session, err = NewSelectionSession(ArgsSelectionSession{ + AccountsAdapter: &stateMock.AccountsStub{}, + TransactionsProcessor: &testscommon.TxProcessorStub{}, }) require.NoError(t, err) require.NotNil(t, session) @@ -66,9 +66,9 @@ func TestSelectionSession_GetAccountState(t *testing.T) { return nil, fmt.Errorf("account not found: %s", address) } - session, err := newSelectionSession(argsSelectionSession{ - accountsAdapter: accounts, - transactionsProcessor: processor, + session, err := NewSelectionSession(ArgsSelectionSession{ + AccountsAdapter: accounts, + TransactionsProcessor: processor, }) require.NoError(t, err) require.NotNil(t, session) @@ -111,9 +111,9 @@ func TestSelectionSession_IsIncorrectlyGuarded(t *testing.T) { return nil } - session, err := newSelectionSession(argsSelectionSession{ - accountsAdapter: accounts, - transactionsProcessor: processor, + session, err := NewSelectionSession(ArgsSelectionSession{ + AccountsAdapter: accounts, + TransactionsProcessor: processor, }) require.NoError(t, err) require.NotNil(t, session) @@ -144,9 +144,9 @@ func TestSelectionSession_ephemeralAccountsCache_IsSharedAmongCalls(t *testing.T return &stateMock.UserAccountStub{}, nil } - session, err := newSelectionSession(argsSelectionSession{ - accountsAdapter: accounts, - transactionsProcessor: processor, + session, err := NewSelectionSession(ArgsSelectionSession{ + AccountsAdapter: accounts, + TransactionsProcessor: processor, }) require.NoError(t, err) require.NotNil(t, session) diff --git a/process/block/preprocess/transactions.go b/process/block/preprocess/transactions.go index 8578a97e92d..2f3fc290ef6 100644 --- a/process/block/preprocess/transactions.go +++ b/process/block/preprocess/transactions.go @@ -1411,9 +1411,9 @@ func (txs *transactions) computeSortedTxs( sortedTransactionsProvider := createSortedTransactionsProvider(txShardPool) log.Debug("computeSortedTxs.GetSortedTransactions") - session, err := newSelectionSession(argsSelectionSession{ - accountsAdapter: txs.accounts, - transactionsProcessor: txs.txProcessor, + session, err := NewSelectionSession(ArgsSelectionSession{ + AccountsAdapter: txs.accounts, + TransactionsProcessor: txs.txProcessor, }) if err != nil { return nil, nil, err From 886df303b57921ddf802560d947d7b528f8b247d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 5 Dec 2024 15:09:53 +0200 Subject: [PATCH 30/74] Sketch test utils. --- .../chainSimulator/mempool/testutils_test.go | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 integrationTests/chainSimulator/mempool/testutils_test.go diff --git a/integrationTests/chainSimulator/mempool/testutils_test.go b/integrationTests/chainSimulator/mempool/testutils_test.go new file mode 100644 index 00000000000..34eed359e86 --- /dev/null +++ b/integrationTests/chainSimulator/mempool/testutils_test.go @@ -0,0 +1,171 @@ +package mempool + +import ( + "math/big" + "strconv" + "testing" + "time" + + "github.com/multiversx/mx-chain-core-go/core" + "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-go/config" + testsChainSimulator "github.com/multiversx/mx-chain-go/integrationTests/chainSimulator" + "github.com/multiversx/mx-chain-go/node/chainSimulator" + "github.com/multiversx/mx-chain-go/node/chainSimulator/components/api" + "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" + "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/process/block/preprocess" + "github.com/multiversx/mx-chain-go/storage/txcache" + "github.com/multiversx/mx-chain-go/testscommon" + "github.com/stretchr/testify/require" +) + +var ( + oneEGLD = big.NewInt(1000000000000000000) + oneQuarterOfEGLD = big.NewInt(250000000000000000) + oneCentOfEGLD = big.NewInt(10000000000000000) + durationWaitAfterSend = 500 * time.Millisecond +) + +func startChainSimulator(t *testing.T, alterConfigsFunction func(cfg *config.Configs)) testsChainSimulator.ChainSimulator { + simulator, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: "../../../cmd/node/config/", + NumOfShards: 1, + GenesisTimestamp: time.Now().Unix(), + RoundDurationInMillis: uint64(4000), + RoundsPerEpoch: core.OptionalUint64{ + HasValue: true, + Value: 10, + }, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 1, + MetaChainMinNodes: 1, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: alterConfigsFunction, + }) + require.NoError(t, err) + require.NotNil(t, simulator) + + err = simulator.GenerateBlocksUntilEpochIsReached(1) + require.NoError(t, err) + + return simulator +} + +type participantsHolder struct { + sendersByShard map[int][]dtos.WalletAddress + receiverByShard map[int]dtos.WalletAddress +} + +func newParticipantsHolder() *participantsHolder { + return &participantsHolder{ + sendersByShard: make(map[int][]dtos.WalletAddress), + receiverByShard: make(map[int]dtos.WalletAddress), + } +} + +func createParticipants(t *testing.T, simulator testsChainSimulator.ChainSimulator, numSendersPerShard int) *participantsHolder { + numShards := int(simulator.GetNodeHandler(0).GetShardCoordinator().NumberOfShards()) + participants := newParticipantsHolder() + + for shard := 0; shard < numShards; shard++ { + senders := make([]dtos.WalletAddress, 0, numSendersPerShard) + + for i := 0; i < numSendersPerShard; i++ { + sender, err := simulator.GenerateAndMintWalletAddress(uint32(shard), oneEGLD) + require.NoError(t, err) + + senders = append(senders, sender) + } + + receiver, err := simulator.GenerateAndMintWalletAddress(0, big.NewInt(0)) + require.NoError(t, err) + + participants.sendersByShard[shard] = senders + participants.receiverByShard[shard] = receiver + } + + err := simulator.GenerateBlocks(1) + require.Nil(t, err) + + return participants +} + +type noncesTracker struct { + nonceByAddress map[string]uint64 +} + +func newNoncesTracker() *noncesTracker { + return &noncesTracker{ + nonceByAddress: make(map[string]uint64), + } +} + +func (tracker *noncesTracker) getThenIncrementNonce(address dtos.WalletAddress) uint64 { + nonce, ok := tracker.nonceByAddress[address.Bech32] + if !ok { + tracker.nonceByAddress[address.Bech32] = 0 + } + + tracker.nonceByAddress[address.Bech32]++ + return nonce +} + +func sendTransactions(t *testing.T, simulator testsChainSimulator.ChainSimulator, transactions []*transaction.Transaction) { + transactionsBySenderShard := make(map[int][]*transaction.Transaction) + shardCoordinator := simulator.GetNodeHandler(0).GetShardCoordinator() + + for _, tx := range transactions { + shard := int(shardCoordinator.ComputeId(tx.SndAddr)) + transactionsBySenderShard[shard] = append(transactionsBySenderShard[shard], tx) + } + + for shard, transactionsFromShard := range transactionsBySenderShard { + node := simulator.GetNodeHandler(uint32(shard)) + numSent, err := node.GetFacadeHandler().SendBulkTransactions(transactionsFromShard) + + require.NoError(t, err) + require.Equal(t, len(transactionsFromShard), int(numSent)) + } + + time.Sleep(durationWaitAfterSend) +} + +func selectTransactions(t *testing.T, simulator testsChainSimulator.ChainSimulator, shard int) ([]*txcache.WrappedTransaction, uint64) { + shardAsString := strconv.Itoa(shard) + node := simulator.GetNodeHandler(uint32(shard)) + accountsAdapter := node.GetStateComponents().AccountsAdapter() + poolsHolder := node.GetDataComponents().Datapool().Transactions() + + selectionSession, err := preprocess.NewSelectionSession(preprocess.ArgsSelectionSession{ + AccountsAdapter: accountsAdapter, + TransactionsProcessor: &testscommon.TxProcessorStub{}, + }) + require.NoError(t, err) + + mempool := poolsHolder.ShardDataStore(shardAsString).(*txcache.TxCache) + + selectedTransactions, gas := mempool.SelectTransactions( + selectionSession, + process.TxCacheSelectionGasRequested, + process.TxCacheSelectionMaxNumTxs, + process.TxCacheSelectionLoopMaximumDuration, + ) + + return selectedTransactions, gas +} + +func getNumTransactionsInPool(simulator testsChainSimulator.ChainSimulator, shard int) int { + node := simulator.GetNodeHandler(uint32(shard)) + poolsHolder := node.GetDataComponents().Datapool().Transactions() + return int(poolsHolder.GetCounts().GetTotal()) +} + +func getNumTransactionsInCurrentBlock(simulator testsChainSimulator.ChainSimulator, shard int) int { + node := simulator.GetNodeHandler(uint32(shard)) + currentBlock := node.GetDataComponents().Blockchain().GetCurrentBlockHeader() + return int(currentBlock.GetTxCount()) +} From 6ee6f362da894ff7050585faef45e60ce6e44210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 5 Dec 2024 15:10:53 +0200 Subject: [PATCH 31/74] Sketch some tests. --- .../chainSimulator/mempool/mempool_test.go | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 integrationTests/chainSimulator/mempool/mempool_test.go diff --git a/integrationTests/chainSimulator/mempool/mempool_test.go b/integrationTests/chainSimulator/mempool/mempool_test.go new file mode 100644 index 00000000000..92df7629c3c --- /dev/null +++ b/integrationTests/chainSimulator/mempool/mempool_test.go @@ -0,0 +1,165 @@ +package mempool + +import ( + "math/big" + "testing" + "time" + + "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-go/config" + "github.com/multiversx/mx-chain-go/node/chainSimulator/configs" + "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" + "github.com/multiversx/mx-chain-go/storage" + "github.com/stretchr/testify/require" +) + +func TestMempoolWithChainSimulator_Selection(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + numSenders := 100 + numTransactionsPerSender := 3 + shard := 0 + + simulator := startChainSimulator(t, func(cfg *config.Configs) {}) + defer simulator.Close() + + participants := createParticipants(t, simulator, numSenders) + noncesTracker := newNoncesTracker() + + transactions := make([]*transaction.Transaction, 0, numSenders*numTransactionsPerSender) + + for i := 0; i < numSenders; i++ { + sender := participants.sendersByShard[shard][i] + receiver := participants.receiverByShard[shard] + + for j := 0; j < numTransactionsPerSender; j++ { + tx := &transaction.Transaction{ + Nonce: noncesTracker.getThenIncrementNonce(sender), + Value: oneQuarterOfEGLD, + SndAddr: sender.Bytes, + RcvAddr: receiver.Bytes, + Data: []byte{}, + GasLimit: 50_000, + GasPrice: 1_000_000_000, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + } + + transactions = append(transactions, tx) + } + } + + sendTransactions(t, simulator, transactions) + require.Equal(t, 300, getNumTransactionsInPool(simulator, shard)) + + selectedTransactions, gas := selectTransactions(t, simulator, shard) + require.Equal(t, 300, len(selectedTransactions)) + require.Equal(t, 50_000*300, int(gas)) + + err := simulator.GenerateBlocks(1) + require.Nil(t, err) + require.Equal(t, 300, getNumTransactionsInCurrentBlock(simulator, shard)) +} + +func TestMempoolWithChainSimulator_Eviction(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + simulator := startChainSimulator(t, func(cfg *config.Configs) {}) + node := simulator.GetNodeHandler(0) + mempool := node.GetDataComponents().Datapool().Transactions() + + defer simulator.Close() + + numSenders := 10000 + numTransactionsPerSender := 30 + + senders := make([]dtos.WalletAddress, numSenders) + sendersNonces := make([]uint64, numSenders) + + for i := 0; i < numSenders; i++ { + sender, err := simulator.GenerateAndMintWalletAddress(0, oneEGLD) + require.NoError(t, err) + + senders[i] = sender + } + + receiver, err := simulator.GenerateAndMintWalletAddress(0, big.NewInt(0)) + require.NoError(t, err) + + err = simulator.GenerateBlocks(1) + require.Nil(t, err) + + transactions := make([]*transaction.Transaction, 0, numSenders*numTransactionsPerSender) + + for i := 0; i < numSenders; i++ { + for j := 0; j < numTransactionsPerSender; j++ { + tx := &transaction.Transaction{ + Nonce: sendersNonces[i], + Value: oneEGLD, + SndAddr: senders[i].Bytes, + RcvAddr: receiver.Bytes, + Data: []byte{}, + GasLimit: 50000, + GasPrice: 1_000_000_000, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + } + + sendersNonces[i]++ + transactions = append(transactions, tx) + } + } + + numSent, err := node.GetFacadeHandler().SendBulkTransactions(transactions) + require.NoError(t, err) + require.Equal(t, 300000, int(numSent)) + + time.Sleep(1 * time.Second) + require.Equal(t, 300000, int(mempool.GetCounts().GetTotal())) + + // Send one more transaction (fill up the mempool) + _, err = node.GetFacadeHandler().SendBulkTransactions([]*transaction.Transaction{ + { + Nonce: 42, + Value: oneEGLD, + SndAddr: senders[7].Bytes, + RcvAddr: receiver.Bytes, + Data: []byte{}, + GasLimit: 50000, + GasPrice: 1_000_000_000, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + }, + }) + require.NoError(t, err) + + time.Sleep(42 * time.Millisecond) + require.Equal(t, 300001, int(mempool.GetCounts().GetTotal())) + + // Send one more transaction to trigger eviction + _, err = node.GetFacadeHandler().SendBulkTransactions([]*transaction.Transaction{ + { + Nonce: 42, + Value: oneEGLD, + SndAddr: senders[7].Bytes, + RcvAddr: receiver.Bytes, + Data: []byte{}, + GasLimit: 50000, + GasPrice: 1_000_000_000, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + }, + }) + require.NoError(t, err) + + time.Sleep(1 * time.Second) + require.Equal(t, 300000+1+1-int(storage.TxPoolSourceMeNumItemsToPreemptivelyEvict), int(mempool.GetCounts().GetTotal())) +} From 5d301c783f2f4051db01650c3faf6aaa7ac6ca58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 6 Dec 2024 22:38:27 +0200 Subject: [PATCH 32/74] Test adjustments (work in progress). --- .../chainSimulator/mempool/mempool_test.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/integrationTests/chainSimulator/mempool/mempool_test.go b/integrationTests/chainSimulator/mempool/mempool_test.go index 92df7629c3c..473a8f9bc35 100644 --- a/integrationTests/chainSimulator/mempool/mempool_test.go +++ b/integrationTests/chainSimulator/mempool/mempool_test.go @@ -10,15 +10,18 @@ import ( "github.com/multiversx/mx-chain-go/node/chainSimulator/configs" "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" "github.com/multiversx/mx-chain-go/storage" + logger "github.com/multiversx/mx-chain-logger-go" "github.com/stretchr/testify/require" ) func TestMempoolWithChainSimulator_Selection(t *testing.T) { + logger.SetLogLevel("*:INFO,txcache:DEBUG") + if testing.Short() { t.Skip("this is not a short test") } - numSenders := 100 + numSenders := 10000 numTransactionsPerSender := 3 shard := 0 @@ -53,15 +56,19 @@ func TestMempoolWithChainSimulator_Selection(t *testing.T) { } sendTransactions(t, simulator, transactions) - require.Equal(t, 300, getNumTransactionsInPool(simulator, shard)) + require.Equal(t, 30_000, getNumTransactionsInPool(simulator, shard)) selectedTransactions, gas := selectTransactions(t, simulator, shard) - require.Equal(t, 300, len(selectedTransactions)) - require.Equal(t, 50_000*300, int(gas)) + require.Equal(t, 30_000, len(selectedTransactions)) + require.Equal(t, 50_000*30_000, int(gas)) err := simulator.GenerateBlocks(1) require.Nil(t, err) - require.Equal(t, 300, getNumTransactionsInCurrentBlock(simulator, shard)) + require.Equal(t, 27_756, getNumTransactionsInCurrentBlock(simulator, shard)) + + selectedTransactions, gas = selectTransactions(t, simulator, shard) + require.Equal(t, 30_000, len(selectedTransactions)) + require.Equal(t, 50_000*30_000, int(gas)) } func TestMempoolWithChainSimulator_Eviction(t *testing.T) { From 353692799711feec685bc34be07de751ccc992b7 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Tue, 10 Dec 2024 16:28:31 +0200 Subject: [PATCH 33/74] remove old persisters when new already existing --- storage/pruning/pruningStorer.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/storage/pruning/pruningStorer.go b/storage/pruning/pruningStorer.go index 2007454a7c8..aab0b744e54 100644 --- a/storage/pruning/pruningStorer.go +++ b/storage/pruning/pruningStorer.go @@ -779,7 +779,7 @@ func (ps *PruningStorer) changeEpoch(header data.HeaderHandler) error { } log.Debug("change epoch pruning storer success", "persister", ps.identifier, "epoch", epoch) - return nil + return ps.removeOldPersistersIfNeeded(header, epoch) } shardID := core.GetShardIDString(ps.shardCoordinator.SelfId()) @@ -802,6 +802,10 @@ func (ps *PruningStorer) changeEpoch(header data.HeaderHandler) error { ps.activePersisters = append(singleItemPersisters, ps.activePersisters...) ps.persistersMapByEpoch[epoch] = newPersister + return ps.removeOldPersistersIfNeeded(header, epoch) +} + +func (ps *PruningStorer) removeOldPersistersIfNeeded(header data.HeaderHandler, epoch uint32) error { wasExtended := ps.extendSavedEpochsIfNeeded(header) if wasExtended { if len(ps.activePersisters) > int(ps.numOfActivePersisters) { @@ -814,11 +818,12 @@ func (ps *PruningStorer) changeEpoch(header data.HeaderHandler) error { return nil } - err = ps.closeAndDestroyPersisters(epoch) + err := ps.closeAndDestroyPersisters(epoch) if err != nil { log.Warn("closing persisters", "error", err.Error()) return err } + return nil } From aa66f652193d15790ce8dfb72ccf6b31cf088be7 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Tue, 10 Dec 2024 17:07:43 +0200 Subject: [PATCH 34/74] add log trace --- storage/pruning/fullHistoryPruningStorer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/storage/pruning/fullHistoryPruningStorer.go b/storage/pruning/fullHistoryPruningStorer.go index 71213b1dcdd..97852aa3bcd 100644 --- a/storage/pruning/fullHistoryPruningStorer.go +++ b/storage/pruning/fullHistoryPruningStorer.go @@ -184,6 +184,7 @@ func (fhps *FullHistoryPruningStorer) getOrOpenPersister(epoch uint32) (storage. } fhps.oldEpochsActivePersistersCache.Put([]byte(epochString), newPdata, 0) + log.Trace("full history pruning storer - init new storer", "epoch", epoch) fhps.persistersMapByEpoch[epoch] = newPdata return newPdata.getPersister(), nil From 480ce7e2fcce9196fef6ce815347936d35b796fa Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Wed, 11 Dec 2024 09:36:55 +0200 Subject: [PATCH 35/74] fixes after merge --- process/transaction/baseProcess.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 77761dbf91c..73af11f5063 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -190,7 +190,7 @@ func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( destinationAccount state.UserAccountHandler, relayerAccount state.UserAccountHandler, ) error { - err := txProc.verifyGuardian(tx, senderAccount) + err := txProc.VerifyGuardian(tx, senderAccount) if err != nil { return err } @@ -367,6 +367,7 @@ func (txProc *baseTxProcessor) checkGuardedAccountUnguardedTxPermission(tx *tran return nil } +// VerifyGuardian does the guardian verification func (txProc *baseTxProcessor) VerifyGuardian(tx *transaction.Transaction, account state.UserAccountHandler) error { if check.IfNil(account) { return nil From 0bdd1c3f50446c8db3384fba8d2059f55b2cfa5e Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 11 Dec 2024 13:38:28 +0200 Subject: [PATCH 36/74] add unit tests --- .../pruning/fullHistoryPruningStorer_test.go | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/storage/pruning/fullHistoryPruningStorer_test.go b/storage/pruning/fullHistoryPruningStorer_test.go index 0e0d43877e8..80b0290511d 100644 --- a/storage/pruning/fullHistoryPruningStorer_test.go +++ b/storage/pruning/fullHistoryPruningStorer_test.go @@ -4,6 +4,7 @@ import ( "context" "crypto/rand" "fmt" + "github.com/multiversx/mx-chain-go/testscommon" "math" "path/filepath" "sync" @@ -399,3 +400,33 @@ func TestFullHistoryPruningStorer_IsInterfaceNil(t *testing.T) { fhps, _ = pruning.NewFullHistoryPruningStorer(fhArgs) require.False(t, fhps.IsInterfaceNil()) } + +func TestFullHistoryPruningStorer_changeEpochClosesOldDbs(t *testing.T) { + t.Parallel() + + shouldCleanCalled := false + args := getDefaultArgs() + fhArgs := pruning.FullHistoryStorerArgs{ + StorerArgs: args, + NumOfOldActivePersisters: 2, + } + fhArgs.OldDataCleanerProvider = &testscommon.OldDataCleanerProviderStub{ + ShouldCleanCalled: func() bool { + shouldCleanCalled = true + return true + }, + } + fhps, err := pruning.NewFullHistoryPruningStorer(fhArgs) + require.Nil(t, err) + + numEpochsChanged := 10 + startEpoch := uint32(0) + for i := 0; i < numEpochsChanged; i++ { + startEpoch++ + key := []byte(fmt.Sprintf("key-%d", i)) + _, _ = fhps.GetFromEpoch(key, startEpoch) + err = fhps.ChangeEpochSimple(startEpoch) + require.Nil(t, err) + } + require.True(t, shouldCleanCalled) +} From 1beb4ca88778ac0dda512234f45df59107e3c3a5 Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 11 Dec 2024 13:41:15 +0200 Subject: [PATCH 37/74] sort imports --- storage/pruning/fullHistoryPruningStorer_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/pruning/fullHistoryPruningStorer_test.go b/storage/pruning/fullHistoryPruningStorer_test.go index 80b0290511d..d1274499bb9 100644 --- a/storage/pruning/fullHistoryPruningStorer_test.go +++ b/storage/pruning/fullHistoryPruningStorer_test.go @@ -4,7 +4,6 @@ import ( "context" "crypto/rand" "fmt" - "github.com/multiversx/mx-chain-go/testscommon" "math" "path/filepath" "sync" @@ -19,6 +18,7 @@ import ( "github.com/multiversx/mx-chain-go/storage/factory" "github.com/multiversx/mx-chain-go/storage/pathmanager" "github.com/multiversx/mx-chain-go/storage/pruning" + "github.com/multiversx/mx-chain-go/testscommon" logger "github.com/multiversx/mx-chain-logger-go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" From fee796fb44c15303b33de173a46151c118f8154e Mon Sep 17 00:00:00 2001 From: BeniaminDrasovean Date: Wed, 11 Dec 2024 15:03:36 +0200 Subject: [PATCH 38/74] fix after review --- storage/pruning/pruningStorer.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/storage/pruning/pruningStorer.go b/storage/pruning/pruningStorer.go index aab0b744e54..d40680e5c87 100644 --- a/storage/pruning/pruningStorer.go +++ b/storage/pruning/pruningStorer.go @@ -779,7 +779,7 @@ func (ps *PruningStorer) changeEpoch(header data.HeaderHandler) error { } log.Debug("change epoch pruning storer success", "persister", ps.identifier, "epoch", epoch) - return ps.removeOldPersistersIfNeeded(header, epoch) + return ps.removeOldPersistersIfNeeded(header) } shardID := core.GetShardIDString(ps.shardCoordinator.SelfId()) @@ -802,10 +802,11 @@ func (ps *PruningStorer) changeEpoch(header data.HeaderHandler) error { ps.activePersisters = append(singleItemPersisters, ps.activePersisters...) ps.persistersMapByEpoch[epoch] = newPersister - return ps.removeOldPersistersIfNeeded(header, epoch) + return ps.removeOldPersistersIfNeeded(header) } -func (ps *PruningStorer) removeOldPersistersIfNeeded(header data.HeaderHandler, epoch uint32) error { +func (ps *PruningStorer) removeOldPersistersIfNeeded(header data.HeaderHandler) error { + epoch := header.GetEpoch() wasExtended := ps.extendSavedEpochsIfNeeded(header) if wasExtended { if len(ps.activePersisters) > int(ps.numOfActivePersisters) { From 05e3a2a325185d135ca7fa16f45efefe2f545831 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 12 Dec 2024 14:30:42 +0200 Subject: [PATCH 39/74] Integrate storage-go. --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 538474732a6..70173c016bc 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,12 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.1 - github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83 + github.com/multiversx/mx-chain-core-go v1.2.24-0.20241204105653-2beb13136490 github.com/multiversx/mx-chain-crypto-go v1.2.12 github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 - github.com/multiversx/mx-chain-storage-go v1.0.18 + github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241212122833-853f67604809 github.com/multiversx/mx-chain-vm-common-go v1.5.16 github.com/multiversx/mx-chain-vm-go v1.5.37 github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68 diff --git a/go.sum b/go.sum index f06c97b4198..d47072eb254 100644 --- a/go.sum +++ b/go.sum @@ -387,8 +387,8 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.1 h1:y4DoQeQOJTaSUsRzczQFazf8JYQmInddypApqA3AkwM= github.com/multiversx/mx-chain-communication-go v1.1.1/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83 h1:VuFFYZ9hpMacAcqcKM0hg6j4D16qKAGihi3X6PaF8qs= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20241029140551-8ed69b598c83/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20241204105653-2beb13136490 h1:uK29uJdsvVYMp37wjC/qu74O8V04gFw0Bw7q9C9zc+c= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20241204105653-2beb13136490/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1 h1:wgMxgtUWd9//FPCTOLj/75j9Kwnd9PE2tHk0KLIFF6s= @@ -397,8 +397,8 @@ github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+w github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= github.com/multiversx/mx-chain-scenario-go v1.4.4/go.mod h1:kI+TWR3oIEgUkbwkHCPo2CQ3VjIge+ezGTibiSGwMxo= -github.com/multiversx/mx-chain-storage-go v1.0.18 h1:DA33o5COEjnCKclCeCvzXXI0zIgFp2QqZK32UTVvDes= -github.com/multiversx/mx-chain-storage-go v1.0.18/go.mod h1:eFDEOrG7Wiyk5I/ObpwcN2eoBlOnnfeEMTvTer1cymk= +github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241212122833-853f67604809 h1:UUYjeDiQhj7geG6zvnx4rIR0Nx3K6Ahr2/HIMzKMarI= +github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241212122833-853f67604809/go.mod h1:Ec+CrhDskz+UPcw/WjOCtQS4uCA1GNCseO3qM6SHj+A= github.com/multiversx/mx-chain-vm-common-go v1.5.16 h1:g1SqYjxl7K66Y1O/q6tvDJ37fzpzlxCSfRzSm/woQQY= github.com/multiversx/mx-chain-vm-common-go v1.5.16/go.mod h1:1rSkXreUZNXyPTTdhj47M+Fy62yjxbu3aAsXEtKN3UY= github.com/multiversx/mx-chain-vm-go v1.5.37 h1:Iy3KCvM+DOq1f9UPA7uYK/rI3ZbBOXc2CVNO2/vm5zw= From 559d93a043b86427ae2f9b554967e355073c2182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Fri, 13 Dec 2024 17:04:06 +0200 Subject: [PATCH 40/74] Reference storage-go, fix mempool memory tests. --- dataRetriever/txpool/memorytests/memory_test.go | 6 +++--- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dataRetriever/txpool/memorytests/memory_test.go b/dataRetriever/txpool/memorytests/memory_test.go index 1359ae8fb5f..e4e7f5f68b8 100644 --- a/dataRetriever/txpool/memorytests/memory_test.go +++ b/dataRetriever/txpool/memorytests/memory_test.go @@ -53,9 +53,9 @@ func TestShardedTxPool_MemoryFootprint(t *testing.T) { journals = append(journals, runScenario(t, newScenario(100, 1, core.MegabyteSize, "1_0"), memoryAssertion{90, 100}, memoryAssertion{0, 1})) journals = append(journals, runScenario(t, newScenario(10000, 1, 10240, "1_0"), memoryAssertion{96, 128}, memoryAssertion{0, 4})) - journals = append(journals, runScenario(t, newScenario(10, 10000, 1000, "1_0"), memoryAssertion{96, 140}, memoryAssertion{16, 25})) - journals = append(journals, runScenario(t, newScenario(150000, 1, 128, "1_0"), memoryAssertion{50, 80}, memoryAssertion{30, 40})) - journals = append(journals, runScenario(t, newScenario(1, 150000, 128, "1_0"), memoryAssertion{50, 80}, memoryAssertion{30, 40})) + journals = append(journals, runScenario(t, newScenario(10, 10000, 1000, "1_0"), memoryAssertion{96, 148}, memoryAssertion{16, 32})) + journals = append(journals, runScenario(t, newScenario(150000, 1, 128, "1_0"), memoryAssertion{50, 84}, memoryAssertion{30, 48})) + journals = append(journals, runScenario(t, newScenario(1, 150000, 128, "1_0"), memoryAssertion{50, 84}, memoryAssertion{30, 48})) for _, journal := range journals { journal.displayFootprintsSummary() diff --git a/go.mod b/go.mod index 70173c016bc..eb5d88cfb61 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 - github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241212122833-853f67604809 + github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241213090416-f46569554341 github.com/multiversx/mx-chain-vm-common-go v1.5.16 github.com/multiversx/mx-chain-vm-go v1.5.37 github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68 diff --git a/go.sum b/go.sum index d47072eb254..f96330123f3 100644 --- a/go.sum +++ b/go.sum @@ -397,8 +397,8 @@ github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+w github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= github.com/multiversx/mx-chain-scenario-go v1.4.4/go.mod h1:kI+TWR3oIEgUkbwkHCPo2CQ3VjIge+ezGTibiSGwMxo= -github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241212122833-853f67604809 h1:UUYjeDiQhj7geG6zvnx4rIR0Nx3K6Ahr2/HIMzKMarI= -github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241212122833-853f67604809/go.mod h1:Ec+CrhDskz+UPcw/WjOCtQS4uCA1GNCseO3qM6SHj+A= +github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241213090416-f46569554341 h1:SydNXPZIt7UpcveL8mUnOGAh+Oped851w2bGbaGqsWw= +github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241213090416-f46569554341/go.mod h1:Ec+CrhDskz+UPcw/WjOCtQS4uCA1GNCseO3qM6SHj+A= github.com/multiversx/mx-chain-vm-common-go v1.5.16 h1:g1SqYjxl7K66Y1O/q6tvDJ37fzpzlxCSfRzSm/woQQY= github.com/multiversx/mx-chain-vm-common-go v1.5.16/go.mod h1:1rSkXreUZNXyPTTdhj47M+Fy62yjxbu3aAsXEtKN3UY= github.com/multiversx/mx-chain-vm-go v1.5.37 h1:Iy3KCvM+DOq1f9UPA7uYK/rI3ZbBOXc2CVNO2/vm5zw= From 8e08e1a3630e994cfd84b88d73d09aa649e5eab2 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Fri, 13 Dec 2024 17:59:28 +0200 Subject: [PATCH 41/74] accept relayed tx v3 with sender account non-existent --- .../relayedTx/relayedTx_test.go | 55 +++++++++++++++++-- process/dataValidators/txValidator.go | 22 +++++++- process/dataValidators/txValidator_test.go | 7 ++- 3 files changed, 74 insertions(+), 10 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index 57c4393e1a4..f1b6582f83b 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -1,6 +1,7 @@ package relayedTx import ( + "crypto/rand" "encoding/hex" "encoding/json" "math/big" @@ -20,7 +21,9 @@ import ( "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" chainSimulatorProcess "github.com/multiversx/mx-chain-go/node/chainSimulator/process" "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/vm" + logger "github.com/multiversx/mx-chain-logger-go" "github.com/stretchr/testify/require" ) @@ -55,8 +58,10 @@ func TestRelayedV3WithChainSimulator(t *testing.T) { t.Run("intra shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 0)) t.Run("cross shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 1)) - t.Run("successful intra shard sc call with refunds", testRelayedV3ScCall(0, 0)) - t.Run("successful cross shard sc call with refunds", testRelayedV3ScCall(0, 1)) + t.Run("successful intra shard sc call with refunds, existing sender", testRelayedV3ScCall(0, 0, true)) + t.Run("successful intra shard sc call with refunds, new sender", testRelayedV3ScCall(0, 0, false)) + t.Run("successful cross shard sc call with refunds, existing sender", testRelayedV3ScCall(0, 1, true)) + t.Run("successful cross shard sc call with refunds, new sender", testRelayedV3ScCall(0, 1, false)) t.Run("intra shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 0)) t.Run("cross shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 1)) t.Run("intra shard sc call, invalid method", testRelayedV3ScCallInvalidMethod(0, 0)) @@ -267,6 +272,7 @@ func testRelayedV3MoveInvalidGasLimit( func testRelayedV3ScCall( relayerShard uint32, ownerShard uint32, + existingSenderWithBalance bool, ) func(t *testing.T) { return func(t *testing.T) { if testing.Short() { @@ -286,8 +292,7 @@ func testRelayedV3ScCall( relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) require.NoError(t, err) - sender, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) - require.NoError(t, err) + sender, senderInitialBalance := prepareSender(t, cs, existingSenderWithBalance, relayerShard, initialBalance) owner, err := cs.GenerateAndMintWalletAddress(ownerShard, initialBalance) require.NoError(t, err) @@ -330,7 +335,7 @@ func testRelayedV3ScCall( // check sender balance senderBalanceAfter := getBalance(t, cs, sender) - require.Equal(t, initialBalance.String(), senderBalanceAfter.String()) + require.Equal(t, senderInitialBalance.String(), senderBalanceAfter.String()) // check owner balance _, feeDeploy, _ := computeTxGasAndFeeBasedOnRefund(resultDeploy, refundDeploy, false, false) @@ -346,6 +351,46 @@ func testRelayedV3ScCall( } } +func prepareSender( + t *testing.T, + cs testsChainSimulator.ChainSimulator, + existingSenderWithBalance bool, + shard uint32, + initialBalance *big.Int, +) (dtos.WalletAddress, *big.Int) { + if existingSenderWithBalance { + sender, err := cs.GenerateAndMintWalletAddress(shard, initialBalance) + require.NoError(t, err) + + return sender, initialBalance + } + + shardC := cs.GetNodeHandler(shard).GetShardCoordinator() + pkConv := cs.GetNodeHandler(shard).GetCoreComponents().AddressPubKeyConverter() + newAddress := generateAddressInShard(shardC, pkConv.Len()) + return dtos.WalletAddress{ + Bech32: pkConv.SilentEncode(newAddress, logger.GetOrCreate("tmp")), + Bytes: newAddress, + }, big.NewInt(0) +} + +func generateAddressInShard(shardCoordinator sharding.Coordinator, len int) []byte { + for { + buff := generateAddress(len) + shardID := shardCoordinator.ComputeId(buff) + if shardID == shardCoordinator.SelfId() { + return buff + } + } +} + +func generateAddress(len int) []byte { + buff := make([]byte, len) + _, _ = rand.Read(buff) + + return buff +} + func testRelayedV3ScCallInvalidGasLimit( relayerShard uint32, ownerShard uint32, diff --git a/process/dataValidators/txValidator.go b/process/dataValidators/txValidator.go index 1e0c67ee007..c28b6265657 100644 --- a/process/dataValidators/txValidator.go +++ b/process/dataValidators/txValidator.go @@ -2,6 +2,7 @@ package dataValidators import ( "fmt" + "math/big" "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/check" @@ -76,14 +77,27 @@ func (txv *txValidator) CheckTxValidity(interceptedTx process.InterceptedTransac return nil } + // for relayed v3, we allow sender accounts that do not exist + isRelayedV3 := common.IsRelayedTxV3(interceptedTx.Transaction()) + hasValue := hasTxValue(interceptedTx) + shouldAllowMissingSenderAccount := isRelayedV3 && !hasValue accountHandler, err := txv.getSenderAccount(interceptedTx) - if err != nil { + if err != nil && !shouldAllowMissingSenderAccount { return err } return txv.checkAccount(interceptedTx, accountHandler) } +func hasTxValue(interceptedTx process.InterceptedTransactionHandler) bool { + txValue := interceptedTx.Transaction().GetValue() + if check.IfNilReflect(txValue) { + return false + } + + return big.NewInt(0).Cmp(txValue) < 0 +} + func (txv *txValidator) checkAccount( interceptedTx process.InterceptedTransactionHandler, accountHandler vmcommon.AccountHandler, @@ -149,7 +163,11 @@ func (txv *txValidator) checkBalance(interceptedTx process.InterceptedTransactio } func (txv *txValidator) checkNonce(interceptedTx process.InterceptedTransactionHandler, accountHandler vmcommon.AccountHandler) error { - accountNonce := accountHandler.GetNonce() + accountNonce := uint64(0) + if !check.IfNil(accountHandler) { + accountNonce = accountHandler.GetNonce() + } + txNonce := interceptedTx.Nonce() lowerNonceInTx := txNonce < accountNonce veryHighNonceInTx := txNonce > accountNonce+uint64(txv.maxNonceDeltaAllowed) diff --git a/process/dataValidators/txValidator_test.go b/process/dataValidators/txValidator_test.go index a45acf2b434..31fa230ec39 100644 --- a/process/dataValidators/txValidator_test.go +++ b/process/dataValidators/txValidator_test.go @@ -324,11 +324,11 @@ func TestTxValidator_CheckTxValidityAccountBalanceIsLessThanTxTotalValueShouldRe adb.GetExistingAccountCalled = func(address []byte) (handler vmcommon.AccountHandler, e error) { cnt++ if cnt == 1 { - require.True(t, bytes.Equal(providedSenderAddress, address)) - } else { - require.True(t, bytes.Equal(providedRelayerAddress, address)) + return nil, errors.New("sender not found") } + require.True(t, bytes.Equal(providedRelayerAddress, address)) + acc, _ := accounts.NewUserAccount(address, &trie.DataTrieTrackerStub{}, &trie.TrieLeafParserStub{}) acc.Nonce = accountNonce acc.Balance = accountBalance @@ -358,6 +358,7 @@ func TestTxValidator_CheckTxValidityAccountBalanceIsLessThanTxTotalValueShouldRe Signature: []byte("address sig"), RelayerAddr: providedRelayerAddress, RelayerSignature: []byte("relayer sig"), + Value: big.NewInt(0), } } result := txValidator.CheckTxValidity(txValidatorHandler) From 8cf26729f46d0a9b101e1b3f1b744c49b4fea647 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 16 Dec 2024 09:53:22 +0200 Subject: [PATCH 42/74] fix after review --- process/dataValidators/txValidator.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/process/dataValidators/txValidator.go b/process/dataValidators/txValidator.go index c28b6265657..d043f207ac0 100644 --- a/process/dataValidators/txValidator.go +++ b/process/dataValidators/txValidator.go @@ -2,7 +2,6 @@ package dataValidators import ( "fmt" - "math/big" "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/core/check" @@ -95,7 +94,7 @@ func hasTxValue(interceptedTx process.InterceptedTransactionHandler) bool { return false } - return big.NewInt(0).Cmp(txValue) < 0 + return txValue.Sign() > 0 } func (txv *txValidator) checkAccount( From eaf721abf49f28708b06a1297998d51971c19bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 19 Dec 2024 12:42:25 +0200 Subject: [PATCH 43/74] Better mempool tests (chain simulator). --- .../chainSimulator/mempool/mempool_test.go | 114 +++++++----------- .../chainSimulator/mempool/testutils_test.go | 13 +- 2 files changed, 53 insertions(+), 74 deletions(-) diff --git a/integrationTests/chainSimulator/mempool/mempool_test.go b/integrationTests/chainSimulator/mempool/mempool_test.go index 473a8f9bc35..1aad3d051a9 100644 --- a/integrationTests/chainSimulator/mempool/mempool_test.go +++ b/integrationTests/chainSimulator/mempool/mempool_test.go @@ -1,22 +1,17 @@ package mempool import ( - "math/big" "testing" "time" "github.com/multiversx/mx-chain-core-go/data/transaction" "github.com/multiversx/mx-chain-go/config" "github.com/multiversx/mx-chain-go/node/chainSimulator/configs" - "github.com/multiversx/mx-chain-go/node/chainSimulator/dtos" "github.com/multiversx/mx-chain-go/storage" - logger "github.com/multiversx/mx-chain-logger-go" "github.com/stretchr/testify/require" ) func TestMempoolWithChainSimulator_Selection(t *testing.T) { - logger.SetLogLevel("*:INFO,txcache:DEBUG") - if testing.Short() { t.Skip("this is not a short test") } @@ -56,6 +51,7 @@ func TestMempoolWithChainSimulator_Selection(t *testing.T) { } sendTransactions(t, simulator, transactions) + time.Sleep(durationWaitAfterSendMany) require.Equal(t, 30_000, getNumTransactionsInPool(simulator, shard)) selectedTransactions, gas := selectTransactions(t, simulator, shard) @@ -67,8 +63,8 @@ func TestMempoolWithChainSimulator_Selection(t *testing.T) { require.Equal(t, 27_756, getNumTransactionsInCurrentBlock(simulator, shard)) selectedTransactions, gas = selectTransactions(t, simulator, shard) - require.Equal(t, 30_000, len(selectedTransactions)) - require.Equal(t, 50_000*30_000, int(gas)) + require.Equal(t, 30_000-27_756, len(selectedTransactions)) + require.Equal(t, 50_000*(30_000-27_756), int(gas)) } func TestMempoolWithChainSimulator_Eviction(t *testing.T) { @@ -76,97 +72,77 @@ func TestMempoolWithChainSimulator_Eviction(t *testing.T) { t.Skip("this is not a short test") } - simulator := startChainSimulator(t, func(cfg *config.Configs) {}) - node := simulator.GetNodeHandler(0) - mempool := node.GetDataComponents().Datapool().Transactions() - - defer simulator.Close() - numSenders := 10000 numTransactionsPerSender := 30 + shard := 0 - senders := make([]dtos.WalletAddress, numSenders) - sendersNonces := make([]uint64, numSenders) - - for i := 0; i < numSenders; i++ { - sender, err := simulator.GenerateAndMintWalletAddress(0, oneEGLD) - require.NoError(t, err) - - senders[i] = sender - } - - receiver, err := simulator.GenerateAndMintWalletAddress(0, big.NewInt(0)) - require.NoError(t, err) + simulator := startChainSimulator(t, func(cfg *config.Configs) {}) + defer simulator.Close() - err = simulator.GenerateBlocks(1) - require.Nil(t, err) + participants := createParticipants(t, simulator, numSenders) + noncesTracker := newNoncesTracker() transactions := make([]*transaction.Transaction, 0, numSenders*numTransactionsPerSender) for i := 0; i < numSenders; i++ { + sender := participants.sendersByShard[shard][i] + receiver := participants.receiverByShard[shard] + for j := 0; j < numTransactionsPerSender; j++ { tx := &transaction.Transaction{ - Nonce: sendersNonces[i], - Value: oneEGLD, - SndAddr: senders[i].Bytes, + Nonce: noncesTracker.getThenIncrementNonce(sender), + Value: oneQuarterOfEGLD, + SndAddr: sender.Bytes, RcvAddr: receiver.Bytes, Data: []byte{}, - GasLimit: 50000, + GasLimit: 50_000, GasPrice: 1_000_000_000, ChainID: []byte(configs.ChainID), Version: 2, Signature: []byte("signature"), } - sendersNonces[i]++ transactions = append(transactions, tx) } } - numSent, err := node.GetFacadeHandler().SendBulkTransactions(transactions) - require.NoError(t, err) - require.Equal(t, 300000, int(numSent)) - - time.Sleep(1 * time.Second) - require.Equal(t, 300000, int(mempool.GetCounts().GetTotal())) + sendTransactions(t, simulator, transactions) + time.Sleep(durationWaitAfterSendMany) + require.Equal(t, 300_000, getNumTransactionsInPool(simulator, shard)) // Send one more transaction (fill up the mempool) - _, err = node.GetFacadeHandler().SendBulkTransactions([]*transaction.Transaction{ - { - Nonce: 42, - Value: oneEGLD, - SndAddr: senders[7].Bytes, - RcvAddr: receiver.Bytes, - Data: []byte{}, - GasLimit: 50000, - GasPrice: 1_000_000_000, - ChainID: []byte(configs.ChainID), - Version: 2, - Signature: []byte("signature"), - }, + sendTransaction(t, simulator, &transaction.Transaction{ + Nonce: 42, + Value: oneEGLD, + SndAddr: participants.sendersByShard[shard][7].Bytes, + RcvAddr: participants.receiverByShard[shard].Bytes, + Data: []byte{}, + GasLimit: 50000, + GasPrice: 1_000_000_000, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), }) - require.NoError(t, err) - time.Sleep(42 * time.Millisecond) - require.Equal(t, 300001, int(mempool.GetCounts().GetTotal())) + time.Sleep(durationWaitAfterSendSome) + require.Equal(t, 300_001, getNumTransactionsInPool(simulator, shard)) // Send one more transaction to trigger eviction - _, err = node.GetFacadeHandler().SendBulkTransactions([]*transaction.Transaction{ - { - Nonce: 42, - Value: oneEGLD, - SndAddr: senders[7].Bytes, - RcvAddr: receiver.Bytes, - Data: []byte{}, - GasLimit: 50000, - GasPrice: 1_000_000_000, - ChainID: []byte(configs.ChainID), - Version: 2, - Signature: []byte("signature"), - }, + sendTransaction(t, simulator, &transaction.Transaction{ + Nonce: 42, + Value: oneEGLD, + SndAddr: participants.sendersByShard[shard][7].Bytes, + RcvAddr: participants.receiverByShard[shard].Bytes, + Data: []byte{}, + GasLimit: 50000, + GasPrice: 1_000_000_000, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), }) - require.NoError(t, err) time.Sleep(1 * time.Second) - require.Equal(t, 300000+1+1-int(storage.TxPoolSourceMeNumItemsToPreemptivelyEvict), int(mempool.GetCounts().GetTotal())) + + expectedNumTransactionsInPool := 300_000 + 1 + 1 - int(storage.TxPoolSourceMeNumItemsToPreemptivelyEvict) + require.Equal(t, expectedNumTransactionsInPool, getNumTransactionsInPool(simulator, shard)) } diff --git a/integrationTests/chainSimulator/mempool/testutils_test.go b/integrationTests/chainSimulator/mempool/testutils_test.go index 34eed359e86..4e1b0c4430f 100644 --- a/integrationTests/chainSimulator/mempool/testutils_test.go +++ b/integrationTests/chainSimulator/mempool/testutils_test.go @@ -21,10 +21,11 @@ import ( ) var ( - oneEGLD = big.NewInt(1000000000000000000) - oneQuarterOfEGLD = big.NewInt(250000000000000000) - oneCentOfEGLD = big.NewInt(10000000000000000) - durationWaitAfterSend = 500 * time.Millisecond + oneEGLD = big.NewInt(1000000000000000000) + oneQuarterOfEGLD = big.NewInt(250000000000000000) + oneCentOfEGLD = big.NewInt(10000000000000000) + durationWaitAfterSendMany = 750 * time.Millisecond + durationWaitAfterSendSome = 10 * time.Millisecond ) func startChainSimulator(t *testing.T, alterConfigsFunction func(cfg *config.Configs)) testsChainSimulator.ChainSimulator { @@ -130,8 +131,10 @@ func sendTransactions(t *testing.T, simulator testsChainSimulator.ChainSimulator require.NoError(t, err) require.Equal(t, len(transactionsFromShard), int(numSent)) } +} - time.Sleep(durationWaitAfterSend) +func sendTransaction(t *testing.T, simulator testsChainSimulator.ChainSimulator, tx *transaction.Transaction) { + sendTransactions(t, simulator, []*transaction.Transaction{tx}) } func selectTransactions(t *testing.T, simulator testsChainSimulator.ChainSimulator, shard int) ([]*txcache.WrappedTransaction, uint64) { From 0ea87203952186c9549f7d91e3e834113fef2604 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 19 Dec 2024 19:03:44 +0200 Subject: [PATCH 44/74] fix receipts hash mismatch --- .../relayedTx/relayedTx_test.go | 35 +++++++++++++++++++ process/transaction/shardProcess.go | 6 +++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index f1b6582f83b..de9f2e748ab 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -180,6 +180,10 @@ func testRelayedV3MoveBalance( // check intra shard logs, should be none require.Nil(t, result.Logs) + + if extraGas { + require.NotNil(t, result.Receipt) + } } } @@ -824,6 +828,37 @@ func TestRelayedTransactionFeeField(t *testing.T) { }) } +func TestRegularMoveBalanceWithRefundReceipt(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + cs := startChainSimulator(t, func(cfg *config.Configs) {}) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + + sender, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + senderNonce := uint64(0) + + extraGas := uint64(minGasLimit) + gasLimit := minGasLimit + extraGas + tx := generateTransaction(sender.Bytes, senderNonce, sender.Bytes, oneEGLD, "", gasLimit) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + require.NotNil(t, result.Receipt) + expectedGasRefunded := core.SafeMul(extraGas, minGasPrice/deductionFactor) + require.Equal(t, expectedGasRefunded.String(), result.Receipt.Value.String()) +} + func startChainSimulator( t *testing.T, alterConfigsFunction func(cfg *config.Configs), diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 354ff22ef08..115e0771534 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -549,7 +549,11 @@ func (txProc *txProcessor) processMoveBalance( } } - txHash := originalTxHash + txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) + if err != nil { + return err + } + err = txProc.createReceiptWithReturnedGas(txHash, tx, feePayer, moveBalanceCost, totalCost, destShardTxType, isUserTxOfRelayed) if err != nil { return err From 145806cf85e48a4758b24977cf2ef22f0eaa0873 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 19 Dec 2024 20:02:31 +0200 Subject: [PATCH 45/74] fix tests --- integrationTests/chainSimulator/relayedTx/relayedTx_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index de9f2e748ab..9ad6028e340 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -151,7 +151,8 @@ func testRelayedV3MoveBalance( result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) require.NoError(t, err) - if relayerShard == destinationShard { + isIntraShard := relayerShard == destinationShard + if isIntraShard { require.NoError(t, cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx)) } @@ -181,7 +182,7 @@ func testRelayedV3MoveBalance( // check intra shard logs, should be none require.Nil(t, result.Logs) - if extraGas { + if extraGas && isIntraShard { require.NotNil(t, result.Receipt) } } From eba1fad81e9d1c5770218c5a55c155d3c36298be Mon Sep 17 00:00:00 2001 From: miiu Date: Mon, 23 Dec 2024 15:51:19 +0200 Subject: [PATCH 46/74] extend /block endpoint --- go.mod | 2 +- go.sum | 4 ++-- node/external/blockAPI/baseBlock.go | 12 ++++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index cc5f4259b96..d0690da2d1c 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.1 - github.com/multiversx/mx-chain-core-go v1.2.23 + github.com/multiversx/mx-chain-core-go v1.2.24-0.20241223124350-686902f86816 github.com/multiversx/mx-chain-crypto-go v1.2.12 github.com/multiversx/mx-chain-es-indexer-go v1.7.10 github.com/multiversx/mx-chain-logger-go v1.0.15 diff --git a/go.sum b/go.sum index b4ebd7201e0..4ec328ed38e 100644 --- a/go.sum +++ b/go.sum @@ -387,8 +387,8 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.1 h1:y4DoQeQOJTaSUsRzczQFazf8JYQmInddypApqA3AkwM= github.com/multiversx/mx-chain-communication-go v1.1.1/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.23 h1:8WlCGqJHR2HQ0vN4feJwb7W4VrCwBGIzPPHunOOg5Wc= -github.com/multiversx/mx-chain-core-go v1.2.23/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20241223124350-686902f86816 h1:Z4IZQsECQUItUfXc6WMhBYnuYn5HJ+hl1TiDdOY6RpI= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20241223124350-686902f86816/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= github.com/multiversx/mx-chain-es-indexer-go v1.7.10 h1:Umi7WN8h4BOXLw7CM3VgvaWkLGef7nXtaPIGbjBCT3U= diff --git a/node/external/blockAPI/baseBlock.go b/node/external/blockAPI/baseBlock.go index 63bfe673f37..df637f338d6 100644 --- a/node/external/blockAPI/baseBlock.go +++ b/node/external/blockAPI/baseBlock.go @@ -125,6 +125,18 @@ func (bap *baseAPIBlockProcessor) getAndAttachTxsToMb( firstProcessed := mbHeader.GetIndexOfFirstTxProcessed() lastProcessed := mbHeader.GetIndexOfLastTxProcessed() + + // When options.ForHyperblock is true, there are two scenarios: + // 1 - If not all transactions were executed, no transactions will be returned. + // 2 - If all transactions were executed, all transactions starting from index 0 will be returned. + if options.ForHyperblock { + allTxsWereExecuted := lastProcessed == int32(len(miniBlock.TxHashes)-1) + if !allTxsWereExecuted { + return nil + } + firstProcessed = 0 + } + return bap.getAndAttachTxsToMbByEpoch(miniblockHash, miniBlock, header, apiMiniblock, firstProcessed, lastProcessed, options) } From 6e5bcf57f18615c513046657e17df2caa7f75641 Mon Sep 17 00:00:00 2001 From: miiu Date: Fri, 27 Dec 2024 13:34:11 +0200 Subject: [PATCH 47/74] fix missing tokens from es --- .../alteredaccounts/tokensProcessor.go | 2 +- .../alteredaccounts/tokensProcessor_test.go | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/outport/process/alteredaccounts/tokensProcessor.go b/outport/process/alteredaccounts/tokensProcessor.go index 687c543bcdf..672a29fc7af 100644 --- a/outport/process/alteredaccounts/tokensProcessor.go +++ b/outport/process/alteredaccounts/tokensProcessor.go @@ -137,7 +137,7 @@ func (tp *tokensProcessor) processMultiTransferEvent(event data.EventHandler, ma if string(tokenID) == vmcommon.EGLDIdentifier { tp.processNativeEGLDTransferWithMultiTransfer(destinationAddress, markedAlteredAccounts) - return + continue } // process event for the sender address diff --git a/outport/process/alteredaccounts/tokensProcessor_test.go b/outport/process/alteredaccounts/tokensProcessor_test.go index af737a1de94..2ac172b88bf 100644 --- a/outport/process/alteredaccounts/tokensProcessor_test.go +++ b/outport/process/alteredaccounts/tokensProcessor_test.go @@ -97,3 +97,46 @@ func TestTokenProcessorProcessEventMultiTransferV2WithEGLD(t *testing.T) { } require.Equal(t, markedAccount2, markedAccounts["receiver"]) } + +func TestTokenProcessorProcessEventMultiTransferV2WithEGLDAndMoreTokens(t *testing.T) { + t.Parallel() + + tp := newTokensProcessor(&mock.ShardCoordinatorStub{}) + + markedAccounts := make(map[string]*markedAlteredAccount) + tp.processEvent(&transaction.Event{ + Identifier: []byte(core.BuiltInFunctionMultiESDTNFTTransfer), + Address: []byte("addr"), + Topics: [][]byte{[]byte("token1"), big.NewInt(0).Bytes(), []byte("2"), []byte(vmcommon.EGLDIdentifier), big.NewInt(0).Bytes(), []byte("3"), []byte("token2"), big.NewInt(0).Bytes(), []byte("2"), []byte("receiver")}, + }, markedAccounts) + + require.Equal(t, 2, len(markedAccounts)) + markedAccount1 := &markedAlteredAccount{ + tokens: map[string]*markedAlteredAccountToken{ + "token1": { + identifier: "token1", + nonce: 0, + }, + "token2": { + identifier: "token2", + nonce: 0, + }, + }, + } + require.Equal(t, markedAccount1, markedAccounts["addr"]) + + markedAccount2 := &markedAlteredAccount{ + balanceChanged: true, + tokens: map[string]*markedAlteredAccountToken{ + "token1": { + identifier: "token1", + nonce: 0, + }, + "token2": { + identifier: "token2", + nonce: 0, + }, + }, + } + require.Equal(t, markedAccount2, markedAccounts["receiver"]) +} From 0683dccac4824b3ad34a878701a0fa649cdc7cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 8 Jan 2025 12:16:23 +0200 Subject: [PATCH 48/74] On Node API, adjust processing type for relayed V3. --- .../chainSimulator/relayedTx/relayedTx_test.go | 3 ++- .../transactionAPI/apiTransactionProcessor.go | 6 +----- .../apiTransactionProcessor_test.go | 17 +++++++++++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index 9ad6028e340..6ff75b227f5 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -1002,7 +1002,8 @@ func computeTxGasAndFeeBasedOnRefund( gasForFullPrice += extraGasLimitForGuarded } - if result.ProcessingTypeOnSource == process.RelayedTxV3.String() { + isRelayedV3 := len(result.RelayerAddress) > 0 + if isRelayedV3 { gasForFullPrice += uint64(minGasLimit) // relayer fee } gasForDeductedPrice := initialTx.GetGasLimit() - gasForFullPrice diff --git a/node/external/transactionAPI/apiTransactionProcessor.go b/node/external/transactionAPI/apiTransactionProcessor.go index e7db63bba5d..f15a096ea5b 100644 --- a/node/external/transactionAPI/apiTransactionProcessor.go +++ b/node/external/transactionAPI/apiTransactionProcessor.go @@ -183,11 +183,7 @@ func (atp *apiTransactionProcessor) PopulateComputedFields(tx *transaction.ApiTr } func (atp *apiTransactionProcessor) populateComputedFieldsProcessingType(tx *transaction.ApiTransactionResult) { - typeOnSource, typeOnDestination, isRelayedV3 := atp.txTypeHandler.ComputeTransactionType(tx.Tx) - if isRelayedV3 { - typeOnSource = process.RelayedTxV3 - typeOnDestination = process.RelayedTxV3 - } + typeOnSource, typeOnDestination, _ := atp.txTypeHandler.ComputeTransactionType(tx.Tx) tx.ProcessingTypeOnSource = typeOnSource.String() tx.ProcessingTypeOnDestination = typeOnDestination.String() } diff --git a/node/external/transactionAPI/apiTransactionProcessor_test.go b/node/external/transactionAPI/apiTransactionProcessor_test.go index bbbbd6e1829..992cc512b0b 100644 --- a/node/external/transactionAPI/apiTransactionProcessor_test.go +++ b/node/external/transactionAPI/apiTransactionProcessor_test.go @@ -1332,10 +1332,23 @@ func TestApiTransactionProcessor_GetTransactionPopulatesComputedFields(t *testin require.Equal(t, process.SCDeployment.String(), tx.ProcessingTypeOnDestination) }) + t.Run("ProcessingType (with relayed v3)", func(t *testing.T) { + txTypeHandler.ComputeTransactionTypeCalled = func(data.TransactionHandler) (process.TransactionType, process.TransactionType, bool) { + return process.MoveBalance, process.SCDeployment, true + } + + dataPool.Transactions().AddData([]byte{0, 2}, &transaction.Transaction{Nonce: 7, SndAddr: []byte("alice"), RcvAddr: []byte("bob")}, 42, "1") + tx, err := processor.GetTransaction("0003", true) + + require.Nil(t, err) + require.Equal(t, process.MoveBalance.String(), tx.ProcessingTypeOnSource) + require.Equal(t, process.SCDeployment.String(), tx.ProcessingTypeOnDestination) + }) + t.Run("IsRefund (false)", func(t *testing.T) { scr := &smartContractResult.SmartContractResult{GasLimit: 0, Data: []byte("@ok"), Value: big.NewInt(0)} dataPool.UnsignedTransactions().AddData([]byte{0, 3}, scr, 42, "foo") - tx, err := processor.GetTransaction("0003", true) + tx, err := processor.GetTransaction("0004", true) require.Nil(t, err) require.Equal(t, false, tx.IsRefund) @@ -1344,7 +1357,7 @@ func TestApiTransactionProcessor_GetTransactionPopulatesComputedFields(t *testin t.Run("IsRefund (true)", func(t *testing.T) { scr := &smartContractResult.SmartContractResult{GasLimit: 0, Data: []byte("@6f6b"), Value: big.NewInt(500)} dataPool.UnsignedTransactions().AddData([]byte{0, 4}, scr, 42, "foo") - tx, err := processor.GetTransaction("0004", true) + tx, err := processor.GetTransaction("0005", true) require.Nil(t, err) require.Equal(t, true, tx.IsRefund) From c56d9e0dcf884b7aaacdce1e677cc1b4f145cb1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 8 Jan 2025 13:53:41 +0200 Subject: [PATCH 49/74] Update node/external/transactionAPI/apiTransactionProcessor_test.go Co-authored-by: Sorin Stanculeanu <34831323+sstanculeanu@users.noreply.github.com> --- node/external/transactionAPI/apiTransactionProcessor_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/external/transactionAPI/apiTransactionProcessor_test.go b/node/external/transactionAPI/apiTransactionProcessor_test.go index 992cc512b0b..259530bd6c8 100644 --- a/node/external/transactionAPI/apiTransactionProcessor_test.go +++ b/node/external/transactionAPI/apiTransactionProcessor_test.go @@ -1356,7 +1356,7 @@ func TestApiTransactionProcessor_GetTransactionPopulatesComputedFields(t *testin t.Run("IsRefund (true)", func(t *testing.T) { scr := &smartContractResult.SmartContractResult{GasLimit: 0, Data: []byte("@6f6b"), Value: big.NewInt(500)} - dataPool.UnsignedTransactions().AddData([]byte{0, 4}, scr, 42, "foo") + dataPool.UnsignedTransactions().AddData([]byte{0, 5}, scr, 42, "foo") tx, err := processor.GetTransaction("0005", true) require.Nil(t, err) From c8df156fccdd489743bc16cd3e37c16bc63aa2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 8 Jan 2025 13:53:51 +0200 Subject: [PATCH 50/74] Update node/external/transactionAPI/apiTransactionProcessor_test.go Co-authored-by: Sorin Stanculeanu <34831323+sstanculeanu@users.noreply.github.com> --- node/external/transactionAPI/apiTransactionProcessor_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/external/transactionAPI/apiTransactionProcessor_test.go b/node/external/transactionAPI/apiTransactionProcessor_test.go index 259530bd6c8..f507d754691 100644 --- a/node/external/transactionAPI/apiTransactionProcessor_test.go +++ b/node/external/transactionAPI/apiTransactionProcessor_test.go @@ -1337,7 +1337,7 @@ func TestApiTransactionProcessor_GetTransactionPopulatesComputedFields(t *testin return process.MoveBalance, process.SCDeployment, true } - dataPool.Transactions().AddData([]byte{0, 2}, &transaction.Transaction{Nonce: 7, SndAddr: []byte("alice"), RcvAddr: []byte("bob")}, 42, "1") + dataPool.Transactions().AddData([]byte{0, 3}, &transaction.Transaction{Nonce: 7, SndAddr: []byte("alice"), RcvAddr: []byte("bob")}, 42, "1") tx, err := processor.GetTransaction("0003", true) require.Nil(t, err) From 5456f8d2f8af2a4a07d0387722e08d02be275c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 8 Jan 2025 13:53:57 +0200 Subject: [PATCH 51/74] Update node/external/transactionAPI/apiTransactionProcessor_test.go Co-authored-by: Sorin Stanculeanu <34831323+sstanculeanu@users.noreply.github.com> --- node/external/transactionAPI/apiTransactionProcessor_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/external/transactionAPI/apiTransactionProcessor_test.go b/node/external/transactionAPI/apiTransactionProcessor_test.go index f507d754691..d7bd038bd7f 100644 --- a/node/external/transactionAPI/apiTransactionProcessor_test.go +++ b/node/external/transactionAPI/apiTransactionProcessor_test.go @@ -1347,7 +1347,7 @@ func TestApiTransactionProcessor_GetTransactionPopulatesComputedFields(t *testin t.Run("IsRefund (false)", func(t *testing.T) { scr := &smartContractResult.SmartContractResult{GasLimit: 0, Data: []byte("@ok"), Value: big.NewInt(0)} - dataPool.UnsignedTransactions().AddData([]byte{0, 3}, scr, 42, "foo") + dataPool.UnsignedTransactions().AddData([]byte{0, 4}, scr, 42, "foo") tx, err := processor.GetTransaction("0004", true) require.Nil(t, err) From c3dfab57b47fca08ae30d1653d384a80fa85325a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Wed, 8 Jan 2025 13:56:53 +0200 Subject: [PATCH 52/74] Fix after review. --- integrationTests/chainSimulator/relayedTx/relayedTx_test.go | 4 ++-- process/constants.go | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index 6ff75b227f5..b7b74a66944 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -12,6 +12,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/config" testsChainSimulator "github.com/multiversx/mx-chain-go/integrationTests/chainSimulator" "github.com/multiversx/mx-chain-go/integrationTests/vm/wasm" @@ -1002,8 +1003,7 @@ func computeTxGasAndFeeBasedOnRefund( gasForFullPrice += extraGasLimitForGuarded } - isRelayedV3 := len(result.RelayerAddress) > 0 - if isRelayedV3 { + if common.IsRelayedTxV3(initialTx) { gasForFullPrice += uint64(minGasLimit) // relayer fee } gasForDeductedPrice := initialTx.GetGasLimit() - gasForFullPrice diff --git a/process/constants.go b/process/constants.go index e82da971fd4..997e0a2a458 100644 --- a/process/constants.go +++ b/process/constants.go @@ -37,8 +37,6 @@ const ( RelayedTx // RelayedTxV2 defines the ID of a slim relayed transaction version RelayedTxV2 - // RelayedTxV3 defines the ID of a relayed transaction v3 - RelayedTxV3 // RewardTx defines ID of a reward transaction RewardTx // InvalidTransaction defines unknown transaction type @@ -59,8 +57,6 @@ func (transactionType TransactionType) String() string { return "RelayedTx" case RelayedTxV2: return "RelayedTxV2" - case RelayedTxV3: - return "RelayedTxV3" case RewardTx: return "RewardTx" case InvalidTransaction: From 07627b90489a4edde0a460ac8b1c76d9ca7441e5 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 9 Jan 2025 11:12:24 +0200 Subject: [PATCH 53/74] extract forHyperblock from block requests --- api/groups/blockGroup.go | 8 +++++++- api/groups/blockGroup_test.go | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/api/groups/blockGroup.go b/api/groups/blockGroup.go index 26d9c05b000..f9f0ed81fd8 100644 --- a/api/groups/blockGroup.go +++ b/api/groups/blockGroup.go @@ -26,6 +26,7 @@ const ( urlParamTokensFilter = "tokens" urlParamWithTxs = "withTxs" urlParamWithLogs = "withLogs" + urlParamForHyperblock = "forHyperblock" ) // blockFacadeHandler defines the methods to be implemented by a facade for handling block requests @@ -219,7 +220,12 @@ func parseBlockQueryOptions(c *gin.Context) (api.BlockQueryOptions, error) { return api.BlockQueryOptions{}, err } - options := api.BlockQueryOptions{WithTransactions: withTxs, WithLogs: withLogs} + forHyperBlock, err := parseBoolUrlParam(c, urlParamForHyperblock) + if err != nil { + return api.BlockQueryOptions{}, err + } + + options := api.BlockQueryOptions{WithTransactions: withTxs, WithLogs: withLogs, ForHyperblock: forHyperBlock} return options, nil } diff --git a/api/groups/blockGroup_test.go b/api/groups/blockGroup_test.go index b190c2f0561..a2ebc61548b 100644 --- a/api/groups/blockGroup_test.go +++ b/api/groups/blockGroup_test.go @@ -90,7 +90,7 @@ func TestBlockGroup_getBlockByNonce(t *testing.T) { t.Parallel() providedNonce := uint64(37) - expectedOptions := api.BlockQueryOptions{WithTransactions: true} + expectedOptions := api.BlockQueryOptions{WithTransactions: true, ForHyperblock: true} expectedBlock := api.Block{ Nonce: 37, Round: 39, @@ -107,7 +107,7 @@ func TestBlockGroup_getBlockByNonce(t *testing.T) { loadBlockGroupResponse( t, facade, - fmt.Sprintf("/block/by-nonce/%d?withTxs=true", providedNonce), + fmt.Sprintf("/block/by-nonce/%d?withTxs=true&forHyperblock=true", providedNonce), "GET", nil, response, From 4bef80d07e1c94048e1f842c8900abed146db5ec Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 9 Jan 2025 17:24:50 +0200 Subject: [PATCH 54/74] update deps after merge --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index eb5d88cfb61..58d4c45bd34 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,12 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.1 - github.com/multiversx/mx-chain-core-go v1.2.24-0.20241204105653-2beb13136490 + github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1 + github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250109151711-ceaca49de8e1 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 - github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241213090416-f46569554341 + github.com/multiversx/mx-chain-storage-go v1.0.19-0.20250109152325-cf81acfd19bd github.com/multiversx/mx-chain-vm-common-go v1.5.16 github.com/multiversx/mx-chain-vm-go v1.5.37 github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68 diff --git a/go.sum b/go.sum index f96330123f3..b361ab5e311 100644 --- a/go.sum +++ b/go.sum @@ -387,18 +387,18 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.1 h1:y4DoQeQOJTaSUsRzczQFazf8JYQmInddypApqA3AkwM= github.com/multiversx/mx-chain-communication-go v1.1.1/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20241204105653-2beb13136490 h1:uK29uJdsvVYMp37wjC/qu74O8V04gFw0Bw7q9C9zc+c= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20241204105653-2beb13136490/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8 h1:0ivlwcl+dKK7BTVngm1uNM2aDneaXK2rhS0HVeBkvYg= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1 h1:wgMxgtUWd9//FPCTOLj/75j9Kwnd9PE2tHk0KLIFF6s= -github.com/multiversx/mx-chain-es-indexer-go v1.7.11-0.20241118100151-956a1f23c5c1/go.mod h1:/KoFDVgh9kGYiINm2THJsII7jfxmbTXWtBoSS1dJo1w= +github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250109151711-ceaca49de8e1 h1:rHZS2Nw7M8thrtdN+s8qIf7TN9pi79r8n9J2gs0MaCc= +github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250109151711-ceaca49de8e1/go.mod h1:NMNBlIO60Wc026iSDp/eqnb0YmoiH05pEuphkdlW43k= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= github.com/multiversx/mx-chain-scenario-go v1.4.4/go.mod h1:kI+TWR3oIEgUkbwkHCPo2CQ3VjIge+ezGTibiSGwMxo= -github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241213090416-f46569554341 h1:SydNXPZIt7UpcveL8mUnOGAh+Oped851w2bGbaGqsWw= -github.com/multiversx/mx-chain-storage-go v1.0.19-0.20241213090416-f46569554341/go.mod h1:Ec+CrhDskz+UPcw/WjOCtQS4uCA1GNCseO3qM6SHj+A= +github.com/multiversx/mx-chain-storage-go v1.0.19-0.20250109152325-cf81acfd19bd h1:qhdCOHlo4EAvFpGhToDKPiXwZA8x9PeGcBWTVvYzUOw= +github.com/multiversx/mx-chain-storage-go v1.0.19-0.20250109152325-cf81acfd19bd/go.mod h1:8EA0PzK1ZPGpSKe+nXHx0My1MJlBcJ51fb7J7SwH7Lw= github.com/multiversx/mx-chain-vm-common-go v1.5.16 h1:g1SqYjxl7K66Y1O/q6tvDJ37fzpzlxCSfRzSm/woQQY= github.com/multiversx/mx-chain-vm-common-go v1.5.16/go.mod h1:1rSkXreUZNXyPTTdhj47M+Fy62yjxbu3aAsXEtKN3UY= github.com/multiversx/mx-chain-vm-go v1.5.37 h1:Iy3KCvM+DOq1f9UPA7uYK/rI3ZbBOXc2CVNO2/vm5zw= From 7092e6154857b474f749d96e2081227af32dcd1b Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 9 Jan 2025 17:39:52 +0200 Subject: [PATCH 55/74] new metric for extra relayed tx gas limit --- api/groups/networkGroup_test.go | 30 ++++++++++++++++++++ common/constants.go | 3 ++ node/chainSimulator/components/nodeFacade.go | 1 + node/nodeRunner.go | 1 + statusHandler/statusMetricsProvider.go | 1 + statusHandler/statusMetricsProvider_test.go | 2 ++ 6 files changed, 38 insertions(+) diff --git a/api/groups/networkGroup_test.go b/api/groups/networkGroup_test.go index 3eb52a4a0c0..c809a632b56 100644 --- a/api/groups/networkGroup_test.go +++ b/api/groups/networkGroup_test.go @@ -206,6 +206,36 @@ func TestNetworkConfigMetrics_GasLimitGuardedTxShouldWork(t *testing.T) { assert.True(t, keyAndValueFoundInResponse) } +func TestNetworkConfigMetrics_GasLimitRelayedTxShouldWork(t *testing.T) { + t.Parallel() + + statusMetricsProvider := statusHandler.NewStatusMetrics() + key := common.MetricExtraGasLimitRelayedTx + val := uint64(123) + statusMetricsProvider.SetUInt64Value(key, val) + + facade := mock.FacadeStub{} + facade.StatusMetricsHandler = func() external.StatusMetricsHandler { + return statusMetricsProvider + } + + networkGroup, err := groups.NewNetworkGroup(&facade) + require.NoError(t, err) + + ws := startWebServer(networkGroup, "network", getNetworkRoutesConfig()) + + req, _ := http.NewRequest("GET", "/network/config", nil) + resp := httptest.NewRecorder() + ws.ServeHTTP(resp, req) + + respBytes, _ := io.ReadAll(resp.Body) + respStr := string(respBytes) + assert.Equal(t, resp.Code, http.StatusOK) + + keyAndValueFoundInResponse := strings.Contains(respStr, key) && strings.Contains(respStr, fmt.Sprintf("%d", val)) + assert.True(t, keyAndValueFoundInResponse) +} + func TestNetworkStatusMetrics_ShouldWork(t *testing.T) { t.Parallel() diff --git a/common/constants.go b/common/constants.go index 67725bdb0b3..e2ed1d80a5a 100644 --- a/common/constants.go +++ b/common/constants.go @@ -340,6 +340,9 @@ const MetricMinGasLimit = "erd_min_gas_limit" // MetricExtraGasLimitGuardedTx specifies the extra gas limit required for guarded transactions const MetricExtraGasLimitGuardedTx = "erd_extra_gas_limit_guarded_tx" +// MetricExtraGasLimitRelayedTx specifies the extra gas limit required for relayed v3 transactions +const MetricExtraGasLimitRelayedTx = "erd_extra_gas_limit_relayed_tx" + // MetricRewardsTopUpGradientPoint is the metric that specifies the rewards top up gradient point const MetricRewardsTopUpGradientPoint = "erd_rewards_top_up_gradient_point" diff --git a/node/chainSimulator/components/nodeFacade.go b/node/chainSimulator/components/nodeFacade.go index d62814fdf03..934807c0659 100644 --- a/node/chainSimulator/components/nodeFacade.go +++ b/node/chainSimulator/components/nodeFacade.go @@ -177,6 +177,7 @@ func (node *testOnlyProcessingNode) createMetrics(configs config.Configs) error metrics.SaveUint64Metric(node.StatusCoreComponents.AppStatusHandler(), common.MetricMinGasPrice, node.CoreComponentsHolder.EconomicsData().MinGasPrice()) metrics.SaveUint64Metric(node.StatusCoreComponents.AppStatusHandler(), common.MetricMinGasLimit, node.CoreComponentsHolder.EconomicsData().MinGasLimit()) metrics.SaveUint64Metric(node.StatusCoreComponents.AppStatusHandler(), common.MetricExtraGasLimitGuardedTx, node.CoreComponentsHolder.EconomicsData().ExtraGasLimitGuardedTx()) + metrics.SaveUint64Metric(node.StatusCoreComponents.AppStatusHandler(), common.MetricExtraGasLimitRelayedTx, node.CoreComponentsHolder.EconomicsData().MinGasLimit()) metrics.SaveStringMetric(node.StatusCoreComponents.AppStatusHandler(), common.MetricRewardsTopUpGradientPoint, node.CoreComponentsHolder.EconomicsData().RewardsTopUpGradientPoint().String()) metrics.SaveStringMetric(node.StatusCoreComponents.AppStatusHandler(), common.MetricTopUpFactor, fmt.Sprintf("%g", node.CoreComponentsHolder.EconomicsData().RewardsTopUpFactor())) metrics.SaveStringMetric(node.StatusCoreComponents.AppStatusHandler(), common.MetricGasPriceModifier, fmt.Sprintf("%g", node.CoreComponentsHolder.EconomicsData().GasPriceModifier())) diff --git a/node/nodeRunner.go b/node/nodeRunner.go index 1837c78b427..749d70ffd2a 100644 --- a/node/nodeRunner.go +++ b/node/nodeRunner.go @@ -845,6 +845,7 @@ func (nr *nodeRunner) createMetrics( metrics.SaveUint64Metric(statusCoreComponents.AppStatusHandler(), common.MetricMinGasPrice, coreComponents.EconomicsData().MinGasPrice()) metrics.SaveUint64Metric(statusCoreComponents.AppStatusHandler(), common.MetricMinGasLimit, coreComponents.EconomicsData().MinGasLimit()) metrics.SaveUint64Metric(statusCoreComponents.AppStatusHandler(), common.MetricExtraGasLimitGuardedTx, coreComponents.EconomicsData().ExtraGasLimitGuardedTx()) + metrics.SaveUint64Metric(statusCoreComponents.AppStatusHandler(), common.MetricExtraGasLimitRelayedTx, coreComponents.EconomicsData().MinGasLimit()) metrics.SaveStringMetric(statusCoreComponents.AppStatusHandler(), common.MetricRewardsTopUpGradientPoint, coreComponents.EconomicsData().RewardsTopUpGradientPoint().String()) metrics.SaveStringMetric(statusCoreComponents.AppStatusHandler(), common.MetricTopUpFactor, fmt.Sprintf("%g", coreComponents.EconomicsData().RewardsTopUpFactor())) metrics.SaveStringMetric(statusCoreComponents.AppStatusHandler(), common.MetricGasPriceModifier, fmt.Sprintf("%g", coreComponents.EconomicsData().GasPriceModifier())) diff --git a/statusHandler/statusMetricsProvider.go b/statusHandler/statusMetricsProvider.go index f068b2630f8..bc92e511c10 100644 --- a/statusHandler/statusMetricsProvider.go +++ b/statusHandler/statusMetricsProvider.go @@ -246,6 +246,7 @@ func (sm *statusMetrics) ConfigMetrics() (map[string]interface{}, error) { configMetrics[common.MetricMinGasPrice] = sm.uint64Metrics[common.MetricMinGasPrice] configMetrics[common.MetricMinGasLimit] = sm.uint64Metrics[common.MetricMinGasLimit] configMetrics[common.MetricExtraGasLimitGuardedTx] = sm.uint64Metrics[common.MetricExtraGasLimitGuardedTx] + configMetrics[common.MetricExtraGasLimitRelayedTx] = sm.uint64Metrics[common.MetricExtraGasLimitRelayedTx] configMetrics[common.MetricMaxGasPerTransaction] = sm.uint64Metrics[common.MetricMaxGasPerTransaction] configMetrics[common.MetricRoundDuration] = sm.uint64Metrics[common.MetricRoundDuration] configMetrics[common.MetricStartTime] = sm.uint64Metrics[common.MetricStartTime] diff --git a/statusHandler/statusMetricsProvider_test.go b/statusHandler/statusMetricsProvider_test.go index 65374bee5f0..40303970ce5 100644 --- a/statusHandler/statusMetricsProvider_test.go +++ b/statusHandler/statusMetricsProvider_test.go @@ -179,6 +179,7 @@ func TestStatusMetrics_NetworkConfig(t *testing.T) { sm.SetUInt64Value(common.MetricMinGasPrice, 1000) sm.SetUInt64Value(common.MetricMinGasLimit, 50000) sm.SetUInt64Value(common.MetricExtraGasLimitGuardedTx, 50000) + sm.SetUInt64Value(common.MetricExtraGasLimitRelayedTx, 50000) sm.SetStringValue(common.MetricRewardsTopUpGradientPoint, "12345") sm.SetUInt64Value(common.MetricGasPerDataByte, 1500) sm.SetStringValue(common.MetricChainId, "local-id") @@ -202,6 +203,7 @@ func TestStatusMetrics_NetworkConfig(t *testing.T) { "erd_meta_consensus_group_size": uint64(25), "erd_min_gas_limit": uint64(50000), "erd_extra_gas_limit_guarded_tx": uint64(50000), + "erd_extra_gas_limit_relayed_tx": uint64(50000), "erd_min_gas_price": uint64(1000), "erd_min_transaction_version": uint64(2), "erd_num_metachain_nodes": uint64(50), From 58251d2a1b3a22595866d9106adaad1dbc95b437 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 13 Jan 2025 17:08:57 +0200 Subject: [PATCH 56/74] fix relayed v3 with relayer one of the participants leading to free txs --- .../relayedTx/relayedTx_test.go | 115 ++++++++++++++++++ process/transaction/baseProcess.go | 15 ++- process/transaction/shardProcess.go | 33 ++--- 3 files changed, 145 insertions(+), 18 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index b7b74a66944..37c17c602d8 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -48,6 +48,8 @@ var ( ) func TestRelayedV3WithChainSimulator(t *testing.T) { + t.Run("sender == relayer move balance should consume fee", testRelayedV3RelayedBySenderMoveBalance()) + t.Run("receiver == relayer move balance should consume fee", testRelayedV3RelayedByReceiverMoveBalance()) t.Run("successful intra shard move balance", testRelayedV3MoveBalance(0, 0, false, false)) t.Run("successful intra shard guarded move balance", testRelayedV3MoveBalance(0, 0, false, true)) t.Run("successful intra shard move balance with extra gas", testRelayedV3MoveBalance(0, 0, true, false)) @@ -357,6 +359,119 @@ func testRelayedV3ScCall( } } +func testRelayedV3RelayedBySenderMoveBalance() func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + + sender, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + senderNonce := uint64(0) + senderBalanceBefore := getBalance(t, cs, sender) + + gasLimit := minGasLimit * 2 + relayedTx := generateRelayedV3Transaction(sender.Bytes, senderNonce, sender.Bytes, sender.Bytes, big.NewInt(0), "", uint64(gasLimit)) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // check fee fields + initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, big.NewInt(0), true, false) + require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) + require.Equal(t, fee.String(), result.Fee) + require.Equal(t, gasUsed, result.GasUsed) + + // check sender balance + expectedFee := core.SafeMul(uint64(gasLimit), uint64(minGasPrice)) + senderBalanceAfter := getBalance(t, cs, sender) + senderBalanceDiff := big.NewInt(0).Sub(senderBalanceBefore, senderBalanceAfter) + require.Equal(t, expectedFee.String(), senderBalanceDiff.String()) + + // check scrs, should be none + require.Zero(t, len(result.SmartContractResults)) + + // check intra shard logs, should be none + require.Nil(t, result.Logs) + } +} + +func testRelayedV3RelayedByReceiverMoveBalance() func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + providedActivationEpoch := uint32(1) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + + sender, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + receiver, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + senderNonce := uint64(0) + receiverBalanceBefore := getBalance(t, cs, receiver) + + gasLimit := minGasLimit * 2 + relayedTx := generateRelayedV3Transaction(sender.Bytes, senderNonce, receiver.Bytes, receiver.Bytes, big.NewInt(0), "", uint64(gasLimit)) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // check fee fields + initiallyPaidFee, fee, gasUsed := computeTxGasAndFeeBasedOnRefund(result, big.NewInt(0), true, false) + require.Equal(t, initiallyPaidFee.String(), result.InitiallyPaidFee) + require.Equal(t, fee.String(), result.Fee) + require.Equal(t, gasUsed, result.GasUsed) + + // check sender balance + senderBalanceAfter := getBalance(t, cs, sender) + require.Equal(t, senderBalanceAfter.String(), initialBalance.String()) + + // check receiver balance + expectedFee := core.SafeMul(uint64(gasLimit), uint64(minGasPrice)) + receiverBalanceAfter := getBalance(t, cs, receiver) + receiverBalanceDiff := big.NewInt(0).Sub(receiverBalanceBefore, receiverBalanceAfter) + require.Equal(t, receiverBalanceDiff.String(), expectedFee.String()) + + // check scrs, should be none + require.Zero(t, len(result.SmartContractResults)) + + // check intra shard logs, should be none + require.Nil(t, result.Logs) + } +} + func prepareSender( t *testing.T, cs testsChainSimulator.ChainSimulator, diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 73af11f5063..aa35237baaa 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -239,10 +239,21 @@ func (txProc *baseTxProcessor) checkUserTxOfRelayedV3Values( func (txProc *baseTxProcessor) getFeePayer( tx *transaction.Transaction, - acntSnd state.UserAccountHandler, + senderAccount state.UserAccountHandler, + destinationAccount state.UserAccountHandler, ) (state.UserAccountHandler, bool, error) { if !common.IsRelayedTxV3(tx) { - return acntSnd, false, nil + return senderAccount, false, nil + } + + relayerIsSender := bytes.Compare(tx.RelayerAddr, tx.SndAddr) == 0 + if relayerIsSender { + return destinationAccount, true, nil // do not load the same account twice + } + + relayerIsDestination := bytes.Compare(tx.RelayerAddr, tx.RcvAddr) == 0 + if relayerIsDestination { + return destinationAccount, true, nil // do not load the same account twice } acntRelayer, err := txProc.getAccountFromAddress(tx.RelayerAddr) diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 115e0771534..a9b4d4d68b8 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -200,14 +200,14 @@ func (txProc *txProcessor) ProcessTransaction(tx *transaction.Transaction) (vmco err = txProc.checkTxValues(tx, acntSnd, acntDst, false) if err != nil { if errors.Is(err, process.ErrInsufficientFunds) { - receiptErr := txProc.executingFailedTransaction(tx, acntSnd, err) + receiptErr := txProc.executingFailedTransaction(tx, acntSnd, acntDst, err) if receiptErr != nil { return 0, receiptErr } } if errors.Is(err, process.ErrUserNameDoesNotMatch) && txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsFlag) { - receiptErr := txProc.executingFailedTransaction(tx, acntSnd, err) + receiptErr := txProc.executingFailedTransaction(tx, acntSnd, acntDst, err) if receiptErr != nil { return vmcommon.UserError, receiptErr } @@ -249,7 +249,7 @@ func (txProc *txProcessor) ProcessTransaction(tx *transaction.Transaction) (vmco return txProc.processRelayedTxV2(tx, acntSnd, acntDst) } - return vmcommon.UserError, txProc.executingFailedTransaction(tx, acntSnd, process.ErrWrongTransaction) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, acntSnd, acntDst, process.ErrWrongTransaction) } func (txProc *txProcessor) executeAfterFailedMoveBalanceTransaction( @@ -296,13 +296,14 @@ func (txProc *txProcessor) executeAfterFailedMoveBalanceTransaction( func (txProc *txProcessor) executingFailedTransaction( tx *transaction.Transaction, acntSnd state.UserAccountHandler, + acntDst state.UserAccountHandler, txError error, ) error { if check.IfNil(acntSnd) { return nil } - feePayer, isRelayedV3, err := txProc.getFeePayer(tx, acntSnd) + feePayer, isRelayedV3, err := txProc.getFeePayer(tx, acntSnd, acntDst) if err != nil { return err } @@ -486,7 +487,7 @@ func (txProc *txProcessor) processMoveBalance( isUserTxOfRelayed bool, ) error { - feePayer, _, err := txProc.getFeePayer(tx, acntSrc) + feePayer, _, err := txProc.getFeePayer(tx, acntSrc, acntDst) if err != nil { return nil } @@ -735,18 +736,18 @@ func (txProc *txProcessor) processRelayedTxV2( relayerAcnt, acntDst state.UserAccountHandler, ) (vmcommon.ReturnCode, error) { if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsV2Flag) { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxV2Disabled) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrRelayedTxV2Disabled) } if tx.GetValue().Cmp(big.NewInt(0)) != 0 { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxV2ZeroVal) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrRelayedTxV2ZeroVal) } _, args, err := txProc.argsParser.ParseCallData(string(tx.GetData())) if err != nil { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, err) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, err) } if len(args) != 4 { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrInvalidArguments) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrInvalidArguments) } userTx := makeUserTxFromRelayedTxV2Args(args) @@ -767,31 +768,31 @@ func (txProc *txProcessor) processRelayedTx( return 0, err } if len(args) != 1 { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrInvalidArguments) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrInvalidArguments) } if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsFlag) { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxDisabled) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrRelayedTxDisabled) } userTx := &transaction.Transaction{} err = txProc.signMarshalizer.Unmarshal(userTx, args[0]) if err != nil { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, err) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, err) } if !bytes.Equal(userTx.SndAddr, tx.RcvAddr) { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxBeneficiaryDoesNotMatchReceiver) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrRelayedTxBeneficiaryDoesNotMatchReceiver) } if userTx.Value.Cmp(tx.Value) < 0 { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxValueHigherThenUserTxValue) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrRelayedTxValueHigherThenUserTxValue) } if userTx.GasPrice != tx.GasPrice { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedGasPriceMissmatch) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrRelayedGasPriceMissmatch) } remainingGasLimit := tx.GasLimit - txProc.economicsFee.ComputeGasLimit(tx) if userTx.GasLimit != remainingGasLimit { - return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxGasLimitMissmatch) + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, acntDst, process.ErrRelayedTxGasLimitMissmatch) } return txProc.finishExecutionOfRelayedTx(relayerAcnt, acntDst, tx, userTx) From c8faf1a02b4c906821e9eda4f8cdbd062c2cb90e Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 13 Jan 2025 17:38:07 +0200 Subject: [PATCH 57/74] also fix for sc call --- .../relayedTx/relayedTx_test.go | 26 +++++++++++++------ .../smartContract/processorV2/processV2.go | 21 ++++++++++----- process/transaction/baseProcess.go | 2 +- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go index 37c17c602d8..b7426c63f5f 100644 --- a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -61,10 +61,12 @@ func TestRelayedV3WithChainSimulator(t *testing.T) { t.Run("intra shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 0)) t.Run("cross shard move balance, invalid gas", testRelayedV3MoveInvalidGasLimit(0, 1)) - t.Run("successful intra shard sc call with refunds, existing sender", testRelayedV3ScCall(0, 0, true)) - t.Run("successful intra shard sc call with refunds, new sender", testRelayedV3ScCall(0, 0, false)) - t.Run("successful cross shard sc call with refunds, existing sender", testRelayedV3ScCall(0, 1, true)) - t.Run("successful cross shard sc call with refunds, new sender", testRelayedV3ScCall(0, 1, false)) + t.Run("successful intra shard sc call with refunds, existing sender", testRelayedV3ScCall(0, 0, true, false)) + t.Run("successful intra shard sc call with refunds, existing sender, relayed by sender", testRelayedV3ScCall(0, 0, true, true)) + t.Run("successful intra shard sc call with refunds, new sender", testRelayedV3ScCall(0, 0, false, false)) + t.Run("successful cross shard sc call with refunds, existing sender", testRelayedV3ScCall(0, 1, true, false)) + t.Run("successful cross shard sc call with refunds, existing sender, relayed by sender", testRelayedV3ScCall(0, 1, true, true)) + t.Run("successful cross shard sc call with refunds, new sender", testRelayedV3ScCall(0, 1, false, false)) t.Run("intra shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 0)) t.Run("cross shard sc call, invalid gas", testRelayedV3ScCallInvalidGasLimit(0, 1)) t.Run("intra shard sc call, invalid method", testRelayedV3ScCallInvalidMethod(0, 0)) @@ -281,6 +283,7 @@ func testRelayedV3ScCall( relayerShard uint32, ownerShard uint32, existingSenderWithBalance bool, + relayedBySender bool, ) func(t *testing.T) { return func(t *testing.T) { if testing.Short() { @@ -299,8 +302,13 @@ func testRelayedV3ScCall( initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) relayer, err := cs.GenerateAndMintWalletAddress(relayerShard, initialBalance) require.NoError(t, err) + relayerInitialBalance := initialBalance sender, senderInitialBalance := prepareSender(t, cs, existingSenderWithBalance, relayerShard, initialBalance) + if relayedBySender { + relayer = sender + relayerInitialBalance = senderInitialBalance + } owner, err := cs.GenerateAndMintWalletAddress(ownerShard, initialBalance) require.NoError(t, err) @@ -338,12 +346,14 @@ func testRelayedV3ScCall( // check relayer balance relayerBalanceAfter := getBalance(t, cs, relayer) - relayerFee := big.NewInt(0).Sub(initialBalance, relayerBalanceAfter) + relayerFee := big.NewInt(0).Sub(relayerInitialBalance, relayerBalanceAfter) require.Equal(t, fee.String(), relayerFee.String()) - // check sender balance - senderBalanceAfter := getBalance(t, cs, sender) - require.Equal(t, senderInitialBalance.String(), senderBalanceAfter.String()) + // check sender balance, only if the tx was not relayed by sender + if !relayedBySender { + senderBalanceAfter := getBalance(t, cs, sender) + require.Equal(t, senderInitialBalance.String(), senderBalanceAfter.String()) + } // check owner balance _, feeDeploy, _ := computeTxGasAndFeeBasedOnRefund(resultDeploy, refundDeploy, false, false) diff --git a/process/smartContract/processorV2/processV2.go b/process/smartContract/processorV2/processV2.go index 31513ecea3b..1bd0f04caea 100644 --- a/process/smartContract/processorV2/processV2.go +++ b/process/smartContract/processorV2/processV2.go @@ -1943,14 +1943,16 @@ func (sc *scProcessor) processSCPayment(tx data.TransactionHandler, acntSnd stat } fee := sc.economicsFee.ComputeTxFee(tx) - err = feePayer.SubFromBalance(fee) - if err != nil { - return err - } + if !check.IfNil(feePayer) { + err = feePayer.SubFromBalance(fee) + if err != nil { + return err + } - err = sc.saveAccount(feePayer) - if err != nil { - return err + err = sc.saveAccount(feePayer) + if err != nil { + return err + } } err = acntSnd.SubFromBalance(tx.GetValue()) @@ -1971,6 +1973,11 @@ func (sc *scProcessor) getFeePayer(tx data.TransactionHandler, acntSnd state.Use return acntSnd, nil } + relayerIsSender := bytes.Compare(relayedTx.GetRelayerAddr(), tx.GetSndAddr()) == 0 + if relayerIsSender { + return acntSnd, nil // do not load the same account twice + } + account, err := sc.getAccountFromAddress(relayedTx.GetRelayerAddr()) if err != nil { return nil, err diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index aa35237baaa..4896e1e3c10 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -248,7 +248,7 @@ func (txProc *baseTxProcessor) getFeePayer( relayerIsSender := bytes.Compare(tx.RelayerAddr, tx.SndAddr) == 0 if relayerIsSender { - return destinationAccount, true, nil // do not load the same account twice + return senderAccount, true, nil // do not load the same account twice } relayerIsDestination := bytes.Compare(tx.RelayerAddr, tx.RcvAddr) == 0 From 55ac0c98f5d12057713c5cc00e072255fcc7546b Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Mon, 13 Jan 2025 17:45:52 +0200 Subject: [PATCH 58/74] linter fixes --- process/smartContract/processorV2/processV2.go | 2 +- process/transaction/baseProcess.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/process/smartContract/processorV2/processV2.go b/process/smartContract/processorV2/processV2.go index 1bd0f04caea..e0d88916a52 100644 --- a/process/smartContract/processorV2/processV2.go +++ b/process/smartContract/processorV2/processV2.go @@ -1973,7 +1973,7 @@ func (sc *scProcessor) getFeePayer(tx data.TransactionHandler, acntSnd state.Use return acntSnd, nil } - relayerIsSender := bytes.Compare(relayedTx.GetRelayerAddr(), tx.GetSndAddr()) == 0 + relayerIsSender := bytes.Equal(relayedTx.GetRelayerAddr(), tx.GetSndAddr()) if relayerIsSender { return acntSnd, nil // do not load the same account twice } diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 4896e1e3c10..0433f8a0f50 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -246,12 +246,12 @@ func (txProc *baseTxProcessor) getFeePayer( return senderAccount, false, nil } - relayerIsSender := bytes.Compare(tx.RelayerAddr, tx.SndAddr) == 0 + relayerIsSender := bytes.Equal(tx.RelayerAddr, tx.SndAddr) if relayerIsSender { return senderAccount, true, nil // do not load the same account twice } - relayerIsDestination := bytes.Compare(tx.RelayerAddr, tx.RcvAddr) == 0 + relayerIsDestination := bytes.Equal(tx.RelayerAddr, tx.RcvAddr) if relayerIsDestination { return destinationAccount, true, nil // do not load the same account twice } From e66a20a8bf2fc5b126b763f8757a0e39adccca3b Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Tue, 14 Jan 2025 12:57:04 +0200 Subject: [PATCH 59/74] 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()) +} From 0de46063c4a64b5cc73cfa41ebecde559b637bce Mon Sep 17 00:00:00 2001 From: miiu Date: Tue, 14 Jan 2025 15:25:18 +0200 Subject: [PATCH 60/74] fix chain simulator --- node/chainSimulator/chainSimulator.go | 3 +++ .../components/syncedMessenger.go | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/node/chainSimulator/chainSimulator.go b/node/chainSimulator/chainSimulator.go index 742d040c8c8..0d3d4d25e6a 100644 --- a/node/chainSimulator/chainSimulator.go +++ b/node/chainSimulator/chainSimulator.go @@ -298,15 +298,18 @@ func (s *simulator) incrementRoundOnAllValidators() { // ForceChangeOfEpoch will force the change of current epoch // This method will call the epoch change trigger and generate block till a new epoch is reached func (s *simulator) ForceChangeOfEpoch() error { + s.mutex.Lock() log.Info("force change of epoch") for shardID, node := range s.nodes { err := node.ForceChangeOfEpoch() if err != nil { + s.mutex.Unlock() return fmt.Errorf("force change of epoch shardID-%d: error-%w", shardID, err) } } epoch := s.nodes[core.MetachainShardId].GetProcessComponents().EpochStartTrigger().Epoch() + s.mutex.Unlock() return s.GenerateBlocksUntilEpochIsReached(int32(epoch + 1)) } diff --git a/node/chainSimulator/components/syncedMessenger.go b/node/chainSimulator/components/syncedMessenger.go index cc437d02038..09786c45842 100644 --- a/node/chainSimulator/components/syncedMessenger.go +++ b/node/chainSimulator/components/syncedMessenger.go @@ -80,13 +80,21 @@ func (messenger *syncedMessenger) receive(fromConnectedPeer core.PeerID, message handlers := messenger.topics[message.Topic()] messenger.mutOperation.RUnlock() + wg := &sync.WaitGroup{} + wg.Add(len(handlers)) for _, handler := range handlers { - err := handler.ProcessReceivedMessage(message, fromConnectedPeer, messenger) - if err != nil { - log.Trace("received message syncedMessenger", - "error", err, "topic", message.Topic(), "from connected peer", fromConnectedPeer.Pretty()) - } + // this is needed to process all received messages on multiple go routines + go func(proc p2p.MessageProcessor, p2pMessage p2p.MessageP2P, peer core.PeerID, localWG *sync.WaitGroup) { + err := proc.ProcessReceivedMessage(p2pMessage, peer, messenger) + if err != nil { + log.Trace("received message syncedMessenger", "error", err, "topic", p2pMessage.Topic(), "from connected peer", peer.Pretty()) + } + + localWG.Done() + }(handler, message, fromConnectedPeer, wg) } + + wg.Wait() } // ProcessReceivedMessage does nothing and returns nil From 054aa1e467e9b18c783a1af5c7a69136c9100484 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Wed, 15 Jan 2025 12:43:29 +0200 Subject: [PATCH 61/74] count all refunds if more than one scr exists --- .../transactionAPI/gasUsedAndFeeProcessor.go | 8 +- .../gasUsedAndFeeProcessor_test.go | 61 ++++++- .../relayedV3WithMultipleRefunds.json | 159 ++++++++++++++++++ 3 files changed, 223 insertions(+), 5 deletions(-) create mode 100644 node/external/transactionAPI/testData/relayedV3WithMultipleRefunds.json diff --git a/node/external/transactionAPI/gasUsedAndFeeProcessor.go b/node/external/transactionAPI/gasUsedAndFeeProcessor.go index 1e50b551d14..7bbb197c69f 100644 --- a/node/external/transactionAPI/gasUsedAndFeeProcessor.go +++ b/node/external/transactionAPI/gasUsedAndFeeProcessor.go @@ -60,6 +60,7 @@ func (gfp *gasUsedAndFeeProcessor) computeAndAttachGasUsedAndFee(tx *transaction isRelayedV3 := common.IsValidRelayedTxV3(tx.Tx) hasRefundForSender := false + totalRefunds := big.NewInt(0) for _, scr := range tx.SmartContractResults { if !scr.IsRefund { continue @@ -71,9 +72,12 @@ func (gfp *gasUsedAndFeeProcessor) computeAndAttachGasUsedAndFee(tx *transaction continue } - gfp.setGasUsedAndFeeBaseOnRefundValue(tx, userTx, scr.Value) hasRefundForSender = true - break + totalRefunds.Add(totalRefunds, scr.Value) + } + + if totalRefunds.Cmp(big.NewInt(0)) > 0 { + gfp.setGasUsedAndFeeBaseOnRefundValue(tx, userTx, totalRefunds) } gfp.prepareTxWithResultsBasedOnLogs(tx, userTx, hasRefundForSender) diff --git a/node/external/transactionAPI/gasUsedAndFeeProcessor_test.go b/node/external/transactionAPI/gasUsedAndFeeProcessor_test.go index 8c5c80826c0..b81ad1e03b9 100644 --- a/node/external/transactionAPI/gasUsedAndFeeProcessor_test.go +++ b/node/external/transactionAPI/gasUsedAndFeeProcessor_test.go @@ -1,6 +1,7 @@ package transactionAPI import ( + "encoding/hex" "math/big" "testing" @@ -257,13 +258,14 @@ func TestNFTTransferWithScCall(t *testing.T) { func TestComputeAndAttachGasUsedAndFeeTransactionWithMultipleScrWithRefund(t *testing.T) { t.Parallel() - feeComp, _ := fee.NewFeeComputer(createEconomicsData(&enableEpochsHandlerMock.EnableEpochsHandlerStub{ + eeh := &enableEpochsHandlerMock.EnableEpochsHandlerStub{ IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { return flag == common.GasPriceModifierFlag || flag == common.PenalizedTooMuchGasFlag || flag == common.FixRelayedBaseCostFlag }, - })) + } + feeComp, _ := fee.NewFeeComputer(createEconomicsData(eeh)) computer := fee.NewTestFeeComputer(feeComp) gasUsedAndFeeProc := newGasUsedAndFeeProcessor( @@ -271,7 +273,7 @@ func TestComputeAndAttachGasUsedAndFeeTransactionWithMultipleScrWithRefund(t *te pubKeyConverter, &testscommon.ArgumentParserMock{}, &testscommon.MarshallerStub{}, - enableEpochsHandlerMock.NewEnableEpochsHandlerStub(), + eeh, ) txWithSRefundSCR := &transaction.ApiTransactionResult{} @@ -394,3 +396,56 @@ func TestComputeAndAttachGasUsedAndFeeRelayedV1CreateNewDelegationContractWithRe require.Equal(t, "1878500000000000", txWithSRefundSCR.Fee) require.Equal(t, "2177505000000000", txWithSRefundSCR.InitiallyPaidFee) } + +func TestComputeAndAttachGasUsedAndFeeRelayedV3WithMultipleRefunds(t *testing.T) { + t.Parallel() + + eeh := &enableEpochsHandlerMock.EnableEpochsHandlerStub{ + IsFlagEnabledInEpochCalled: func(flag core.EnableEpochFlag, epoch uint32) bool { + return flag == common.GasPriceModifierFlag || + flag == common.PenalizedTooMuchGasFlag || + flag == common.FixRelayedBaseCostFlag || + flag == common.RelayedTransactionsV3Flag + }, + } + feeComp, _ := fee.NewFeeComputer(createEconomicsData(eeh)) + computer := fee.NewTestFeeComputer(feeComp) + + gasUsedAndFeeProc := newGasUsedAndFeeProcessor( + computer, + pubKeyConverter, + &testscommon.ArgumentParserMock{}, + &testscommon.MarshallerStub{}, + eeh, + ) + + txWithRefunds := &transaction.ApiTransactionResult{} + err := core.LoadJsonFile(txWithRefunds, "testData/relayedV3WithMultipleRefunds.json") + require.NoError(t, err) + + txWithRefunds.Fee = "" + txWithRefunds.GasUsed = 0 + + snd, _ := pubKeyConverter.Decode(txWithRefunds.Sender) + rcv, _ := pubKeyConverter.Decode(txWithRefunds.Receiver) + rel, _ := pubKeyConverter.Decode(txWithRefunds.RelayerAddress) + val, _ := big.NewInt(0).SetString(txWithRefunds.Value, 10) + sig, _ := hex.DecodeString(txWithRefunds.Signature) + relayerSig, _ := hex.DecodeString(txWithRefunds.RelayerSignature) + txWithRefunds.Tx = &transaction.Transaction{ + Nonce: txWithRefunds.Nonce, + Value: val, + RcvAddr: rcv, + SndAddr: snd, + RelayerAddr: rel, + GasPrice: txWithRefunds.GasPrice, + GasLimit: txWithRefunds.GasLimit, + Data: txWithRefunds.Data, + Signature: sig, + RelayerSignature: relayerSig, + } + + gasUsedAndFeeProc.computeAndAttachGasUsedAndFee(txWithRefunds) + require.Equal(t, uint64(4220447), txWithRefunds.GasUsed) + require.Equal(t, "289704470000000", txWithRefunds.Fee) +} diff --git a/node/external/transactionAPI/testData/relayedV3WithMultipleRefunds.json b/node/external/transactionAPI/testData/relayedV3WithMultipleRefunds.json new file mode 100644 index 00000000000..26d3005c9d8 --- /dev/null +++ b/node/external/transactionAPI/testData/relayedV3WithMultipleRefunds.json @@ -0,0 +1,159 @@ +{ + "type": "normal", + "processingTypeOnSource": "SCInvoking", + "processingTypeOnDestination": "SCInvoking", + "value": "0", + "receiver": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "sender": "erd1at9keal0jfhamc67ulq4csmchh33eek87yf5hhzcvlw8e5qlx8zq5hjwjl", + "gasPrice": 1000000000, + "gasLimit": 15000000, + "gasUsed": 14536537, + "data": "Zm9yd2FyZEAwMUAwMDAwMDAwMDAwMDAwMDAwMDUwMGMxMzVlMjc2NmM3MDcyMTA2ZjIzYjAzNWIzODUxZDYzZDdmNjIxYzY5NmRhQDAwQDYxNjQ2NDQwMzAzMUAwMDdmZmZmZg==", + "signature": "645d88221a50bbf5173a9a46a70308f0c272d9b4701fe935ae2565147a32b484c4ea695bcaa102a299877f7e7699bb7990c491a601ae636851f5485dd59fe10b", + "smartContractResults": [ + { + "hash": "16b05474872d51840ca9270d8790fc65d50f5d076bb491388344f5095f6f0df0", + "nonce": 24, + "value": 4634630000000, + "receiver": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "sender": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "prevTxHash": "8fe5133b33d315392006d11dbeb2ea9c0d5f1eb0856aaf3044e9f55118656843", + "originalTxHash": "8fe5133b33d315392006d11dbeb2ea9c0d5f1eb0856aaf3044e9f55118656843", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "returnMessage": "gas refund for relayer", + "originalSender": "erd1at9keal0jfhamc67ulq4csmchh33eek87yf5hhzcvlw8e5qlx8zq5hjwjl", + "logs": { + "address": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "events": [ + { + "address": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "identifier": "completedTxEvent", + "topics": [ + "j+UTOzPTFTkgBtEdvrLqnA1fHrCFaq8wROn1URhlaEM=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer", + "isRefund": true + }, + { + "hash": "9090261203cf20e3b51e4c921ce27fa595fcca3f37c83543c7a4a57733139f4d", + "nonce": 1, + "value": 103160900000000, + "receiver": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "sender": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "prevTxHash": "a74d26756c58c522637b3c73b299828901533c93d5ccd75d6ec6a3410755d3e4", + "originalTxHash": "8fe5133b33d315392006d11dbeb2ea9c0d5f1eb0856aaf3044e9f55118656843", + "gasLimit": 0, + "gasPrice": 1000000000, + "callType": 0, + "returnMessage": "gas refund for relayer", + "originalSender": "erd1at9keal0jfhamc67ulq4csmchh33eek87yf5hhzcvlw8e5qlx8zq5hjwjl", + "logs": { + "address": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "events": [ + { + "address": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "identifier": "completedTxEvent", + "topics": [ + "p00mdWxYxSJjezxzspmCiQFTPJPVzNddbsajQQdV0+Q=" + ], + "data": null, + "additionalData": null + } + ] + }, + "operation": "transfer", + "isRefund": true + }, + { + "hash": "5fb1c0d5d04b80331839de417523dff45a1be9489d4d84f9c5535314e0542525", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqcy67yanvwpepqmerkq6m8pgav0tlvgwxjmdq4hukxw", + "sender": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "relayerAddress": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "relayedValue": 0, + "data": "add@01@21fdaf01f965469c1bebf13c3c49a18f0dde9d8e380cec78cea065246fabb2d9@8fe5133b33d315392006d11dbeb2ea9c0d5f1eb0856aaf3044e9f55118656843@4185d4", + "prevTxHash": "8fe5133b33d315392006d11dbeb2ea9c0d5f1eb0856aaf3044e9f55118656843", + "originalTxHash": "8fe5133b33d315392006d11dbeb2ea9c0d5f1eb0856aaf3044e9f55118656843", + "gasLimit": 12682707, + "gasPrice": 1000000000, + "callType": 1, + "originalSender": "erd1at9keal0jfhamc67ulq4csmchh33eek87yf5hhzcvlw8e5qlx8zq5hjwjl", + "operation": "transfer", + "function": "add" + }, + { + "hash": "a74d26756c58c522637b3c73b299828901533c93d5ccd75d6ec6a3410755d3e4", + "nonce": 0, + "value": 0, + "receiver": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "sender": "erd1qqqqqqqqqqqqqpgqcy67yanvwpepqmerkq6m8pgav0tlvgwxjmdq4hukxw", + "relayerAddress": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "relayedValue": 0, + "data": "@00@95a836710c0857f995e670bf3aa944263473534c8c5f4b7959c938045f62023b@21fdaf01f965469c1bebf13c3c49a18f0dde9d8e380cec78cea065246fabb2d9@8fe5133b33d315392006d11dbeb2ea9c0d5f1eb0856aaf3044e9f55118656843@00", + "prevTxHash": "5fb1c0d5d04b80331839de417523dff45a1be9489d4d84f9c5535314e0542525", + "originalTxHash": "8fe5133b33d315392006d11dbeb2ea9c0d5f1eb0856aaf3044e9f55118656843", + "gasLimit": 11512215, + "gasPrice": 1000000000, + "callType": 2, + "originalSender": "erd1at9keal0jfhamc67ulq4csmchh33eek87yf5hhzcvlw8e5qlx8zq5hjwjl", + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "identifier": "writeLog", + "topics": [ + "AAAAAAAAAAAFAO2OJalO+oN6rg5ZMRLPuwG0SHVQaeE=" + ], + "data": "QDZmNmJAMDBjYTc3YmFjNEAwNjBjY2U1NQ==", + "additionalData": [ + "QDZmNmJAMDBjYTc3YmFjNEAwNjBjY2U1NQ==" + ] + } + ] + }, + "operation": "transfer" + } + ], + "logs": { + "address": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "events": [ + { + "address": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "identifier": "transferValueOnly", + "topics": [ + "", + "AAAAAAAAAAAFAME14nZscHIQbyOwNbOFHWPX9iHGlto=" + ], + "data": "QXN5bmNDYWxs", + "additionalData": [ + "QXN5bmNDYWxs", + "YWRk", + "AQ==" + ] + }, + { + "address": "erd1qqqqqqqqqqqqqpgqak8zt22wl2ph4tswtyc39namqx6ysa2sd8ss4xmlj3", + "identifier": "writeLog", + "topics": [ + "6sts9++Sb93jXufBXEN4veMc5sfxE0vcWGfcfNAfMcQ=" + ], + "data": "QDZmNmI=", + "additionalData": [ + "QDZmNmI=" + ] + } + ] + }, + "isRelayed": true, + "relayerAddress": "erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx", + "relayerSignature": "dfb60f7d13c024335ec9586b7af579ed47da002a23313272069711bceebddc2d9216b7cc1395c37a1c328288fcc774d5cbeb610db2900f76647307d35a593e08" +} From edf2be28e449f561825a7d09dc6c7230773d2286 Mon Sep 17 00:00:00 2001 From: miiu Date: Wed, 15 Jan 2025 15:28:30 +0200 Subject: [PATCH 62/74] treat multiple scrs outport driver --- genesis/process/disabled/feeHandler.go | 5 +++++ go.mod | 4 ++-- go.sum | 8 ++++---- outport/mock/economicsDataMock.go | 5 +++++ outport/process/interface.go | 1 + outport/process/transactionsfee/interface.go | 1 + .../transactionsFeeProcessor.go | 20 ++++++++++++++++--- process/economics/economicsData.go | 9 +++++++++ process/interface.go | 1 + .../economicsDataHandlerStub.go | 10 ++++++++++ .../economicsmocks/economicsHandlerMock.go | 5 +++++ 11 files changed, 60 insertions(+), 9 deletions(-) diff --git a/genesis/process/disabled/feeHandler.go b/genesis/process/disabled/feeHandler.go index 1fc34bbc2b5..0b3051cf845 100644 --- a/genesis/process/disabled/feeHandler.go +++ b/genesis/process/disabled/feeHandler.go @@ -12,6 +12,11 @@ import ( type FeeHandler struct { } +// ComputeGasUnitsFromRefundValue return 0 +func (fh *FeeHandler) ComputeGasUnitsFromRefundValue(_ data.TransactionWithFeeHandler, _ *big.Int, _ uint32) uint64 { + return 0 +} + // GasPriceModifier returns 1.0 func (fh *FeeHandler) GasPriceModifier() float64 { return 1.0 diff --git a/go.mod b/go.mod index 58d4c45bd34..a8f83c0a0a8 100644 --- a/go.mod +++ b/go.mod @@ -15,9 +15,9 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.1 - github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8 + github.com/multiversx/mx-chain-core-go v1.2.24-0.20250115104420-0580ffeedb71 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250109151711-ceaca49de8e1 + github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250115131432-0d2cff53280d github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 github.com/multiversx/mx-chain-storage-go v1.0.19-0.20250109152325-cf81acfd19bd diff --git a/go.sum b/go.sum index b361ab5e311..a742ed9c43b 100644 --- a/go.sum +++ b/go.sum @@ -387,12 +387,12 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.1 h1:y4DoQeQOJTaSUsRzczQFazf8JYQmInddypApqA3AkwM= github.com/multiversx/mx-chain-communication-go v1.1.1/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8 h1:0ivlwcl+dKK7BTVngm1uNM2aDneaXK2rhS0HVeBkvYg= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20250109151319-81a62c045af8/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20250115104420-0580ffeedb71 h1:UZODeK+VpQxtLKaRU0iubQ9Jm1HIobFEXIf4N4Nvkwg= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20250115104420-0580ffeedb71/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250109151711-ceaca49de8e1 h1:rHZS2Nw7M8thrtdN+s8qIf7TN9pi79r8n9J2gs0MaCc= -github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250109151711-ceaca49de8e1/go.mod h1:NMNBlIO60Wc026iSDp/eqnb0YmoiH05pEuphkdlW43k= +github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250115131432-0d2cff53280d h1:sRZqFVEbQHmaL/Hfy60FPgJn6vkpgcdjbNH4SOzM5Ds= +github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250115131432-0d2cff53280d/go.mod h1:GinQIoGBZbXLoyxgBbC76LO4OkPWtIV1tLsYp0Fj0mM= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= diff --git a/outport/mock/economicsDataMock.go b/outport/mock/economicsDataMock.go index cf9cf4dc848..36da6e9a7d4 100644 --- a/outport/mock/economicsDataMock.go +++ b/outport/mock/economicsDataMock.go @@ -20,6 +20,11 @@ const ( type EconomicsHandlerMock struct { } +// ComputeGasUnitsFromRefundValue - +func (e *EconomicsHandlerMock) ComputeGasUnitsFromRefundValue(_ coreData.TransactionWithFeeHandler, _ *big.Int, _ uint32) uint64 { + return 0 +} + // MaxGasLimitPerBlock - func (e *EconomicsHandlerMock) MaxGasLimitPerBlock(_ uint32) uint64 { return 0 diff --git a/outport/process/interface.go b/outport/process/interface.go index bec97f362b3..0c8b332aa31 100644 --- a/outport/process/interface.go +++ b/outport/process/interface.go @@ -32,6 +32,7 @@ type GasConsumedProvider interface { // EconomicsDataHandler defines the functionality needed for economics data type EconomicsDataHandler interface { + ComputeGasUnitsFromRefundValue(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) uint64 ComputeGasUsedAndFeeBasedOnRefundValue(tx data.TransactionWithFeeHandler, refundValue *big.Int) (uint64, *big.Int) ComputeTxFeeBasedOnGasUsed(tx data.TransactionWithFeeHandler, gasUsed uint64) *big.Int ComputeTxFee(tx data.TransactionWithFeeHandler) *big.Int diff --git a/outport/process/transactionsfee/interface.go b/outport/process/transactionsfee/interface.go index 53042467442..551ee59d1e2 100644 --- a/outport/process/transactionsfee/interface.go +++ b/outport/process/transactionsfee/interface.go @@ -11,6 +11,7 @@ import ( // FeesProcessorHandler defines the interface for the transaction fees processor type FeesProcessorHandler interface { ComputeGasUsedAndFeeBasedOnRefundValue(tx data.TransactionWithFeeHandler, refundValue *big.Int) (uint64, *big.Int) + ComputeGasUnitsFromRefundValue(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) uint64 ComputeTxFeeBasedOnGasUsed(tx data.TransactionWithFeeHandler, gasUsed uint64) *big.Int ComputeTxFee(tx data.TransactionWithFeeHandler) *big.Int ComputeGasLimit(tx data.TransactionWithFeeHandler) uint64 diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index e7aeece280e..694b0824116 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -103,7 +103,7 @@ func (tep *transactionsFeeProcessor) PutFeeAndGasUsed(pool *outportcore.Transact txsWithResultsMap := prepareTransactionsAndScrs(pool) tep.prepareNormalTxs(txsWithResultsMap, epoch) - return tep.prepareScrsNoTx(txsWithResultsMap) + return tep.prepareScrsNoTx(txsWithResultsMap, epoch) } func (tep *transactionsFeeProcessor) prepareInvalidTxs(pool *outportcore.TransactionPool) { @@ -155,6 +155,7 @@ func (tep *transactionsFeeProcessor) prepareTxWithResults( epoch uint32, ) { hasRefund := false + totalRefunds := big.NewInt(0) for _, scrHandler := range txWithResults.scrs { scr, ok := scrHandler.GetTxHandler().(*smartContractResult.SmartContractResult) if !ok { @@ -162,12 +163,17 @@ func (tep *transactionsFeeProcessor) prepareTxWithResults( } if isSCRForSenderWithRefund(scr, txHashHex, txWithResults.GetTxHandler()) || isRefundForRelayed(scr, txWithResults.GetTxHandler()) { - tep.setGasUsedAndFeeBasedOnRefundValue(txWithResults, userTx, scr.Value, epoch) hasRefund = true + totalRefunds.Add(totalRefunds, scr.Value) break } } + if totalRefunds.Cmp(big.NewInt(0)) > 0 { + tep.setGasUsedAndFeeBasedOnRefundValue(txWithResults, userTx, totalRefunds, epoch) + + } + tep.prepareTxWithResultsBasedOnLogs(txHashHex, txWithResults, userTx, hasRefund, epoch) } @@ -293,7 +299,7 @@ func (tep *transactionsFeeProcessor) setGasUsedAndFeeBasedOnRefundValue( txWithResults.GetFeeInfo().SetFee(fee) } -func (tep *transactionsFeeProcessor) prepareScrsNoTx(transactionsAndScrs *transactionsAndScrsHolder) error { +func (tep *transactionsFeeProcessor) prepareScrsNoTx(transactionsAndScrs *transactionsAndScrsHolder, epoch uint32) error { for _, scrHandler := range transactionsAndScrs.scrsNoTx { scr, ok := scrHandler.GetTxHandler().(*smartContractResult.SmartContractResult) if !ok { @@ -326,11 +332,19 @@ func (tep *transactionsFeeProcessor) prepareScrsNoTx(transactionsAndScrs *transa userTx := tep.getUserTxOfRelayed(txFromStorage) if check.IfNil(userTx) { + // relayed v3 and other txs + if isRelayedV3 { + gasUnits := tep.txFeeCalculator.ComputeGasUnitsFromRefundValue(txFromStorage, scr.Value, epoch) + scrHandler.GetFeeInfo().SetGasRefunded(gasUnits) + scrHandler.GetFeeInfo().SetFee(scr.Value) + } + gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(txFromStorage, scr.Value) scrHandler.GetFeeInfo().SetGasUsed(gasUsed) scrHandler.GetFeeInfo().SetFee(fee) } else { + // relayed v1 and v2 gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(userTx, scr.Value) gasUsedRelayedTx := tep.txFeeCalculator.ComputeGasLimit(txFromStorage) diff --git a/process/economics/economicsData.go b/process/economics/economicsData.go index dfce9d5a6f6..84e161ef86f 100644 --- a/process/economics/economicsData.go +++ b/process/economics/economicsData.go @@ -579,6 +579,15 @@ func (ed *economicsData) ComputeGasLimitBasedOnBalance(tx data.TransactionWithFe return ed.ComputeGasLimitBasedOnBalanceInEpoch(tx, balance, currentEpoch) } +// ComputeGasUnitsFromRefundValue will compute the gas unit based on the refund value +func (ed *economicsData) ComputeGasUnitsFromRefundValue(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) uint64 { + gasPrice := ed.GasPriceForProcessingInEpoch(tx, epoch) + refund := big.NewInt(0).Set(refundValue) + gasUnits := refund.Div(refund, big.NewInt(int64(gasPrice))) + + return gasUnits.Uint64() +} + // ComputeGasLimitBasedOnBalanceInEpoch will compute gas limit for the given transaction based on the balance in a specific epoch func (ed *economicsData) ComputeGasLimitBasedOnBalanceInEpoch(tx data.TransactionWithFeeHandler, balance *big.Int, epoch uint32) (uint64, error) { balanceWithoutTransferValue := big.NewInt(0).Sub(balance, tx.GetValue()) diff --git a/process/interface.go b/process/interface.go index 6638c680897..e5800a54796 100644 --- a/process/interface.go +++ b/process/interface.go @@ -696,6 +696,7 @@ type feeHandler interface { ComputeGasUsedAndFeeBasedOnRefundValue(tx data.TransactionWithFeeHandler, refundValue *big.Int) (uint64, *big.Int) ComputeTxFeeBasedOnGasUsed(tx data.TransactionWithFeeHandler, gasUsed uint64) *big.Int ComputeGasLimitBasedOnBalance(tx data.TransactionWithFeeHandler, balance *big.Int) (uint64, error) + ComputeGasUnitsFromRefundValue(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) uint64 ComputeTxFeeInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) *big.Int ComputeGasLimitInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) uint64 ComputeGasUsedAndFeeBasedOnRefundValueInEpoch(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) (uint64, *big.Int) diff --git a/testscommon/economicsmocks/economicsDataHandlerStub.go b/testscommon/economicsmocks/economicsDataHandlerStub.go index 4ef784c596f..a69206b12e6 100644 --- a/testscommon/economicsmocks/economicsDataHandlerStub.go +++ b/testscommon/economicsmocks/economicsDataHandlerStub.go @@ -47,6 +47,16 @@ type EconomicsHandlerStub struct { ComputeGasUsedAndFeeBasedOnRefundValueInEpochCalled func(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) (uint64, *big.Int) ComputeTxFeeBasedOnGasUsedInEpochCalled func(tx data.TransactionWithFeeHandler, gasUsed uint64, epoch uint32) *big.Int ComputeMoveBalanceFeeInEpochCalled func(tx data.TransactionWithFeeHandler, epoch uint32) *big.Int + ComputeGasUnitsFromRefundValueCalled func(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) uint64 +} + +// ComputeGasUnitsFromRefundValue - +func (e *EconomicsHandlerStub) ComputeGasUnitsFromRefundValue(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) uint64 { + if e.ComputeGasUnitsFromRefundValueCalled != nil { + return e.ComputeGasUnitsFromRefundValueCalled(tx, refundValue, epoch) + } + + return 0 } // ComputeFeeForProcessing - diff --git a/testscommon/economicsmocks/economicsHandlerMock.go b/testscommon/economicsmocks/economicsHandlerMock.go index b1e4321f389..304e86e37d2 100644 --- a/testscommon/economicsmocks/economicsHandlerMock.go +++ b/testscommon/economicsmocks/economicsHandlerMock.go @@ -49,6 +49,11 @@ type EconomicsHandlerMock struct { ComputeTxFeeBasedOnGasUsedInEpochCalled func(tx data.TransactionWithFeeHandler, gasUsed uint64, epoch uint32) *big.Int } +// ComputeGasUnitsFromRefundValue - +func (ehm *EconomicsHandlerMock) ComputeGasUnitsFromRefundValue(_ data.TransactionWithFeeHandler, _ *big.Int, _ uint32) uint64 { + return 0 +} + // LeaderPercentage - func (ehm *EconomicsHandlerMock) LeaderPercentage() float64 { return ehm.LeaderPercentageCalled() From e6703ecae9d690a9f80a69583626f2289d0ee63a Mon Sep 17 00:00:00 2001 From: miiu Date: Wed, 15 Jan 2025 15:36:23 +0200 Subject: [PATCH 63/74] small fix --- outport/process/transactionsfee/transactionsFeeProcessor.go | 1 - 1 file changed, 1 deletion(-) diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index 694b0824116..9fae644b1b0 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -165,7 +165,6 @@ func (tep *transactionsFeeProcessor) prepareTxWithResults( if isSCRForSenderWithRefund(scr, txHashHex, txWithResults.GetTxHandler()) || isRefundForRelayed(scr, txWithResults.GetTxHandler()) { hasRefund = true totalRefunds.Add(totalRefunds, scr.Value) - break } } From ee6ae2150c49e7a0f66ac7134508965523664478 Mon Sep 17 00:00:00 2001 From: miiu Date: Thu, 16 Jan 2025 10:26:31 +0200 Subject: [PATCH 64/74] had refund --- go.mod | 4 ++-- go.sum | 8 ++++---- .../process/transactionsfee/transactionsFeeProcessor.go | 2 ++ .../transactionsfee/transactionsFeeProcessor_test.go | 1 + 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index a8f83c0a0a8..02d7fe91bce 100644 --- a/go.mod +++ b/go.mod @@ -15,9 +15,9 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.1 - github.com/multiversx/mx-chain-core-go v1.2.24-0.20250115104420-0580ffeedb71 + github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250115131432-0d2cff53280d + github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250116081916-62f5c3451bed github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 github.com/multiversx/mx-chain-storage-go v1.0.19-0.20250109152325-cf81acfd19bd diff --git a/go.sum b/go.sum index a742ed9c43b..9281063733f 100644 --- a/go.sum +++ b/go.sum @@ -387,12 +387,12 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.1 h1:y4DoQeQOJTaSUsRzczQFazf8JYQmInddypApqA3AkwM= github.com/multiversx/mx-chain-communication-go v1.1.1/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20250115104420-0580ffeedb71 h1:UZODeK+VpQxtLKaRU0iubQ9Jm1HIobFEXIf4N4Nvkwg= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20250115104420-0580ffeedb71/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4 h1:rWYFL38q5cbo5MtdW2DvAp4+WMaVp8e7gBjmrLQ9SCY= +github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250115131432-0d2cff53280d h1:sRZqFVEbQHmaL/Hfy60FPgJn6vkpgcdjbNH4SOzM5Ds= -github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250115131432-0d2cff53280d/go.mod h1:GinQIoGBZbXLoyxgBbC76LO4OkPWtIV1tLsYp0Fj0mM= +github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250116081916-62f5c3451bed h1:UOZ6c1MOANM8RLyYw/okKGwnowF+dRbzwPpzr11zaZ0= +github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250116081916-62f5c3451bed/go.mod h1:Q6qug6OodSOzwZuMrvrfDcMmPB2FcP7CKr9rqsn0OHQ= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index 9fae644b1b0..35bf65ec5de 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -279,6 +279,8 @@ func (tep *transactionsFeeProcessor) setGasUsedAndFeeBasedOnRefundValue( refund *big.Int, epoch uint32, ) { + txWithResults.GetFeeInfo().SetHadRefund() + isValidUserTxAfterBaseCostActivation := !check.IfNil(userTx) && tep.enableEpochsHandler.IsFlagEnabledInEpoch(common.FixRelayedBaseCostFlag, epoch) if isValidUserTxAfterBaseCostActivation && !common.IsValidRelayedTxV3(txWithResults.GetTxHandler()) { gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(userTx, refund) diff --git a/outport/process/transactionsfee/transactionsFeeProcessor_test.go b/outport/process/transactionsfee/transactionsFeeProcessor_test.go index 9e2d45e6b30..2aa399a26fe 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor_test.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor_test.go @@ -673,4 +673,5 @@ func TestPutFeeAndGasUsedRelayedTxV3(t *testing.T) { 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()) + require.True(t, initialTx.GetFeeInfo().HadRefund) } From ae1e852c73c06d141f1cafebaf254ddeb2638948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 16 Jan 2025 10:35:42 +0200 Subject: [PATCH 65/74] Additional test: TestMempoolWithChainSimulator_Selection_WhenInsufficientBalanceForFee_WithRelayedV3. --- .../chainSimulator/mempool/mempool_test.go | 104 ++++++++++++++++++ .../chainSimulator/mempool/testutils_test.go | 12 ++ 2 files changed, 116 insertions(+) diff --git a/integrationTests/chainSimulator/mempool/mempool_test.go b/integrationTests/chainSimulator/mempool/mempool_test.go index 1aad3d051a9..9be46fb6061 100644 --- a/integrationTests/chainSimulator/mempool/mempool_test.go +++ b/integrationTests/chainSimulator/mempool/mempool_test.go @@ -1,6 +1,7 @@ package mempool import ( + "math/big" "testing" "time" @@ -67,6 +68,109 @@ func TestMempoolWithChainSimulator_Selection(t *testing.T) { require.Equal(t, 50_000*(30_000-27_756), int(gas)) } +func TestMempoolWithChainSimulator_Selection_WhenInsufficientBalanceForFee_WithRelayedV3(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + numSenders := 3 + shard := 0 + + simulator := startChainSimulator(t, func(cfg *config.Configs) {}) + defer simulator.Close() + + err := simulator.GenerateBlocksUntilEpochIsReached(2) + require.NoError(t, err) + + participants := createParticipants(t, simulator, numSenders) + noncesTracker := newNoncesTracker() + + alice := participants.sendersByShard[shard][0] + bob := participants.sendersByShard[shard][1] + carol := participants.sendersByShard[shard][2] + relayer := participants.relayerByShard[shard] + receiver := participants.receiverByShard[shard] + + transactions := make([]*transaction.Transaction, 0) + + // Consume most of relayer's balance. Keep an amount that is enough for the fee of two simple transfer transactions. + currentBalance := int64(1000000000000000000) + feeForTransfer := int64(50_000 * 1_000_000_004) + feeForRelayingTransactionsOfAliceAndBob := int64(100_000*1_000_000_003 + 100_000*1_000_000_002) + + transactions = append(transactions, &transaction.Transaction{ + Nonce: noncesTracker.getThenIncrementNonce(relayer), + Value: big.NewInt(currentBalance - feeForTransfer - feeForRelayingTransactionsOfAliceAndBob), + SndAddr: relayer.Bytes, + RcvAddr: receiver.Bytes, + Data: []byte{}, + GasLimit: 50_000, + GasPrice: 1_000_000_004, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + }) + + // Transfer from Alice (relayed) + transactions = append(transactions, &transaction.Transaction{ + Nonce: noncesTracker.getThenIncrementNonce(alice), + Value: oneQuarterOfEGLD, + SndAddr: alice.Bytes, + RcvAddr: receiver.Bytes, + RelayerAddr: relayer.Bytes, + Data: []byte{}, + GasLimit: 100_000, + GasPrice: 1_000_000_003, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + RelayerSignature: []byte("signature"), + }) + + // Transfer from Bob (relayed) + transactions = append(transactions, &transaction.Transaction{ + Nonce: noncesTracker.getThenIncrementNonce(bob), + Value: oneQuarterOfEGLD, + SndAddr: bob.Bytes, + RcvAddr: receiver.Bytes, + RelayerAddr: relayer.Bytes, + Data: []byte{}, + GasLimit: 100_000, + GasPrice: 1_000_000_002, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + RelayerSignature: []byte("signature"), + }) + + // Transfer from Carol (relayed) - this one should not be selected due to insufficient balance (of the relayer) + transactions = append(transactions, &transaction.Transaction{ + Nonce: noncesTracker.getThenIncrementNonce(carol), + Value: oneQuarterOfEGLD, + SndAddr: carol.Bytes, + RcvAddr: receiver.Bytes, + RelayerAddr: relayer.Bytes, + Data: []byte{}, + GasLimit: 100_000, + GasPrice: 1_000_000_001, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + RelayerSignature: []byte("signature"), + }) + + sendTransactions(t, simulator, transactions) + time.Sleep(durationWaitAfterSendMany) + require.Equal(t, 4, getNumTransactionsInPool(simulator, shard)) + + selectedTransactions, _ := selectTransactions(t, simulator, shard) + require.Equal(t, 3, len(selectedTransactions)) + + require.Equal(t, relayer.Bytes, selectedTransactions[0].Tx.GetSndAddr()) + require.Equal(t, alice.Bytes, selectedTransactions[1].Tx.GetSndAddr()) + require.Equal(t, bob.Bytes, selectedTransactions[2].Tx.GetSndAddr()) +} + func TestMempoolWithChainSimulator_Eviction(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") diff --git a/integrationTests/chainSimulator/mempool/testutils_test.go b/integrationTests/chainSimulator/mempool/testutils_test.go index 4e1b0c4430f..b2befb1ef87 100644 --- a/integrationTests/chainSimulator/mempool/testutils_test.go +++ b/integrationTests/chainSimulator/mempool/testutils_test.go @@ -58,12 +58,14 @@ func startChainSimulator(t *testing.T, alterConfigsFunction func(cfg *config.Con type participantsHolder struct { sendersByShard map[int][]dtos.WalletAddress + relayerByShard map[int]dtos.WalletAddress receiverByShard map[int]dtos.WalletAddress } func newParticipantsHolder() *participantsHolder { return &participantsHolder{ sendersByShard: make(map[int][]dtos.WalletAddress), + relayerByShard: make(map[int]dtos.WalletAddress), receiverByShard: make(map[int]dtos.WalletAddress), } } @@ -82,10 +84,14 @@ func createParticipants(t *testing.T, simulator testsChainSimulator.ChainSimulat senders = append(senders, sender) } + relayer, err := simulator.GenerateAndMintWalletAddress(uint32(shard), oneEGLD) + require.NoError(t, err) + receiver, err := simulator.GenerateAndMintWalletAddress(0, big.NewInt(0)) require.NoError(t, err) participants.sendersByShard[shard] = senders + participants.relayerByShard[shard] = relayer participants.receiverByShard[shard] = receiver } @@ -126,6 +132,12 @@ func sendTransactions(t *testing.T, simulator testsChainSimulator.ChainSimulator for shard, transactionsFromShard := range transactionsBySenderShard { node := simulator.GetNodeHandler(uint32(shard)) + + for _, tx := range transactionsFromShard { + err := node.GetFacadeHandler().ValidateTransaction(tx) + require.NoError(t, err) + } + numSent, err := node.GetFacadeHandler().SendBulkTransactions(transactionsFromShard) require.NoError(t, err) From 189ba98cacc85fe22ec3b6347c5f2118a23b8f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 16 Jan 2025 10:37:39 +0200 Subject: [PATCH 66/74] Refactor. --- integrationTests/chainSimulator/mempool/mempool_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationTests/chainSimulator/mempool/mempool_test.go b/integrationTests/chainSimulator/mempool/mempool_test.go index 9be46fb6061..16f49ba9594 100644 --- a/integrationTests/chainSimulator/mempool/mempool_test.go +++ b/integrationTests/chainSimulator/mempool/mempool_test.go @@ -94,13 +94,13 @@ func TestMempoolWithChainSimulator_Selection_WhenInsufficientBalanceForFee_WithR transactions := make([]*transaction.Transaction, 0) // Consume most of relayer's balance. Keep an amount that is enough for the fee of two simple transfer transactions. - currentBalance := int64(1000000000000000000) + currentRelayerBalance := int64(1000000000000000000) feeForTransfer := int64(50_000 * 1_000_000_004) feeForRelayingTransactionsOfAliceAndBob := int64(100_000*1_000_000_003 + 100_000*1_000_000_002) transactions = append(transactions, &transaction.Transaction{ Nonce: noncesTracker.getThenIncrementNonce(relayer), - Value: big.NewInt(currentBalance - feeForTransfer - feeForRelayingTransactionsOfAliceAndBob), + Value: big.NewInt(currentRelayerBalance - feeForTransfer - feeForRelayingTransactionsOfAliceAndBob), SndAddr: relayer.Bytes, RcvAddr: receiver.Bytes, Data: []byte{}, From 86fdeb9a4f5fcc8721bba0cf075291b721d908ec Mon Sep 17 00:00:00 2001 From: miiu Date: Thu, 16 Jan 2025 10:57:22 +0200 Subject: [PATCH 67/74] add continue --- outport/process/transactionsfee/transactionsFeeProcessor.go | 1 + 1 file changed, 1 insertion(+) diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index 35bf65ec5de..6cbfb0ddbcf 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -338,6 +338,7 @@ func (tep *transactionsFeeProcessor) prepareScrsNoTx(transactionsAndScrs *transa gasUnits := tep.txFeeCalculator.ComputeGasUnitsFromRefundValue(txFromStorage, scr.Value, epoch) scrHandler.GetFeeInfo().SetGasRefunded(gasUnits) scrHandler.GetFeeInfo().SetFee(scr.Value) + continue } gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(txFromStorage, scr.Value) From f0e500b1b87be4854e50bcc14a0d75df9a573b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 16 Jan 2025 11:26:36 +0200 Subject: [PATCH 68/74] Additional test: TestMempoolWithChainSimulator_Selection_WhenUsersHaveZeroBalance_WithRelayedV3. --- .../chainSimulator/mempool/mempool_test.go | 81 ++++++++++++++++++- .../chainSimulator/mempool/testutils_test.go | 10 ++- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/integrationTests/chainSimulator/mempool/mempool_test.go b/integrationTests/chainSimulator/mempool/mempool_test.go index 16f49ba9594..08921a0d69c 100644 --- a/integrationTests/chainSimulator/mempool/mempool_test.go +++ b/integrationTests/chainSimulator/mempool/mempool_test.go @@ -68,6 +68,86 @@ func TestMempoolWithChainSimulator_Selection(t *testing.T) { require.Equal(t, 50_000*(30_000-27_756), int(gas)) } +func TestMempoolWithChainSimulator_Selection_WhenUsersHaveZeroBalance_WithRelayedV3(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + shard := 0 + + simulator := startChainSimulator(t, func(cfg *config.Configs) {}) + defer simulator.Close() + + err := simulator.GenerateBlocksUntilEpochIsReached(2) + require.NoError(t, err) + + relayer, err := simulator.GenerateAndMintWalletAddress(uint32(shard), oneEGLD) + require.NoError(t, err) + + receiver, err := simulator.GenerateAndMintWalletAddress(uint32(shard), big.NewInt(0)) + require.NoError(t, err) + + alice, err := simulator.GenerateAndMintWalletAddress(uint32(shard), big.NewInt(0)) + require.NoError(t, err) + + bob, err := simulator.GenerateAndMintWalletAddress(uint32(shard), big.NewInt(0)) + require.NoError(t, err) + + err = simulator.GenerateBlocks(1) + require.Nil(t, err) + + noncesTracker := newNoncesTracker() + transactions := make([]*transaction.Transaction, 0) + + // Transfer (executable, invalid) from Alice (relayed) + transactions = append(transactions, &transaction.Transaction{ + Nonce: noncesTracker.getThenIncrementNonce(alice), + Value: oneQuarterOfEGLD, + SndAddr: alice.Bytes, + RcvAddr: receiver.Bytes, + RelayerAddr: relayer.Bytes, + Data: []byte{}, + GasLimit: 100_000, + GasPrice: 1_000_000_002, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + RelayerSignature: []byte("signature"), + }) + + // Contract call from Bob (relayed) + transactions = append(transactions, &transaction.Transaction{ + Nonce: noncesTracker.getThenIncrementNonce(bob), + Value: big.NewInt(0), + SndAddr: bob.Bytes, + RcvAddr: receiver.Bytes, + RelayerAddr: relayer.Bytes, + Data: []byte("hello"), + GasLimit: 100_000 + 5*1500, + GasPrice: 1_000_000_001, + ChainID: []byte(configs.ChainID), + Version: 2, + Signature: []byte("signature"), + RelayerSignature: []byte("signature"), + }) + + sendTransactions(t, simulator, transactions) + time.Sleep(durationWaitAfterSendMany) + require.Equal(t, 2, getNumTransactionsInPool(simulator, shard)) + + selectedTransactions, _ := selectTransactions(t, simulator, shard) + require.Equal(t, 2, len(selectedTransactions)) + require.Equal(t, alice.Bytes, selectedTransactions[0].Tx.GetSndAddr()) + require.Equal(t, bob.Bytes, selectedTransactions[1].Tx.GetSndAddr()) + + err = simulator.GenerateBlocks(1) + require.Nil(t, err) + require.Equal(t, 2, getNumTransactionsInCurrentBlock(simulator, shard)) + + require.Equal(t, "invalid", getTransaction(t, simulator, shard, selectedTransactions[0].TxHash).Status.String()) + require.Equal(t, "success", getTransaction(t, simulator, shard, selectedTransactions[1].TxHash).Status.String()) +} + func TestMempoolWithChainSimulator_Selection_WhenInsufficientBalanceForFee_WithRelayedV3(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") @@ -165,7 +245,6 @@ func TestMempoolWithChainSimulator_Selection_WhenInsufficientBalanceForFee_WithR selectedTransactions, _ := selectTransactions(t, simulator, shard) require.Equal(t, 3, len(selectedTransactions)) - require.Equal(t, relayer.Bytes, selectedTransactions[0].Tx.GetSndAddr()) require.Equal(t, alice.Bytes, selectedTransactions[1].Tx.GetSndAddr()) require.Equal(t, bob.Bytes, selectedTransactions[2].Tx.GetSndAddr()) diff --git a/integrationTests/chainSimulator/mempool/testutils_test.go b/integrationTests/chainSimulator/mempool/testutils_test.go index b2befb1ef87..2e0a0d5a0c9 100644 --- a/integrationTests/chainSimulator/mempool/testutils_test.go +++ b/integrationTests/chainSimulator/mempool/testutils_test.go @@ -1,6 +1,7 @@ package mempool import ( + "encoding/hex" "math/big" "strconv" "testing" @@ -87,7 +88,7 @@ func createParticipants(t *testing.T, simulator testsChainSimulator.ChainSimulat relayer, err := simulator.GenerateAndMintWalletAddress(uint32(shard), oneEGLD) require.NoError(t, err) - receiver, err := simulator.GenerateAndMintWalletAddress(0, big.NewInt(0)) + receiver, err := simulator.GenerateAndMintWalletAddress(uint32(shard), big.NewInt(0)) require.NoError(t, err) participants.sendersByShard[shard] = senders @@ -184,3 +185,10 @@ func getNumTransactionsInCurrentBlock(simulator testsChainSimulator.ChainSimulat currentBlock := node.GetDataComponents().Blockchain().GetCurrentBlockHeader() return int(currentBlock.GetTxCount()) } + +func getTransaction(t *testing.T, simulator testsChainSimulator.ChainSimulator, shard int, hash []byte) *transaction.ApiTransactionResult { + hashAsHex := hex.EncodeToString(hash) + transaction, err := simulator.GetNodeHandler(uint32(shard)).GetFacadeHandler().GetTransaction(hashAsHex, true) + require.NoError(t, err) + return transaction +} From c020f20679cc65bb87cc2b802a15b31dd0e6eb9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 16 Jan 2025 11:39:14 +0200 Subject: [PATCH 69/74] Fix linter. --- integrationTests/chainSimulator/mempool/testutils_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/integrationTests/chainSimulator/mempool/testutils_test.go b/integrationTests/chainSimulator/mempool/testutils_test.go index 2e0a0d5a0c9..dc38a072dc6 100644 --- a/integrationTests/chainSimulator/mempool/testutils_test.go +++ b/integrationTests/chainSimulator/mempool/testutils_test.go @@ -24,7 +24,6 @@ import ( var ( oneEGLD = big.NewInt(1000000000000000000) oneQuarterOfEGLD = big.NewInt(250000000000000000) - oneCentOfEGLD = big.NewInt(10000000000000000) durationWaitAfterSendMany = 750 * time.Millisecond durationWaitAfterSendSome = 10 * time.Millisecond ) From fdfbff69210c105f1a4a7923455feceae35e67fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrei=20B=C4=83ncioiu?= Date: Thu, 16 Jan 2025 12:34:06 +0200 Subject: [PATCH 70/74] Adjust timing / sleeps (for slower CI agents). --- integrationTests/chainSimulator/mempool/mempool_test.go | 6 +++--- integrationTests/chainSimulator/mempool/testutils_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/integrationTests/chainSimulator/mempool/mempool_test.go b/integrationTests/chainSimulator/mempool/mempool_test.go index 08921a0d69c..704be8e40fb 100644 --- a/integrationTests/chainSimulator/mempool/mempool_test.go +++ b/integrationTests/chainSimulator/mempool/mempool_test.go @@ -132,7 +132,7 @@ func TestMempoolWithChainSimulator_Selection_WhenUsersHaveZeroBalance_WithRelaye }) sendTransactions(t, simulator, transactions) - time.Sleep(durationWaitAfterSendMany) + time.Sleep(durationWaitAfterSendSome) require.Equal(t, 2, getNumTransactionsInPool(simulator, shard)) selectedTransactions, _ := selectTransactions(t, simulator, shard) @@ -240,7 +240,7 @@ func TestMempoolWithChainSimulator_Selection_WhenInsufficientBalanceForFee_WithR }) sendTransactions(t, simulator, transactions) - time.Sleep(durationWaitAfterSendMany) + time.Sleep(durationWaitAfterSendSome) require.Equal(t, 4, getNumTransactionsInPool(simulator, shard)) selectedTransactions, _ := selectTransactions(t, simulator, shard) @@ -324,7 +324,7 @@ func TestMempoolWithChainSimulator_Eviction(t *testing.T) { Signature: []byte("signature"), }) - time.Sleep(1 * time.Second) + time.Sleep(2 * time.Second) expectedNumTransactionsInPool := 300_000 + 1 + 1 - int(storage.TxPoolSourceMeNumItemsToPreemptivelyEvict) require.Equal(t, expectedNumTransactionsInPool, getNumTransactionsInPool(simulator, shard)) diff --git a/integrationTests/chainSimulator/mempool/testutils_test.go b/integrationTests/chainSimulator/mempool/testutils_test.go index dc38a072dc6..3d4a0afd5f7 100644 --- a/integrationTests/chainSimulator/mempool/testutils_test.go +++ b/integrationTests/chainSimulator/mempool/testutils_test.go @@ -24,8 +24,8 @@ import ( var ( oneEGLD = big.NewInt(1000000000000000000) oneQuarterOfEGLD = big.NewInt(250000000000000000) - durationWaitAfterSendMany = 750 * time.Millisecond - durationWaitAfterSendSome = 10 * time.Millisecond + durationWaitAfterSendMany = 1500 * time.Millisecond + durationWaitAfterSendSome = 50 * time.Millisecond ) func startChainSimulator(t *testing.T, alterConfigsFunction func(cfg *config.Configs)) testsChainSimulator.ChainSimulator { From 1476698d153770d17a8f39bcb702e93ae71826c3 Mon Sep 17 00:00:00 2001 From: Sorin Stanculeanu Date: Thu, 16 Jan 2025 13:38:21 +0200 Subject: [PATCH 71/74] updated deps --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 02d7fe91bce..111b510c0ab 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,12 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/mitchellh/mapstructure v1.5.0 github.com/multiversx/mx-chain-communication-go v1.1.1 - github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4 + github.com/multiversx/mx-chain-core-go v1.2.24 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250116081916-62f5c3451bed + github.com/multiversx/mx-chain-es-indexer-go v1.7.13 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 - github.com/multiversx/mx-chain-storage-go v1.0.19-0.20250109152325-cf81acfd19bd + github.com/multiversx/mx-chain-storage-go v1.0.19 github.com/multiversx/mx-chain-vm-common-go v1.5.16 github.com/multiversx/mx-chain-vm-go v1.5.37 github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68 diff --git a/go.sum b/go.sum index 9281063733f..9886037c8d0 100644 --- a/go.sum +++ b/go.sum @@ -387,18 +387,18 @@ github.com/multiversx/concurrent-map v0.1.4 h1:hdnbM8VE4b0KYJaGY5yJS2aNIW9TFFsUY github.com/multiversx/concurrent-map v0.1.4/go.mod h1:8cWFRJDOrWHOTNSqgYCUvwT7c7eFQ4U2vKMOp4A/9+o= github.com/multiversx/mx-chain-communication-go v1.1.1 h1:y4DoQeQOJTaSUsRzczQFazf8JYQmInddypApqA3AkwM= github.com/multiversx/mx-chain-communication-go v1.1.1/go.mod h1:WK6bP4pGEHGDDna/AYRIMtl6G9OA0NByI1Lw8PmOnRM= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4 h1:rWYFL38q5cbo5MtdW2DvAp4+WMaVp8e7gBjmrLQ9SCY= -github.com/multiversx/mx-chain-core-go v1.2.24-0.20250116081327-adb8c08089b4/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= +github.com/multiversx/mx-chain-core-go v1.2.24 h1:O0X7N9GfNVUCE9fukXA+dvfCRRjViYn88zOaE7feUog= +github.com/multiversx/mx-chain-core-go v1.2.24/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250116081916-62f5c3451bed h1:UOZ6c1MOANM8RLyYw/okKGwnowF+dRbzwPpzr11zaZ0= -github.com/multiversx/mx-chain-es-indexer-go v1.7.13-0.20250116081916-62f5c3451bed/go.mod h1:Q6qug6OodSOzwZuMrvrfDcMmPB2FcP7CKr9rqsn0OHQ= +github.com/multiversx/mx-chain-es-indexer-go v1.7.13 h1:1Boeb0x28fzYBVRlnaCPRaXifRXAFiCit34t6O8efyM= +github.com/multiversx/mx-chain-es-indexer-go v1.7.13/go.mod h1:5Sr49FjWWzZ3/WcC3jzln8TlMSNToCIT9Lqy6P7i7bs= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= github.com/multiversx/mx-chain-scenario-go v1.4.4/go.mod h1:kI+TWR3oIEgUkbwkHCPo2CQ3VjIge+ezGTibiSGwMxo= -github.com/multiversx/mx-chain-storage-go v1.0.19-0.20250109152325-cf81acfd19bd h1:qhdCOHlo4EAvFpGhToDKPiXwZA8x9PeGcBWTVvYzUOw= -github.com/multiversx/mx-chain-storage-go v1.0.19-0.20250109152325-cf81acfd19bd/go.mod h1:8EA0PzK1ZPGpSKe+nXHx0My1MJlBcJ51fb7J7SwH7Lw= +github.com/multiversx/mx-chain-storage-go v1.0.19 h1:2R35MoSXcuNJOFmV5xEhcXqiEGZw6AYGy9R8J9KH66Q= +github.com/multiversx/mx-chain-storage-go v1.0.19/go.mod h1:Pb/BuVmiFqO66DSZO16KFkSUeom94x3e3Q9IloBvkYI= github.com/multiversx/mx-chain-vm-common-go v1.5.16 h1:g1SqYjxl7K66Y1O/q6tvDJ37fzpzlxCSfRzSm/woQQY= github.com/multiversx/mx-chain-vm-common-go v1.5.16/go.mod h1:1rSkXreUZNXyPTTdhj47M+Fy62yjxbu3aAsXEtKN3UY= github.com/multiversx/mx-chain-vm-go v1.5.37 h1:Iy3KCvM+DOq1f9UPA7uYK/rI3ZbBOXc2CVNO2/vm5zw= From 1c86a1ee64f924e160d405a6d64f6e14ab665c15 Mon Sep 17 00:00:00 2001 From: miiu Date: Wed, 22 Jan 2025 18:15:46 +0200 Subject: [PATCH 72/74] new indexer --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 111b510c0ab..2a1bbadf954 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/multiversx/mx-chain-communication-go v1.1.1 github.com/multiversx/mx-chain-core-go v1.2.24 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.13 + github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250122161311-c658f09cc043 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 github.com/multiversx/mx-chain-storage-go v1.0.19 diff --git a/go.sum b/go.sum index 9886037c8d0..483ee1d83b0 100644 --- a/go.sum +++ b/go.sum @@ -391,8 +391,8 @@ github.com/multiversx/mx-chain-core-go v1.2.24 h1:O0X7N9GfNVUCE9fukXA+dvfCRRjViY github.com/multiversx/mx-chain-core-go v1.2.24/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.13 h1:1Boeb0x28fzYBVRlnaCPRaXifRXAFiCit34t6O8efyM= -github.com/multiversx/mx-chain-es-indexer-go v1.7.13/go.mod h1:5Sr49FjWWzZ3/WcC3jzln8TlMSNToCIT9Lqy6P7i7bs= +github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250122161311-c658f09cc043 h1:90sjT5Kgtw8JW9XNORhauCtb+B+i+ogxuD1/C1Jstho= +github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250122161311-c658f09cc043/go.mod h1:5Sr49FjWWzZ3/WcC3jzln8TlMSNToCIT9Lqy6P7i7bs= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= From e9dfa12de916901b6fb2f9e61e476093d0459293 Mon Sep 17 00:00:00 2001 From: miiu Date: Thu, 23 Jan 2025 11:53:08 +0200 Subject: [PATCH 73/74] fixes --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2a1bbadf954..05d33e3e14b 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/multiversx/mx-chain-communication-go v1.1.1 github.com/multiversx/mx-chain-core-go v1.2.24 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250122161311-c658f09cc043 + github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250123094846-b9d3793de7eb github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 github.com/multiversx/mx-chain-storage-go v1.0.19 diff --git a/go.sum b/go.sum index 483ee1d83b0..6261ccbffe4 100644 --- a/go.sum +++ b/go.sum @@ -391,8 +391,8 @@ github.com/multiversx/mx-chain-core-go v1.2.24 h1:O0X7N9GfNVUCE9fukXA+dvfCRRjViY github.com/multiversx/mx-chain-core-go v1.2.24/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250122161311-c658f09cc043 h1:90sjT5Kgtw8JW9XNORhauCtb+B+i+ogxuD1/C1Jstho= -github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250122161311-c658f09cc043/go.mod h1:5Sr49FjWWzZ3/WcC3jzln8TlMSNToCIT9Lqy6P7i7bs= +github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250123094846-b9d3793de7eb h1:eNNDlJ+0dIqEdAN05sbxB/YD6BUMN0e0A5ojNlvM2aY= +github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250123094846-b9d3793de7eb/go.mod h1:5Sr49FjWWzZ3/WcC3jzln8TlMSNToCIT9Lqy6P7i7bs= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460= From 4ff8d192626b36d0947b73e668db81a908d2969d Mon Sep 17 00:00:00 2001 From: miiu Date: Thu, 23 Jan 2025 14:13:19 +0200 Subject: [PATCH 74/74] proper tag --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 05d33e3e14b..cd0ee839650 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/multiversx/mx-chain-communication-go v1.1.1 github.com/multiversx/mx-chain-core-go v1.2.24 github.com/multiversx/mx-chain-crypto-go v1.2.12 - github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250123094846-b9d3793de7eb + github.com/multiversx/mx-chain-es-indexer-go v1.7.14 github.com/multiversx/mx-chain-logger-go v1.0.15 github.com/multiversx/mx-chain-scenario-go v1.4.4 github.com/multiversx/mx-chain-storage-go v1.0.19 diff --git a/go.sum b/go.sum index 6261ccbffe4..ea2dab5a446 100644 --- a/go.sum +++ b/go.sum @@ -391,8 +391,8 @@ github.com/multiversx/mx-chain-core-go v1.2.24 h1:O0X7N9GfNVUCE9fukXA+dvfCRRjViY github.com/multiversx/mx-chain-core-go v1.2.24/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= github.com/multiversx/mx-chain-crypto-go v1.2.12 h1:zWip7rpUS4CGthJxfKn5MZfMfYPjVjIiCID6uX5BSOk= github.com/multiversx/mx-chain-crypto-go v1.2.12/go.mod h1:HzcPpCm1zanNct/6h2rIh+MFrlXbjA5C8+uMyXj3LI4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250123094846-b9d3793de7eb h1:eNNDlJ+0dIqEdAN05sbxB/YD6BUMN0e0A5ojNlvM2aY= -github.com/multiversx/mx-chain-es-indexer-go v1.7.14-0.20250123094846-b9d3793de7eb/go.mod h1:5Sr49FjWWzZ3/WcC3jzln8TlMSNToCIT9Lqy6P7i7bs= +github.com/multiversx/mx-chain-es-indexer-go v1.7.14 h1:V4fuubEUYskWCLQIkbuoB0WHoKyldLQRq/fllIzW1CU= +github.com/multiversx/mx-chain-es-indexer-go v1.7.14/go.mod h1:5Sr49FjWWzZ3/WcC3jzln8TlMSNToCIT9Lqy6P7i7bs= github.com/multiversx/mx-chain-logger-go v1.0.15 h1:HlNdK8etyJyL9NQ+6mIXyKPEBo+wRqOwi3n+m2QIHXc= github.com/multiversx/mx-chain-logger-go v1.0.15/go.mod h1:t3PRKaWB1M+i6gUfD27KXgzLJJC+mAQiN+FLlL1yoGQ= github.com/multiversx/mx-chain-scenario-go v1.4.4 h1:DVE2V+FPeyD/yWoC+KEfPK3jsFzHeruelESfpTlf460=