diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index b43adf3ef0e..d552db889c7 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -9,7 +9,7 @@ jobs: build: strategy: matrix: - runs-on: [ubuntu-latest, macos-13-xlarge] + runs-on: [ubuntu-latest, macos-13, macos-13-xlarge] runs-on: ${{ matrix.runs-on }} name: Build steps: diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml index 81fd087a704..fe74d301325 100644 --- a/.github/workflows/create_release.yml +++ b/.github/workflows/create_release.yml @@ -15,7 +15,7 @@ jobs: build: strategy: matrix: - runs-on: [ubuntu-latest, macos-13-xlarge] + runs-on: [ubuntu-latest, macos-13, macos-13-xlarge] runs-on: ${{ matrix.runs-on }} name: Build steps: diff --git a/.github/workflows/docker-keygenerator.yaml b/.github/workflows/docker-keygenerator.yaml new file mode 100644 index 00000000000..5e4d9d44a32 --- /dev/null +++ b/.github/workflows/docker-keygenerator.yaml @@ -0,0 +1,36 @@ +name: Build & push keygenerator docker image + +on: + workflow_dispatch: + pull_request: + +jobs: + build-docker-image: + strategy: + matrix: + runs-on: [ubuntu-latest] + runs-on: ${{ matrix.runs-on }} + + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log into Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push image to Docker Hub + id: push + uses: docker/build-push-action@v6 + with: + context: . + file: ./docker/keygenerator/Dockerfile + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: multiversx/chain-keygenerator:latest diff --git a/api/errors/errors.go b/api/errors/errors.go index b01cec657ca..30cfb923bbd 100644 --- a/api/errors/errors.go +++ b/api/errors/errors.go @@ -174,3 +174,6 @@ var ErrGetWaitingManagedKeys = errors.New("error getting the waiting managed key // ErrGetWaitingEpochsLeftForPublicKey signals that an error occurred while getting the waiting epochs left for public key var ErrGetWaitingEpochsLeftForPublicKey = errors.New("error getting the waiting epochs left for public key") + +// ErrRecursiveRelayedTxIsNotAllowed signals that recursive relayed tx is not allowed +var ErrRecursiveRelayedTxIsNotAllowed = errors.New("recursive relayed tx is not allowed") diff --git a/api/groups/addressGroup.go b/api/groups/addressGroup.go index a059d3a4388..151b7f53372 100644 --- a/api/groups/addressGroup.go +++ b/api/groups/addressGroup.go @@ -72,9 +72,11 @@ type esdtTokenData struct { Properties string `json:"properties"` } -type esdtNFTTokenData struct { +// ESDTNFTTokenData defines the exposed nft token data structure +type ESDTNFTTokenData struct { TokenIdentifier string `json:"tokenIdentifier"` Balance string `json:"balance"` + Type string `json:"type"` Properties string `json:"properties,omitempty"` Name string `json:"name,omitempty"` Nonce uint64 `json:"nonce,omitempty"` @@ -448,7 +450,7 @@ func (ag *addressGroup) getAllESDTData(c *gin.Context) { return } - formattedTokens := make(map[string]*esdtNFTTokenData) + formattedTokens := make(map[string]*ESDTNFTTokenData) for tokenID, esdtData := range tokens { tokenData := buildTokenDataApiResponse(tokenID, esdtData) @@ -481,12 +483,14 @@ func (ag *addressGroup) isDataTrieMigrated(c *gin.Context) { shared.RespondWithSuccess(c, gin.H{"isMigrated": isMigrated}) } -func buildTokenDataApiResponse(tokenIdentifier string, esdtData *esdt.ESDigitalToken) *esdtNFTTokenData { - tokenData := &esdtNFTTokenData{ +func buildTokenDataApiResponse(tokenIdentifier string, esdtData *esdt.ESDigitalToken) *ESDTNFTTokenData { + tokenData := &ESDTNFTTokenData{ TokenIdentifier: tokenIdentifier, Balance: esdtData.Value.String(), Properties: hex.EncodeToString(esdtData.Properties), } + + tokenType := core.ESDTType(esdtData.Type).String() if esdtData.TokenMetaData != nil { tokenData.Name = string(esdtData.TokenMetaData.Name) tokenData.Nonce = esdtData.TokenMetaData.Nonce @@ -495,11 +499,25 @@ func buildTokenDataApiResponse(tokenIdentifier string, esdtData *esdt.ESDigitalT tokenData.Hash = esdtData.TokenMetaData.Hash tokenData.URIs = esdtData.TokenMetaData.URIs tokenData.Attributes = esdtData.TokenMetaData.Attributes + + tokenType = getTokenType(esdtData.GetType(), tokenData.Nonce) } + tokenData.Type = tokenType + return tokenData } +func getTokenType(tokenType uint32, tokenNonce uint64) string { + isNotFungible := tokenNonce != 0 + tokenTypeNotSet := isNotFungible && core.ESDTType(tokenType) == core.NonFungible + if tokenTypeNotSet { + return "" + } + + return core.ESDTType(tokenType).String() +} + func (ag *addressGroup) getFacade() addressFacadeHandler { ag.mutFacade.RLock() defer ag.mutFacade.RUnlock() diff --git a/api/groups/transactionGroup.go b/api/groups/transactionGroup.go index 3c62221d121..29d07de2640 100644 --- a/api/groups/transactionGroup.go +++ b/api/groups/transactionGroup.go @@ -182,27 +182,23 @@ func (tg *transactionGroup) simulateTransaction(c *gin.Context) { return } - txArgs := &external.ArgsCreateTransaction{ - Nonce: ftx.Nonce, - Value: ftx.Value, - Receiver: ftx.Receiver, - ReceiverUsername: ftx.ReceiverUsername, - Sender: ftx.Sender, - SenderUsername: ftx.SenderUsername, - GasPrice: ftx.GasPrice, - GasLimit: ftx.GasLimit, - DataField: ftx.Data, - SignatureHex: ftx.Signature, - ChainID: ftx.ChainID, - Version: ftx.Version, - Options: ftx.Options, - Guardian: ftx.GuardianAddr, - GuardianSigHex: ftx.GuardianSignature, + innerTxs, err := tg.extractInnerTransactions(ftx.InnerTransactions) + if err != nil { + c.JSON( + http.StatusBadRequest, + shared.GenericAPIResponse{ + Data: nil, + Error: fmt.Sprintf("%s: %s", errors.ErrTxGenerationFailed.Error(), err.Error()), + Code: shared.ReturnCodeRequestError, + }, + ) + return } - start := time.Now() - tx, txHash, err := tg.getFacade().CreateTransaction(txArgs) - logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction") + if len(innerTxs) == 0 { + innerTxs = nil + } + tx, txHash, err := tg.createTransaction(&ftx, innerTxs) if err != nil { c.JSON( http.StatusBadRequest, @@ -215,7 +211,7 @@ func (tg *transactionGroup) simulateTransaction(c *gin.Context) { return } - start = time.Now() + start := time.Now() err = tg.getFacade().ValidateTransactionForSimulation(tx, checkSignature) logging.LogAPIActionDurationIfNeeded(start, "API call: ValidateTransactionForSimulation") if err != nil { @@ -272,26 +268,23 @@ func (tg *transactionGroup) sendTransaction(c *gin.Context) { return } - txArgs := &external.ArgsCreateTransaction{ - Nonce: ftx.Nonce, - Value: ftx.Value, - Receiver: ftx.Receiver, - ReceiverUsername: ftx.ReceiverUsername, - Sender: ftx.Sender, - SenderUsername: ftx.SenderUsername, - GasPrice: ftx.GasPrice, - GasLimit: ftx.GasLimit, - DataField: ftx.Data, - SignatureHex: ftx.Signature, - ChainID: ftx.ChainID, - Version: ftx.Version, - Options: ftx.Options, - Guardian: ftx.GuardianAddr, - GuardianSigHex: ftx.GuardianSignature, + innerTxs, err := tg.extractInnerTransactions(ftx.InnerTransactions) + if err != nil { + c.JSON( + http.StatusBadRequest, + shared.GenericAPIResponse{ + Data: nil, + Error: fmt.Sprintf("%s: %s", errors.ErrTxGenerationFailed.Error(), err.Error()), + Code: shared.ReturnCodeRequestError, + }, + ) + return } - start := time.Now() - tx, txHash, err := tg.getFacade().CreateTransaction(txArgs) - logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction") + + if len(innerTxs) == 0 { + innerTxs = nil + } + tx, txHash, err := tg.createTransaction(&ftx, innerTxs) if err != nil { c.JSON( http.StatusBadRequest, @@ -304,7 +297,7 @@ func (tg *transactionGroup) sendTransaction(c *gin.Context) { return } - start = time.Now() + start := time.Now() err = tg.getFacade().ValidateTransaction(tx) logging.LogAPIActionDurationIfNeeded(start, "API call: ValidateTransaction") if err != nil { @@ -370,25 +363,23 @@ func (tg *transactionGroup) sendMultipleTransactions(c *gin.Context) { var start time.Time txsHashes := make(map[int]string) for idx, receivedTx := range ftxs { - 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, + innerTxs, errExtractInnerTransactions := tg.extractInnerTransactions(receivedTx.InnerTransactions) + if errExtractInnerTransactions != nil { + c.JSON( + http.StatusBadRequest, + shared.GenericAPIResponse{ + Data: nil, + Error: fmt.Sprintf("%s: %s", errors.ErrTxGenerationFailed.Error(), err.Error()), + Code: shared.ReturnCodeInternalError, + }, + ) + return + } + + if len(innerTxs) == 0 { + innerTxs = nil } - tx, txHash, err = tg.getFacade().CreateTransaction(txArgs) - logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction") + tx, txHash, err = tg.createTransaction(&receivedTx, innerTxs) if err != nil { continue } @@ -499,26 +490,23 @@ func (tg *transactionGroup) computeTransactionGasLimit(c *gin.Context) { return } - txArgs := &external.ArgsCreateTransaction{ - Nonce: ftx.Nonce, - Value: ftx.Value, - Receiver: ftx.Receiver, - ReceiverUsername: ftx.ReceiverUsername, - Sender: ftx.Sender, - SenderUsername: ftx.SenderUsername, - GasPrice: ftx.GasPrice, - GasLimit: ftx.GasLimit, - DataField: ftx.Data, - SignatureHex: ftx.Signature, - ChainID: ftx.ChainID, - Version: ftx.Version, - Options: ftx.Options, - Guardian: ftx.GuardianAddr, - GuardianSigHex: ftx.GuardianSignature, + innerTxs, errExtractInnerTransactions := tg.extractInnerTransactions(ftx.InnerTransactions) + if errExtractInnerTransactions != nil { + c.JSON( + http.StatusBadRequest, + shared.GenericAPIResponse{ + Data: nil, + Error: fmt.Sprintf("%s: %s", errors.ErrTxGenerationFailed.Error(), errExtractInnerTransactions.Error()), + Code: shared.ReturnCodeInternalError, + }, + ) + return } - start := time.Now() - tx, _, err := tg.getFacade().CreateTransaction(txArgs) - logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction") + + if len(innerTxs) == 0 { + innerTxs = nil + } + tx, _, err := tg.createTransaction(&ftx, innerTxs) if err != nil { c.JSON( http.StatusInternalServerError, @@ -531,7 +519,7 @@ func (tg *transactionGroup) computeTransactionGasLimit(c *gin.Context) { return } - start = time.Now() + start := time.Now() cost, err := tg.getFacade().ComputeTransactionGasLimit(tx) logging.LogAPIActionDurationIfNeeded(start, "API call: ComputeTransactionGasLimit") if err != nil { @@ -728,6 +716,33 @@ func (tg *transactionGroup) getTransactionsPoolNonceGapsForSender(sender string, ) } +func (tg *transactionGroup) createTransaction(receivedTx *transaction.FrontendTransaction, innerTxs []*transaction.Transaction) (*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, + Relayer: receivedTx.Relayer, + InnerTransactions: innerTxs, + } + start := time.Now() + tx, txHash, err := tg.getFacade().CreateTransaction(txArgs) + logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction") + + return tx, txHash, err +} + func validateQuery(sender, fields string, lastNonce, nonceGaps bool) error { if fields != "" && lastNonce { return errors.ErrFetchingLatestNonceCannotIncludeFields @@ -825,6 +840,28 @@ func (tg *transactionGroup) getFacade() transactionFacadeHandler { return tg.facade } +func (tg *transactionGroup) extractInnerTransactions( + innerTransactions []*transaction.FrontendTransaction, +) ([]*transaction.Transaction, error) { + innerTxs := make([]*transaction.Transaction, 0, len(innerTransactions)) + if len(innerTransactions) != 0 { + for _, innerTx := range innerTransactions { + if len(innerTx.InnerTransactions) != 0 { + return innerTxs, errors.ErrRecursiveRelayedTxIsNotAllowed + } + + newInnerTx, _, err := tg.createTransaction(innerTx, nil) + if err != nil { + return innerTxs, err + } + + innerTxs = append(innerTxs, newInnerTx) + } + } + + return innerTxs, nil +} + // UpdateFacade will update the facade func (tg *transactionGroup) UpdateFacade(newFacade interface{}) error { if newFacade == nil { diff --git a/api/groups/transactionGroup_test.go b/api/groups/transactionGroup_test.go index 22085956fe9..f183dd30b4c 100644 --- a/api/groups/transactionGroup_test.go +++ b/api/groups/transactionGroup_test.go @@ -312,6 +312,7 @@ func TestTransactionGroup_sendTransaction(t *testing.T) { expectedErr, ) }) + t.Run("recursive relayed v3 should error", testRecursiveRelayedV3("/transaction/send")) t.Run("should work", func(t *testing.T) { t.Parallel() @@ -520,6 +521,7 @@ func TestTransactionGroup_computeTransactionGasLimit(t *testing.T) { expectedErr, ) }) + t.Run("recursive relayed v3 should error", testRecursiveRelayedV3("/transaction/cost")) t.Run("should work", func(t *testing.T) { t.Parallel() @@ -640,6 +642,7 @@ func TestTransactionGroup_simulateTransaction(t *testing.T) { expectedErr, ) }) + t.Run("recursive relayed v3 should error", testRecursiveRelayedV3("/transaction/simulate")) t.Run("should work", func(t *testing.T) { t.Parallel() @@ -1127,3 +1130,62 @@ func getTransactionRoutesConfig() config.ApiRoutesConfig { }, } } + +func testRecursiveRelayedV3(url string) func(t *testing.T) { + return func(t *testing.T) { + t.Parallel() + + facade := &mock.FacadeStub{ + CreateTransactionHandler: func(txArgs *external.ArgsCreateTransaction) (*dataTx.Transaction, []byte, error) { + txHash, _ := hex.DecodeString(hexTxHash) + return nil, txHash, nil + }, + SendBulkTransactionsHandler: func(txs []*dataTx.Transaction) (u uint64, err error) { + return 1, nil + }, + ValidateTransactionHandler: func(tx *dataTx.Transaction) error { + return nil + }, + } + + userTx1 := fmt.Sprintf(`{"nonce": %d, "sender":"%s", "receiver":"%s", "value":"%s", "signature":"%s"}`, + nonce, + sender, + receiver, + value, + signature, + ) + userTx2 := fmt.Sprintf(`{"nonce": %d, "sender":"%s", "receiver":"%s", "value":"%s", "signature":"%s", "innerTransactions":[%s]}`, + nonce, + sender, + receiver, + value, + signature, + userTx1, + ) + tx := fmt.Sprintf(`{"nonce": %d, "sender":"%s", "receiver":"%s", "value":"%s", "signature":"%s", "innerTransactions":[%s]}`, + nonce, + sender, + receiver, + value, + signature, + userTx2, + ) + + transactionGroup, err := groups.NewTransactionGroup(facade) + require.NoError(t, err) + + ws := startWebServer(transactionGroup, "transaction", getTransactionRoutesConfig()) + + req, _ := http.NewRequest("POST", url, bytes.NewBuffer([]byte(tx))) + resp := httptest.NewRecorder() + ws.ServeHTTP(resp, req) + + txResp := shared.GenericAPIResponse{} + loadResponse(resp.Body, &txResp) + + assert.Equal(t, http.StatusBadRequest, resp.Code) + assert.True(t, strings.Contains(txResp.Error, apiErrors.ErrRecursiveRelayedTxIsNotAllowed.Error())) + assert.Empty(t, txResp.Data) + } +} diff --git a/cmd/node/config/config.toml b/cmd/node/config/config.toml index 6e1205d5f7e..7f07d4dd380 100644 --- a/cmd/node/config/config.toml +++ b/cmd/node/config/config.toml @@ -946,3 +946,6 @@ # MaxRoundsOfInactivityAccepted defines the number of rounds missed by a main or higher level backup machine before # the current machine will take over and propose/sign blocks. Used in both single-key and multi-key modes. MaxRoundsOfInactivityAccepted = 3 + +[RelayedTransactionConfig] + MaxTransactionsAllowed = 50 diff --git a/cmd/node/config/enableEpochs.toml b/cmd/node/config/enableEpochs.toml index c2f84c7a409..f088f7b549c 100644 --- a/cmd/node/config/enableEpochs.toml +++ b/cmd/node/config/enableEpochs.toml @@ -318,6 +318,18 @@ # CryptoOpcodesV2EnableEpoch represents the epoch when BLSMultiSig, Secp256r1 and other opcodes are enabled CryptoOpcodesV2EnableEpoch = 4 + # UnjailCleanupEnableEpoch represents the epoch when the cleanup of the unjailed nodes is enabled + UnJailCleanupEnableEpoch = 4 + + # RelayedTransactionsV3EnableEpoch represents the epoch when the relayed transactions V3 will be enabled + RelayedTransactionsV3EnableEpoch = 7 + + # FixRelayedBaseCostEnableEpoch represents the epoch when the fix for relayed base cost will be enabled + FixRelayedBaseCostEnableEpoch = 7 + + # MultiESDTNFTTransferAndExecuteByUserEnableEpoch represents the epoch when enshrined sovereign cross chain opcodes are enabled + MultiESDTNFTTransferAndExecuteByUserEnableEpoch = 9999999 + # BLSMultiSignerEnableEpoch represents the activation epoch for different types of BLS multi-signers BLSMultiSignerEnableEpoch = [ { EnableEpoch = 0, Type = "no-KOSK" }, @@ -338,5 +350,5 @@ [GasSchedule] # GasScheduleByEpochs holds the configuration for the gas schedule that will be applied from specific epochs GasScheduleByEpochs = [ - { StartEpoch = 0, FileName = "gasScheduleV7.toml" }, + { StartEpoch = 0, FileName = "gasScheduleV8.toml" }, ] diff --git a/cmd/node/config/gasSchedules/gasScheduleV1.toml b/cmd/node/config/gasSchedules/gasScheduleV1.toml index 5e715a2d466..7fca1d6a7d2 100644 --- a/cmd/node/config/gasSchedules/gasScheduleV1.toml +++ b/cmd/node/config/gasSchedules/gasScheduleV1.toml @@ -112,6 +112,7 @@ GetCallbackClosure = 10000 GetCodeMetadata = 10000 IsBuiltinFunction = 10000 + IsReservedFunctionName = 10000 [EthAPICost] UseGas = 100 diff --git a/cmd/node/config/gasSchedules/gasScheduleV2.toml b/cmd/node/config/gasSchedules/gasScheduleV2.toml index e0d1c4e366e..bfc53d1b91d 100644 --- a/cmd/node/config/gasSchedules/gasScheduleV2.toml +++ b/cmd/node/config/gasSchedules/gasScheduleV2.toml @@ -112,6 +112,7 @@ GetCallbackClosure = 10000 GetCodeMetadata = 10000 IsBuiltinFunction = 10000 + IsReservedFunctionName = 10000 [EthAPICost] UseGas = 100 diff --git a/cmd/node/config/gasSchedules/gasScheduleV3.toml b/cmd/node/config/gasSchedules/gasScheduleV3.toml index 8c3a763363e..eb88204bf5e 100644 --- a/cmd/node/config/gasSchedules/gasScheduleV3.toml +++ b/cmd/node/config/gasSchedules/gasScheduleV3.toml @@ -112,6 +112,7 @@ GetCallbackClosure = 10000 GetCodeMetadata = 10000 IsBuiltinFunction = 10000 + IsReservedFunctionName = 10000 [EthAPICost] UseGas = 100 diff --git a/cmd/node/config/gasSchedules/gasScheduleV4.toml b/cmd/node/config/gasSchedules/gasScheduleV4.toml index 4d178ff0fd5..f41a7a8d940 100644 --- a/cmd/node/config/gasSchedules/gasScheduleV4.toml +++ b/cmd/node/config/gasSchedules/gasScheduleV4.toml @@ -112,6 +112,7 @@ GetCallbackClosure = 10000 GetCodeMetadata = 10000 IsBuiltinFunction = 10000 + IsReservedFunctionName = 10000 [EthAPICost] UseGas = 100 diff --git a/cmd/node/config/gasSchedules/gasScheduleV5.toml b/cmd/node/config/gasSchedules/gasScheduleV5.toml index e5f5035bb17..34b4336b32c 100644 --- a/cmd/node/config/gasSchedules/gasScheduleV5.toml +++ b/cmd/node/config/gasSchedules/gasScheduleV5.toml @@ -112,6 +112,7 @@ GetCallbackClosure = 10000 GetCodeMetadata = 10000 IsBuiltinFunction = 10000 + IsReservedFunctionName = 10000 [EthAPICost] UseGas = 100 diff --git a/cmd/node/config/gasSchedules/gasScheduleV6.toml b/cmd/node/config/gasSchedules/gasScheduleV6.toml index f41c5002b85..99ff15c8482 100644 --- a/cmd/node/config/gasSchedules/gasScheduleV6.toml +++ b/cmd/node/config/gasSchedules/gasScheduleV6.toml @@ -112,6 +112,7 @@ GetCallbackClosure = 10000 GetCodeMetadata = 10000 IsBuiltinFunction = 10000 + IsReservedFunctionName = 10000 [EthAPICost] UseGas = 100 diff --git a/cmd/node/config/gasSchedules/gasScheduleV7.toml b/cmd/node/config/gasSchedules/gasScheduleV7.toml index 6b580c893cc..250d89117cf 100644 --- a/cmd/node/config/gasSchedules/gasScheduleV7.toml +++ b/cmd/node/config/gasSchedules/gasScheduleV7.toml @@ -113,6 +113,7 @@ GetCallbackClosure = 10000 GetCodeMetadata = 10000 IsBuiltinFunction = 10000 + IsReservedFunctionName = 10000 [EthAPICost] UseGas = 100 diff --git a/cmd/node/config/gasSchedules/gasScheduleV8.toml b/cmd/node/config/gasSchedules/gasScheduleV8.toml new file mode 100644 index 00000000000..7a0c11de4e9 --- /dev/null +++ b/cmd/node/config/gasSchedules/gasScheduleV8.toml @@ -0,0 +1,837 @@ +[BuiltInCost] + ChangeOwnerAddress = 5000000 + ClaimDeveloperRewards = 5000000 + SaveUserName = 1000000 + SaveKeyValue = 100000 + ESDTTransfer = 200000 + ESDTBurn = 100000 + ESDTLocalMint = 50000 + ESDTLocalBurn = 50000 + ESDTNFTCreate = 150000 + ESDTNFTAddQuantity = 50000 + ESDTNFTBurn = 50000 + ESDTNFTTransfer = 200000 + ESDTNFTChangeCreateOwner = 1000000 + ESDTNFTAddUri = 50000 + ESDTNFTUpdateAttributes = 50000 + ESDTNFTMultiTransfer = 200000 + MultiESDTNFTTransfer = 200000 # should be the same value with the ESDTNFTMultiTransfer + ESDTModifyRoyalties = 500000 + ESDTModifyCreator = 500000 + ESDTNFTRecreate = 1000000 + ESDTNFTUpdate = 1000000 + ESDTNFTSetNewURIs = 500000 + SetGuardian = 250000 + GuardAccount = 250000 + UnGuardAccount = 250000 + TrieLoadPerNode = 100000 + TrieStorePerNode = 50000 + +[MetaChainSystemSCsCost] + Stake = 5000000 + UnStake = 5000000 + UnBond = 5000000 + Claim = 5000000 + Get = 5000000 + ChangeRewardAddress = 5000000 + ChangeValidatorKeys = 5000000 + UnJail = 5000000 + DelegationOps = 1000000 + DelegationMgrOps = 50000000 + ValidatorToDelegation = 500000000 + ESDTIssue = 50000000 + ESDTOperations = 50000000 + Proposal = 50000000 + Vote = 5000000 + DelegateVote = 50000000 + RevokeVote = 50000000 + CloseProposal = 50000000 + GetAllNodeStates = 20000000 + UnstakeTokens = 5000000 + UnbondTokens = 5000000 + GetActiveFund = 50000 + FixWaitingListSize = 500000000 + +[BaseOperationCost] + StorePerByte = 10000 + ReleasePerByte = 1000 + DataCopyPerByte = 50 + PersistPerByte = 1000 + CompilePerByte = 300 + AoTPreparePerByte = 100 + GetCode = 1000000 + +[BaseOpsAPICost] + GetSCAddress = 1000 + GetOwnerAddress = 5000 + IsSmartContract = 5000 + GetShardOfAddress = 5000 + GetExternalBalance = 7000 + GetBlockHash = 10000 + TransferValue = 100000 + GetArgument = 1000 + GetFunction = 1000 + GetNumArguments = 1000 + StorageStore = 75000 + StorageLoad = 50000 + CachedStorageLoad = 1000 + GetCaller = 1000 + GetCallValue = 1000 + Log = 3750 + Finish = 1 + SignalError = 1 + GetBlockTimeStamp = 10000 + GetGasLeft = 1000 + Int64GetArgument = 1000 + Int64StorageStore = 75000 + Int64StorageLoad = 50000 + Int64Finish = 1000 + GetStateRootHash = 10000 + GetBlockNonce = 10000 + GetBlockEpoch = 10000 + GetBlockRound = 10000 + GetBlockRandomSeed = 10000 + ExecuteOnSameContext = 100000 + ExecuteOnDestContext = 100000 + DelegateExecution = 100000 + AsyncCallStep = 100000 + AsyncCallbackGasLock = 4000000 + ExecuteReadOnly = 160000 + CreateContract = 300000 + GetReturnData = 1000 + GetNumReturnData = 1000 + GetReturnDataSize = 1000 + GetOriginalTxHash = 10000 + CleanReturnData = 1000 + DeleteFromReturnData = 1000 + GetPrevTxHash = 10000 + GetCurrentTxHash = 10000 + CreateAsyncCall = 200000 + SetAsyncCallback = 100000 + SetAsyncGroupCallback = 100000 + SetAsyncContextCallback = 100000 + GetCallbackClosure = 10000 + GetCodeMetadata = 10000 + IsBuiltinFunction = 10000 + IsReservedFunctionName = 10000 + +[EthAPICost] + UseGas = 100 + GetAddress = 100000 + GetExternalBalance = 70000 + GetBlockHash = 100000 + Call = 160000 + CallDataCopy = 200 + GetCallDataSize = 100 + CallCode = 160000 + CallDelegate = 160000 + CallStatic = 160000 + StorageStore = 250000 + StorageLoad = 100000 + GetCaller = 100 + GetCallValue = 100 + CodeCopy = 1000 + GetCodeSize = 100 + GetBlockCoinbase = 100 + Create = 320000 + GetBlockDifficulty = 100 + ExternalCodeCopy = 3000 + GetExternalCodeSize = 2500 + GetGasLeft = 100 + GetBlockGasLimit = 100000 + GetTxGasPrice = 1000 + Log = 3750 + GetBlockNumber = 100000 + GetTxOrigin = 100000 + Finish = 1 + Revert = 1 + GetReturnDataSize = 200 + ReturnDataCopy = 500 + SelfDestruct = 5000000 + GetBlockTimeStamp = 100000 + +[BigIntAPICost] + BigIntNew = 2000 + BigIntByteLength = 2000 + BigIntUnsignedByteLength = 2000 + BigIntSignedByteLength = 2000 + BigIntGetBytes = 2000 + BigIntGetUnsignedBytes = 2000 + BigIntGetSignedBytes = 2000 + BigIntSetBytes = 2000 + BigIntSetUnsignedBytes = 2000 + BigIntSetSignedBytes = 2000 + BigIntIsInt64 = 2000 + BigIntGetInt64 = 2000 + BigIntSetInt64 = 2000 + BigIntAdd = 2000 + BigIntSub = 2000 + BigIntMul = 6000 + BigIntSqrt = 6000 + BigIntPow = 6000 + BigIntLog = 6000 + BigIntTDiv = 6000 + BigIntTMod = 6000 + BigIntEDiv = 6000 + BigIntEMod = 6000 + BigIntAbs = 2000 + BigIntNeg = 2000 + BigIntSign = 2000 + BigIntCmp = 2000 + BigIntNot = 2000 + BigIntAnd = 2000 + BigIntOr = 2000 + BigIntXor = 2000 + BigIntShr = 2000 + BigIntShl = 2000 + BigIntFinishUnsigned = 1000 + BigIntFinishSigned = 1000 + BigIntStorageLoadUnsigned = 50000 + BigIntStorageStoreUnsigned = 75000 + BigIntGetArgument = 1000 + BigIntGetUnsignedArgument = 1000 + BigIntGetSignedArgument = 1000 + BigIntGetCallValue = 1000 + BigIntGetExternalBalance = 10000 + CopyPerByteForTooBig = 1000 + +[CryptoAPICost] + SHA256 = 1000000 + Keccak256 = 1000000 + Ripemd160 = 1000000 + VerifyBLS = 5000000 + VerifyEd25519 = 2000000 + VerifySecp256k1 = 2000000 + EllipticCurveNew = 10000 + AddECC = 75000 + DoubleECC = 65000 + IsOnCurveECC = 10000 + ScalarMultECC = 400000 + MarshalECC = 13000 + MarshalCompressedECC = 15000 + UnmarshalECC = 20000 + UnmarshalCompressedECC = 270000 + GenerateKeyECC = 7000000 + EncodeDERSig = 10000000 + VerifySecp256r1 = 2000000 + VerifyBLSSignatureShare = 2000000 + VerifyBLSMultiSig = 2000000 + +[ManagedBufferAPICost] + MBufferNew = 2000 + MBufferNewFromBytes = 2000 + MBufferGetLength = 2000 + MBufferGetBytes = 2000 + MBufferGetByteSlice = 2000 + MBufferCopyByteSlice = 2000 + MBufferSetBytes = 2000 + MBufferAppend = 2000 + MBufferAppendBytes = 2000 + MBufferToBigIntUnsigned = 2000 + MBufferToBigIntSigned = 5000 + MBufferFromBigIntUnsigned = 2000 + MBufferFromBigIntSigned = 5000 + MBufferStorageStore = 75000 + MBufferStorageLoad = 50000 + MBufferGetArgument = 1000 + MBufferFinish = 1000 + MBufferSetRandom = 6000 + MBufferToBigFloat = 2000 + MBufferFromBigFloat = 2000 + +[BigFloatAPICost] + BigFloatNewFromParts = 3000 + BigFloatAdd = 7000 + BigFloatSub = 7000 + BigFloatMul = 7000 + BigFloatDiv = 7000 + BigFloatTruncate = 5000 + BigFloatNeg = 5000 + BigFloatClone = 5000 + BigFloatCmp = 4000 + BigFloatAbs = 5000 + BigFloatSqrt = 7000 + BigFloatPow = 10000 + BigFloatFloor = 5000 + BigFloatCeil = 5000 + BigFloatIsInt = 3000 + BigFloatSetBigInt = 3000 + BigFloatSetInt64 = 1000 + BigFloatGetConst = 1000 + +[WASMOpcodeCost] + Unreachable = 5 + Nop = 5 + Block = 5 + Loop = 5 + If = 5 + Else = 5 + End = 5 + Br = 5 + BrIf = 5 + BrTable = 5 + Return = 5 + Call = 5 + CallIndirect = 5 + Drop = 5 + Select = 5 + TypedSelect = 5 + LocalGet = 5 + LocalSet = 5 + LocalTee = 5 + GlobalGet = 5 + GlobalSet = 5 + I32Load = 5 + I64Load = 5 + F32Load = 6 + F64Load = 6 + I32Load8S = 5 + I32Load8U = 5 + I32Load16S = 5 + I32Load16U = 5 + I64Load8S = 5 + I64Load8U = 5 + I64Load16S = 5 + I64Load16U = 5 + I64Load32S = 5 + I64Load32U = 5 + I32Store = 5 + I64Store = 5 + F32Store = 12 + F64Store = 12 + I32Store8 = 5 + I32Store16 = 5 + I64Store8 = 5 + I64Store16 = 5 + I64Store32 = 5 + MemorySize = 5 + MemoryGrow = 1000000 + I32Const = 5 + I64Const = 5 + F32Const = 5 + F64Const = 5 + RefNull = 5 + RefIsNull = 5 + RefFunc = 5 + I32Eqz = 5 + I32Eq = 5 + I32Ne = 5 + I32LtS = 5 + I32LtU = 5 + I32GtS = 5 + I32GtU = 5 + I32LeS = 5 + I32LeU = 5 + I32GeS = 5 + I32GeU = 5 + I64Eqz = 5 + I64Eq = 5 + I64Ne = 5 + I64LtS = 5 + I64LtU = 5 + I64GtS = 5 + I64GtU = 5 + I64LeS = 5 + I64LeU = 5 + I64GeS = 5 + I64GeU = 5 + F32Eq = 6 + F32Ne = 6 + F32Lt = 6 + F32Gt = 6 + F32Le = 6 + F32Ge = 6 + F64Eq = 6 + F64Ne = 6 + F64Lt = 6 + F64Gt = 6 + F64Le = 6 + F64Ge = 6 + I32Clz = 100 + I32Ctz = 100 + I32Popcnt = 100 + I32Add = 5 + I32Sub = 5 + I32Mul = 5 + I32DivS = 18 + I32DivU = 18 + I32RemS = 18 + I32RemU = 18 + I32And = 5 + I32Or = 5 + I32Xor = 5 + I32Shl = 5 + I32ShrS = 5 + I32ShrU = 5 + I32Rotl = 5 + I32Rotr = 5 + I64Clz = 100 + I64Ctz = 100 + I64Popcnt = 100 + I64Add = 5 + I64Sub = 5 + I64Mul = 5 + I64DivS = 18 + I64DivU = 18 + I64RemS = 18 + I64RemU = 18 + I64And = 5 + I64Or = 5 + I64Xor = 5 + I64Shl = 5 + I64ShrS = 5 + I64ShrU = 5 + I64Rotl = 5 + I64Rotr = 5 + F32Abs = 5 + F32Neg = 5 + F32Ceil = 100 + F32Floor = 100 + F32Trunc = 100 + F32Nearest = 100 + F32Sqrt = 100 + F32Add = 5 + F32Sub = 5 + F32Mul = 15 + F32Div = 100 + F32Min = 15 + F32Max = 15 + F32Copysign = 5 + F64Abs = 5 + F64Neg = 5 + F64Ceil = 100 + F64Floor = 100 + F64Trunc = 100 + F64Nearest = 100 + F64Sqrt = 100 + F64Add = 5 + F64Sub = 5 + F64Mul = 15 + F64Div = 100 + F64Min = 15 + F64Max = 15 + F64Copysign = 5 + I32WrapI64 = 9 + I32TruncF32S = 100 + I32TruncF32U = 100 + I32TruncF64S = 100 + I32TruncF64U = 100 + I64ExtendI32S = 9 + I64ExtendI32U = 9 + I64TruncF32S = 100 + I64TruncF32U = 100 + I64TruncF64S = 100 + I64TruncF64U = 100 + F32ConvertI32S = 100 + F32ConvertI32U = 100 + F32ConvertI64S = 100 + F32ConvertI64U = 100 + F32DemoteF64 = 100 + F64ConvertI32S = 100 + F64ConvertI32U = 100 + F64ConvertI64S = 100 + F64ConvertI64U = 100 + F64PromoteF32 = 100 + I32ReinterpretF32 = 100 + I64ReinterpretF64 = 100 + F32ReinterpretI32 = 100 + F64ReinterpretI64 = 100 + I32Extend8S = 9 + I32Extend16S = 9 + I64Extend8S = 9 + I64Extend16S = 9 + I64Extend32S = 9 + I32TruncSatF32S = 100 + I32TruncSatF32U = 100 + I32TruncSatF64S = 100 + I32TruncSatF64U = 100 + I64TruncSatF32S = 100 + I64TruncSatF32U = 100 + I64TruncSatF64S = 100 + I64TruncSatF64U = 100 + MemoryInit = 5 + DataDrop = 5 + MemoryCopy = 5 + MemoryFill = 5 + TableInit = 10 + ElemDrop = 10 + TableCopy = 10 + TableFill = 10 + TableGet = 10 + TableSet = 10 + TableGrow = 10 + TableSize = 10 + AtomicNotify = 1000000 + I32AtomicWait = 1000000 + I64AtomicWait = 1000000 + AtomicFence = 1000000 + I32AtomicLoad = 1000000 + I64AtomicLoad = 1000000 + I32AtomicLoad8U = 1000000 + I32AtomicLoad16U = 1000000 + I64AtomicLoad8U = 1000000 + I64AtomicLoad16U = 1000000 + I64AtomicLoad32U = 1000000 + I32AtomicStore = 1000000 + I64AtomicStore = 1000000 + I32AtomicStore8 = 1000000 + I32AtomicStore16 = 1000000 + I64AtomicStore8 = 1000000 + I64AtomicStore16 = 1000000 + I64AtomicStore32 = 1000000 + I32AtomicRmwAdd = 1000000 + I64AtomicRmwAdd = 1000000 + I32AtomicRmw8AddU = 1000000 + I32AtomicRmw16AddU = 1000000 + I64AtomicRmw8AddU = 1000000 + I64AtomicRmw16AddU = 1000000 + I64AtomicRmw32AddU = 1000000 + I32AtomicRmwSub = 1000000 + I64AtomicRmwSub = 1000000 + I32AtomicRmw8SubU = 1000000 + I32AtomicRmw16SubU = 1000000 + I64AtomicRmw8SubU = 1000000 + I64AtomicRmw16SubU = 1000000 + I64AtomicRmw32SubU = 1000000 + I32AtomicRmwAnd = 1000000 + I64AtomicRmwAnd = 1000000 + I32AtomicRmw8AndU = 1000000 + I32AtomicRmw16AndU = 1000000 + I64AtomicRmw8AndU = 1000000 + I64AtomicRmw16AndU = 1000000 + I64AtomicRmw32AndU = 1000000 + I32AtomicRmwOr = 1000000 + I64AtomicRmwOr = 1000000 + I32AtomicRmw8OrU = 1000000 + I32AtomicRmw16OrU = 1000000 + I64AtomicRmw8OrU = 1000000 + I64AtomicRmw16OrU = 1000000 + I64AtomicRmw32OrU = 1000000 + I32AtomicRmwXor = 1000000 + I64AtomicRmwXor = 1000000 + I32AtomicRmw8XorU = 1000000 + I32AtomicRmw16XorU = 1000000 + I64AtomicRmw8XorU = 1000000 + I64AtomicRmw16XorU = 1000000 + I64AtomicRmw32XorU = 1000000 + I32AtomicRmwXchg = 1000000 + I64AtomicRmwXchg = 1000000 + I32AtomicRmw8XchgU = 1000000 + I32AtomicRmw16XchgU = 1000000 + I64AtomicRmw8XchgU = 1000000 + I64AtomicRmw16XchgU = 1000000 + I64AtomicRmw32XchgU = 1000000 + I32AtomicRmwCmpxchg = 1000000 + I64AtomicRmwCmpxchg = 1000000 + I32AtomicRmw8CmpxchgU = 1000000 + I32AtomicRmw16CmpxchgU = 1000000 + I64AtomicRmw8CmpxchgU = 1000000 + I64AtomicRmw16CmpxchgU = 1000000 + I64AtomicRmw32CmpxchgU = 1000000 + V128Load = 1000000 + V128Store = 1000000 + V128Const = 1000000 + I8x16Splat = 1000000 + I8x16ExtractLaneS = 1000000 + I8x16ExtractLaneU = 1000000 + I8x16ReplaceLane = 1000000 + I16x8Splat = 1000000 + I16x8ExtractLaneS = 1000000 + I16x8ExtractLaneU = 1000000 + I16x8ReplaceLane = 1000000 + I32x4Splat = 1000000 + I32x4ExtractLane = 1000000 + I32x4ReplaceLane = 1000000 + I64x2Splat = 1000000 + I64x2ExtractLane = 1000000 + I64x2ReplaceLane = 1000000 + F32x4Splat = 1000000 + F32x4ExtractLane = 1000000 + F32x4ReplaceLane = 1000000 + F64x2Splat = 1000000 + F64x2ExtractLane = 1000000 + F64x2ReplaceLane = 1000000 + I8x16Eq = 1000000 + I8x16Ne = 1000000 + I8x16LtS = 1000000 + I8x16LtU = 1000000 + I8x16GtS = 1000000 + I8x16GtU = 1000000 + I8x16LeS = 1000000 + I8x16LeU = 1000000 + I8x16GeS = 1000000 + I8x16GeU = 1000000 + I16x8Eq = 1000000 + I16x8Ne = 1000000 + I16x8LtS = 1000000 + I16x8LtU = 1000000 + I16x8GtS = 1000000 + I16x8GtU = 1000000 + I16x8LeS = 1000000 + I16x8LeU = 1000000 + I16x8GeS = 1000000 + I16x8GeU = 1000000 + I32x4Eq = 1000000 + I32x4Ne = 1000000 + I32x4LtS = 1000000 + I32x4LtU = 1000000 + I32x4GtS = 1000000 + I32x4GtU = 1000000 + I32x4LeS = 1000000 + I32x4LeU = 1000000 + I32x4GeS = 1000000 + I32x4GeU = 1000000 + F32x4Eq = 1000000 + F32x4Ne = 1000000 + F32x4Lt = 1000000 + F32x4Gt = 1000000 + F32x4Le = 1000000 + F32x4Ge = 1000000 + F64x2Eq = 1000000 + F64x2Ne = 1000000 + F64x2Lt = 1000000 + F64x2Gt = 1000000 + F64x2Le = 1000000 + F64x2Ge = 1000000 + V128Not = 1000000 + V128And = 1000000 + V128AndNot = 1000000 + V128Or = 1000000 + V128Xor = 1000000 + V128Bitselect = 1000000 + I8x16Neg = 1000000 + I8x16AnyTrue = 1000000 + I8x16AllTrue = 1000000 + I8x16Shl = 1000000 + I8x16ShrS = 1000000 + I8x16ShrU = 1000000 + I8x16Add = 1000000 + I8x16AddSaturateS = 1000000 + I8x16AddSaturateU = 1000000 + I8x16Sub = 1000000 + I8x16SubSaturateS = 1000000 + I8x16SubSaturateU = 1000000 + I8x16MinS = 1000000 + I8x16MinU = 1000000 + I8x16MaxS = 1000000 + I8x16MaxU = 1000000 + I8x16Mul = 1000000 + I16x8Neg = 1000000 + I16x8AnyTrue = 1000000 + I16x8AllTrue = 1000000 + I16x8Shl = 1000000 + I16x8ShrS = 1000000 + I16x8ShrU = 1000000 + I16x8Add = 1000000 + I16x8AddSaturateS = 1000000 + I16x8AddSaturateU = 1000000 + I16x8Sub = 1000000 + I16x8SubSaturateS = 1000000 + I16x8SubSaturateU = 1000000 + I16x8Mul = 1000000 + I16x8MinS = 1000000 + I16x8MinU = 1000000 + I16x8MaxS = 1000000 + I16x8MaxU = 1000000 + I32x4Neg = 1000000 + I32x4AnyTrue = 1000000 + I32x4AllTrue = 1000000 + I32x4Shl = 1000000 + I32x4ShrS = 1000000 + I32x4ShrU = 1000000 + I32x4Add = 1000000 + I32x4Sub = 1000000 + I32x4Mul = 1000000 + I32x4MinS = 1000000 + I32x4MinU = 1000000 + I32x4MaxS = 1000000 + I32x4MaxU = 1000000 + I64x2Neg = 1000000 + I64x2AnyTrue = 1000000 + I64x2AllTrue = 1000000 + I64x2Shl = 1000000 + I64x2ShrS = 1000000 + I64x2ShrU = 1000000 + I64x2Add = 1000000 + I64x2Sub = 1000000 + I64x2Mul = 1000000 + F32x4Abs = 1000000 + F32x4Neg = 1000000 + F32x4Sqrt = 1000000 + F32x4Add = 1000000 + F32x4Sub = 1000000 + F32x4Mul = 1000000 + F32x4Div = 1000000 + F32x4Min = 1000000 + F32x4Max = 1000000 + F64x2Abs = 1000000 + F64x2Neg = 1000000 + F64x2Sqrt = 1000000 + F64x2Add = 1000000 + F64x2Sub = 1000000 + F64x2Mul = 1000000 + F64x2Div = 1000000 + F64x2Min = 1000000 + F64x2Max = 1000000 + I32x4TruncSatF32x4S = 1000000 + I32x4TruncSatF32x4U = 1000000 + I64x2TruncSatF64x2S = 1000000 + I64x2TruncSatF64x2U = 1000000 + F32x4ConvertI32x4S = 1000000 + F32x4ConvertI32x4U = 1000000 + F64x2ConvertI64x2S = 1000000 + F64x2ConvertI64x2U = 1000000 + V8x16Swizzle = 1000000 + V8x16Shuffle = 1000000 + V8x16LoadSplat = 1000000 + V16x8LoadSplat = 1000000 + V32x4LoadSplat = 1000000 + V64x2LoadSplat = 1000000 + I8x16NarrowI16x8S = 1000000 + I8x16NarrowI16x8U = 1000000 + I16x8NarrowI32x4S = 1000000 + I16x8NarrowI32x4U = 1000000 + I16x8WidenLowI8x16S = 1000000 + I16x8WidenHighI8x16S = 1000000 + I16x8WidenLowI8x16U = 1000000 + I16x8WidenHighI8x16U = 1000000 + I32x4WidenLowI16x8S = 1000000 + I32x4WidenHighI16x8S = 1000000 + I32x4WidenLowI16x8U = 1000000 + I32x4WidenHighI16x8U = 1000000 + I16x8Load8x8S = 1000000 + I16x8Load8x8U = 1000000 + I32x4Load16x4S = 1000000 + I32x4Load16x4U = 1000000 + I64x2Load32x2S = 1000000 + I64x2Load32x2U = 1000000 + I8x16RoundingAverageU = 1000000 + I16x8RoundingAverageU = 1000000 + LocalAllocate = 5 + LocalsUnmetered = 100 + MaxMemoryGrowDelta = 1 + MaxMemoryGrow = 10 + Catch = 10 + CatchAll = 10 + Delegate = 10 + Rethrow = 10 + ReturnCall = 10 + ReturnCallIndirect = 10 + Throw = 10 + Try = 10 + Unwind = 10 + F32x4Ceil = 1000000 + F32x4DemoteF64x2Zero = 1000000 + F32x4Floor = 1000000 + F32x4Nearest = 1000000 + F32x4PMax = 1000000 + F32x4PMin = 1000000 + F32x4Trunc = 1000000 + F64x2Ceil = 1000000 + F64x2ConvertLowI32x4S = 1000000 + F64x2ConvertLowI32x4U = 1000000 + F64x2Floor = 1000000 + F64x2Nearest = 1000000 + F64x2PMax = 1000000 + F64x2PMin = 1000000 + F64x2PromoteLowF32x4 = 1000000 + F64x2Trunc = 1000000 + I16x8Abs = 1000000 + I16x8AddSatS = 1000000 + I16x8AddSatU = 1000000 + I16x8Bitmask = 1000000 + I16x8ExtAddPairwiseI8x16S = 1000000 + I16x8ExtAddPairwiseI8x16U = 1000000 + I16x8ExtMulHighI8x16S = 1000000 + I16x8ExtMulHighI8x16U = 1000000 + I16x8ExtMulLowI8x16S = 1000000 + I16x8ExtMulLowI8x16U = 1000000 + I16x8ExtendHighI8x16S = 1000000 + I16x8ExtendHighI8x16U = 1000000 + I16x8ExtendLowI8x16S = 1000000 + I16x8ExtendLowI8x16U = 1000000 + I16x8Q15MulrSatS = 1000000 + I16x8SubSatS = 1000000 + I16x8SubSatU = 1000000 + I32x4Abs = 1000000 + I32x4Bitmask = 1000000 + I32x4DotI16x8S = 1000000 + I32x4ExtAddPairwiseI16x8S = 1000000 + I32x4ExtAddPairwiseI16x8U = 1000000 + I32x4ExtMulHighI16x8S = 1000000 + I32x4ExtMulHighI16x8U = 1000000 + I32x4ExtMulLowI16x8S = 1000000 + I32x4ExtMulLowI16x8U = 1000000 + I32x4ExtendHighI16x8S = 1000000 + I32x4ExtendHighI16x8U = 1000000 + I32x4ExtendLowI16x8S = 1000000 + I32x4ExtendLowI16x8U = 1000000 + I32x4TruncSatF64x2SZero = 1000000 + I32x4TruncSatF64x2UZero = 1000000 + I64x2Abs = 1000000 + I64x2Bitmask = 1000000 + I64x2Eq = 1000000 + I64x2ExtMulHighI32x4S = 1000000 + I64x2ExtMulHighI32x4U = 1000000 + I64x2ExtMulLowI32x4S = 1000000 + I64x2ExtMulLowI32x4U = 1000000 + I64x2ExtendHighI32x4S = 1000000 + I64x2ExtendHighI32x4U = 1000000 + I64x2ExtendLowI32x4S = 1000000 + I64x2ExtendLowI32x4U = 1000000 + I64x2GeS = 1000000 + I64x2GtS = 1000000 + I64x2LeS = 1000000 + I64x2LtS = 1000000 + I64x2Ne = 1000000 + I8x16Abs = 1000000 + I8x16AddSatS = 1000000 + I8x16AddSatU = 1000000 + I8x16Bitmask = 1000000 + I8x16Popcnt = 1000000 + I8x16Shuffle = 1000000 + I8x16SubSatS = 1000000 + I8x16SubSatU = 1000000 + I8x16Swizzle = 1000000 + MemoryAtomicNotify = 1000000 + MemoryAtomicWait32 = 1000000 + MemoryAtomicWait64 = 1000000 + V128AnyTrue = 1000000 + V128Load16Lane = 1000000 + V128Load16Splat = 1000000 + V128Load16x4S = 1000000 + V128Load16x4U = 1000000 + V128Load32Lane = 1000000 + V128Load32Splat = 1000000 + V128Load32Zero = 1000000 + V128Load32x2S = 1000000 + V128Load32x2U = 1000000 + V128Load64Lane = 1000000 + V128Load64Splat = 1000000 + V128Load64Zero = 1000000 + V128Load8Lane = 1000000 + V128Load8Splat = 1000000 + V128Load8x8S = 1000000 + V128Load8x8U = 1000000 + V128Store16Lane = 1000000 + V128Store32Lane = 1000000 + V128Store64Lane = 1000000 + V128Store8Lane = 1000000 + +[MaxPerTransaction] + MaxBuiltInCallsPerTx = 100 + MaxNumberOfTransfersPerTx = 250 + MaxNumberOfTrieReadsPerTx = 1500 + +# Quadratic, Linear and Constant are the coefficients for a quadratic func. Separate variables are used for the +# sign of each coefficient, 0 meaning positive and 1 meaning negative +# The current values for the coefficients were computed based on benchmarking. +# For the given coefficients, the minimum of the function must not be lower than MinimumGasCost +[DynamicStorageLoad] + QuadraticCoefficient = 688 + SignOfQuadratic = 0 + LinearCoefficient = 31858 + SignOfLinear = 0 + ConstantCoefficient = 15287 + SignOfConstant = 0 + MinimumGasCost = 10000 diff --git a/common/constants.go b/common/constants.go index 83b4249b0d2..984dec87b07 100644 --- a/common/constants.go +++ b/common/constants.go @@ -495,6 +495,12 @@ const ( // MetricRelayedTransactionsV2EnableEpoch represents the epoch when the relayed transactions v2 is enabled MetricRelayedTransactionsV2EnableEpoch = "erd_relayed_transactions_v2_enable_epoch" + // MetricRelayedTransactionsV3EnableEpoch represents the epoch when the relayed transactions v3 is enabled + MetricRelayedTransactionsV3EnableEpoch = "erd_relayed_transactions_v3_enable_epoch" + + // MetricFixRelayedBaseCostEnableEpoch represents the epoch when the fix for relayed base cost is enabled + MetricFixRelayedBaseCostEnableEpoch = "erd_fix_relayed_base_cost_enable_epoch" + // MetricUnbondTokensV2EnableEpoch represents the epoch when the unbond tokens v2 is applied MetricUnbondTokensV2EnableEpoch = "erd_unbond_tokens_v2_enable_epoch" @@ -728,6 +734,9 @@ const ( // MetricCryptoOpcodesV2EnableEpoch represents the epoch when crypto opcodes v2 feature is enabled MetricCryptoOpcodesV2EnableEpoch = "erd_crypto_opcodes_v2_enable_epoch" + // MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch represents the epoch when enshrined sovereign opcodes are enabled + MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch = "erd_multi_esdt_transfer_execute_by_user_enable_epoch" + // MetricMaxNodesChangeEnableEpoch holds configuration for changing the maximum number of nodes and the enabling epoch MetricMaxNodesChangeEnableEpoch = "erd_max_nodes_change_enable_epoch" @@ -1220,5 +1229,9 @@ const ( DynamicESDTFlag core.EnableEpochFlag = "DynamicEsdtFlag" EGLDInESDTMultiTransferFlag core.EnableEpochFlag = "EGLDInESDTMultiTransferFlag" CryptoOpcodesV2Flag core.EnableEpochFlag = "CryptoOpcodesV2Flag" + UnJailCleanupFlag core.EnableEpochFlag = "UnJailCleanupFlag" + RelayedTransactionsV3Flag core.EnableEpochFlag = "RelayedTransactionsV3Flag" + FixRelayedBaseCostFlag core.EnableEpochFlag = "FixRelayedBaseCostFlag" + MultiESDTNFTTransferAndExecuteByUserFlag core.EnableEpochFlag = "MultiESDTNFTTransferAndExecuteByUserFlag" // 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 24962e09030..d3df21b6bbb 100644 --- a/common/enablers/enableEpochsHandler.go +++ b/common/enablers/enableEpochsHandler.go @@ -750,6 +750,30 @@ func (handler *enableEpochsHandler) createAllFlagsMap() { }, activationEpoch: handler.enableEpochsConfig.CryptoOpcodesV2EnableEpoch, }, + common.UnJailCleanupFlag: { + isActiveInEpoch: func(epoch uint32) bool { + return epoch >= handler.enableEpochsConfig.UnJailCleanupEnableEpoch + }, + activationEpoch: handler.enableEpochsConfig.UnJailCleanupEnableEpoch, + }, + common.RelayedTransactionsV3Flag: { + isActiveInEpoch: func(epoch uint32) bool { + return epoch >= handler.enableEpochsConfig.RelayedTransactionsV3EnableEpoch + }, + activationEpoch: handler.enableEpochsConfig.RelayedTransactionsV3EnableEpoch, + }, + common.FixRelayedBaseCostFlag: { + isActiveInEpoch: func(epoch uint32) bool { + return epoch >= handler.enableEpochsConfig.FixRelayedBaseCostEnableEpoch + }, + activationEpoch: handler.enableEpochsConfig.FixRelayedBaseCostEnableEpoch, + }, + common.MultiESDTNFTTransferAndExecuteByUserFlag: { + isActiveInEpoch: func(epoch uint32) bool { + return epoch >= handler.enableEpochsConfig.MultiESDTNFTTransferAndExecuteByUserEnableEpoch + }, + activationEpoch: handler.enableEpochsConfig.MultiESDTNFTTransferAndExecuteByUserEnableEpoch, + }, } } diff --git a/common/enablers/enableEpochsHandler_test.go b/common/enablers/enableEpochsHandler_test.go index 524fe924771..72fafc5a689 100644 --- a/common/enablers/enableEpochsHandler_test.go +++ b/common/enablers/enableEpochsHandler_test.go @@ -115,10 +115,13 @@ func createEnableEpochsConfig() config.EnableEpochs { StakingV4Step2EnableEpoch: 98, StakingV4Step3EnableEpoch: 99, AlwaysMergeContextsInEEIEnableEpoch: 100, - CleanupAuctionOnLowWaitingListEnableEpoch: 101, + CleanupAuctionOnLowWaitingListEnableEpoch: 101, DynamicESDTEnableEpoch: 102, EGLDInMultiTransferEnableEpoch: 103, CryptoOpcodesV2EnableEpoch: 104, + RelayedTransactionsV3EnableEpoch: 105, + FixRelayedBaseCostEnableEpoch: 106, + MultiESDTNFTTransferAndExecuteByUserEnableEpoch: 107, } } @@ -319,6 +322,8 @@ func TestEnableEpochsHandler_IsFlagEnabled(t *testing.T) { require.True(t, handler.IsFlagEnabled(common.StakingV4StartedFlag)) require.True(t, handler.IsFlagEnabled(common.AlwaysMergeContextsInEEIFlag)) require.True(t, handler.IsFlagEnabled(common.DynamicESDTFlag)) + require.True(t, handler.IsFlagEnabled(common.RelayedTransactionsV3Flag)) + require.True(t, handler.IsFlagEnabled(common.FixRelayedBaseCostFlag)) } func TestEnableEpochsHandler_GetActivationEpoch(t *testing.T) { @@ -438,6 +443,9 @@ func TestEnableEpochsHandler_GetActivationEpoch(t *testing.T) { require.Equal(t, cfg.DynamicESDTEnableEpoch, handler.GetActivationEpoch(common.DynamicESDTFlag)) require.Equal(t, cfg.EGLDInMultiTransferEnableEpoch, handler.GetActivationEpoch(common.EGLDInESDTMultiTransferFlag)) require.Equal(t, cfg.CryptoOpcodesV2EnableEpoch, handler.GetActivationEpoch(common.CryptoOpcodesV2Flag)) + require.Equal(t, cfg.RelayedTransactionsV3EnableEpoch, handler.GetActivationEpoch(common.RelayedTransactionsV3Flag)) + require.Equal(t, cfg.FixRelayedBaseCostEnableEpoch, handler.GetActivationEpoch(common.FixRelayedBaseCostFlag)) + require.Equal(t, cfg.MultiESDTNFTTransferAndExecuteByUserEnableEpoch, handler.GetActivationEpoch(common.MultiESDTNFTTransferAndExecuteByUserFlag)) } func TestEnableEpochsHandler_IsInterfaceNil(t *testing.T) { diff --git a/common/reflectcommon/structFieldsUpdate.go b/common/reflectcommon/structFieldsUpdate.go index 94ad6002c07..be8671eff4f 100644 --- a/common/reflectcommon/structFieldsUpdate.go +++ b/common/reflectcommon/structFieldsUpdate.go @@ -123,6 +123,10 @@ func trySetTheNewValue(value *reflect.Value, newValue interface{}) error { structVal := reflect.ValueOf(newValue) return trySetStructValue(value, structVal) + case reflect.Map: + mapValue := reflect.ValueOf(newValue) + + return tryUpdateMapValue(value, mapValue) default: return fmt.Errorf("unsupported type <%s> when trying to set the value '%v' of type <%s>", valueKind, newValue, reflect.TypeOf(newValue)) } @@ -163,6 +167,31 @@ func trySetStructValue(value *reflect.Value, newValue reflect.Value) error { } } +func tryUpdateMapValue(value *reflect.Value, newValue reflect.Value) error { + if value.IsNil() { + value.Set(reflect.MakeMap(value.Type())) + } + + switch newValue.Kind() { + case reflect.Map: + for _, key := range newValue.MapKeys() { + item := newValue.MapIndex(key) + newItem := reflect.New(value.Type().Elem()).Elem() + + err := trySetTheNewValue(&newItem, item.Interface()) + if err != nil { + return err + } + + value.SetMapIndex(key, newItem) + } + default: + return fmt.Errorf("unsupported type <%s> when trying to add value in type <%s>", newValue.Kind(), value.Kind()) + } + + return nil +} + func updateStructFromMap(value *reflect.Value, newValue reflect.Value) error { for _, key := range newValue.MapKeys() { fieldName := key.String() diff --git a/common/reflectcommon/structFieldsUpdate_test.go b/common/reflectcommon/structFieldsUpdate_test.go index d2145ca8fa0..44d3ae7d694 100644 --- a/common/reflectcommon/structFieldsUpdate_test.go +++ b/common/reflectcommon/structFieldsUpdate_test.go @@ -5,9 +5,10 @@ import ( "reflect" "testing" - "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-go/config" "github.com/multiversx/mx-chain-go/testscommon/toml" + + "github.com/multiversx/mx-chain-core-go/core" "github.com/stretchr/testify/require" ) @@ -447,10 +448,10 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { expectedNewValue["first"] = 1 expectedNewValue["second"] = 2 - path := "TestMap.Value" + path := "TestInterface.Value" err = AdaptStructureValueBasedOnPath(testConfig, path, expectedNewValue) - require.Equal(t, "unsupported type when trying to set the value 'map[first:1 second:2]' of type ", err.Error()) + require.Equal(t, "unsupported type when trying to set the value 'map[first:1 second:2]' of type ", err.Error()) }) t.Run("should error fit signed for target type not int", func(t *testing.T) { @@ -517,11 +518,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI8.Int8.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[0].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[0].Path, overrideConfig.OverridableConfigTomlValues[0].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[0].Value, int64(testConfig.Int8.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[0].Value, int64(testConfig.Int8.Number)) }) t.Run("should error int8 value", func(t *testing.T) { @@ -533,9 +532,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI8.Int8.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[1].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[1].Path, overrideConfig.OverridableConfigTomlValues[1].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '128' of type to type ", err.Error()) }) @@ -549,11 +546,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI8.Int8.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[2].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[2].Path, overrideConfig.OverridableConfigTomlValues[2].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[2].Value, int64(testConfig.Int8.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[2].Value, int64(testConfig.Int8.Number)) }) t.Run("should error int8 negative value", func(t *testing.T) { @@ -565,9 +560,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI8.Int8.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[3].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[3].Path, overrideConfig.OverridableConfigTomlValues[3].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '-129' of type to type ", err.Error()) }) @@ -581,11 +574,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI16.Int16.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[4].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[4].Path, overrideConfig.OverridableConfigTomlValues[4].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[4].Value, int64(testConfig.Int16.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[4].Value, int64(testConfig.Int16.Number)) }) t.Run("should error int16 value", func(t *testing.T) { @@ -597,9 +588,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI16.Int16.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[5].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[5].Path, overrideConfig.OverridableConfigTomlValues[5].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '32768' of type to type ", err.Error()) }) @@ -613,11 +602,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI16.Int16.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[6].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[6].Path, overrideConfig.OverridableConfigTomlValues[6].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[6].Value, int64(testConfig.Int16.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[6].Value, int64(testConfig.Int16.Number)) }) t.Run("should error int16 negative value", func(t *testing.T) { @@ -629,9 +616,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI16.Int16.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[7].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[7].Path, overrideConfig.OverridableConfigTomlValues[7].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '-32769' of type to type ", err.Error()) }) @@ -645,11 +630,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI32.Int32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[17].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[8].Path, overrideConfig.OverridableConfigTomlValues[8].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[17].Value, int64(testConfig.Int32.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[8].Value, int64(testConfig.Int32.Number)) }) t.Run("should work and override int32 value with uint16", func(t *testing.T) { @@ -660,11 +643,11 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { expectedNewValue := uint16(10) - path := "TestConfigI32.Int32.Value" + path := "TestConfigI32.Int32.Number" err = AdaptStructureValueBasedOnPath(testConfig, path, expectedNewValue) require.NoError(t, err) - require.Equal(t, int32(expectedNewValue), testConfig.Int32.Value) + require.Equal(t, int32(expectedNewValue), testConfig.Int32.Number) }) t.Run("should error int32 value", func(t *testing.T) { @@ -676,9 +659,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI32.Int32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[9].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[9].Path, overrideConfig.OverridableConfigTomlValues[9].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '2147483648' of type to type ", err.Error()) }) @@ -692,11 +673,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI32.Int32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[10].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[10].Path, overrideConfig.OverridableConfigTomlValues[10].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[10].Value, int64(testConfig.Int32.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[10].Value, int64(testConfig.Int32.Number)) }) t.Run("should error int32 negative value", func(t *testing.T) { @@ -708,9 +687,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI32.Int32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[11].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[11].Path, overrideConfig.OverridableConfigTomlValues[11].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '-2147483649' of type to type ", err.Error()) }) @@ -724,11 +701,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI64.Int64.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[12].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[12].Path, overrideConfig.OverridableConfigTomlValues[12].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[12].Value, int64(testConfig.Int64.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[12].Value, int64(testConfig.Int64.Number)) }) t.Run("should work and override int64 negative value", func(t *testing.T) { @@ -740,11 +715,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigI64.Int64.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[13].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[13].Path, overrideConfig.OverridableConfigTomlValues[13].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[13].Value, int64(testConfig.Int64.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[13].Value, int64(testConfig.Int64.Number)) }) t.Run("should work and override uint8 value", func(t *testing.T) { @@ -756,11 +729,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU8.Uint8.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[14].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[14].Path, overrideConfig.OverridableConfigTomlValues[14].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[14].Value, int64(testConfig.Uint8.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[14].Value, int64(testConfig.Uint8.Number)) }) t.Run("should error uint8 value", func(t *testing.T) { @@ -772,9 +743,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU8.Uint8.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[15].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[15].Path, overrideConfig.OverridableConfigTomlValues[15].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '256' of type to type ", err.Error()) }) @@ -788,9 +757,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU8.Uint8.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[16].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[16].Path, overrideConfig.OverridableConfigTomlValues[16].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '-256' of type to type ", err.Error()) }) @@ -804,11 +771,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU16.Uint16.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[17].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[17].Path, overrideConfig.OverridableConfigTomlValues[17].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[17].Value, int64(testConfig.Uint16.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[17].Value, int64(testConfig.Uint16.Number)) }) t.Run("should error uint16 value", func(t *testing.T) { @@ -820,9 +785,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU16.Uint16.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[18].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[18].Path, overrideConfig.OverridableConfigTomlValues[18].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '65536' of type to type ", err.Error()) }) @@ -836,9 +799,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU16.Uint16.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[19].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[19].Path, overrideConfig.OverridableConfigTomlValues[19].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '-65536' of type to type ", err.Error()) }) @@ -852,11 +813,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU32.Uint32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[20].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[20].Path, overrideConfig.OverridableConfigTomlValues[20].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[20].Value, int64(testConfig.Uint32.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[20].Value, int64(testConfig.Uint32.Number)) }) t.Run("should error uint32 value", func(t *testing.T) { @@ -868,9 +827,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU32.Uint32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[21].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[21].Path, overrideConfig.OverridableConfigTomlValues[21].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '4294967296' of type to type ", err.Error()) }) @@ -884,9 +841,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU32.Uint32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[22].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[22].Path, overrideConfig.OverridableConfigTomlValues[22].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '-4294967296' of type to type ", err.Error()) }) @@ -900,11 +855,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU64.Uint64.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[23].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[23].Path, overrideConfig.OverridableConfigTomlValues[23].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[23].Value, int64(testConfig.Uint64.Value)) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[23].Value, int64(testConfig.Uint64.Number)) }) t.Run("should error uint64 negative value", func(t *testing.T) { @@ -916,9 +869,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigU64.Uint64.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[24].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[24].Path, overrideConfig.OverridableConfigTomlValues[24].Value) require.Equal(t, "unable to cast value '-9223372036854775808' of type to type ", err.Error()) }) @@ -931,11 +882,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigF32.Float32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[25].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[25].Path, overrideConfig.OverridableConfigTomlValues[25].Value) require.NoError(t, err) - require.Equal(t, float32(3.4), testConfig.Float32.Value) + require.Equal(t, float32(3.4), testConfig.Float32.Number) }) t.Run("should error float32 value", func(t *testing.T) { @@ -947,9 +896,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigF32.Float32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[26].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[26].Path, overrideConfig.OverridableConfigTomlValues[26].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '3.4e+39' of type to type ", err.Error()) }) @@ -963,11 +910,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigF32.Float32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[27].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[27].Path, overrideConfig.OverridableConfigTomlValues[27].Value) require.NoError(t, err) - require.Equal(t, float32(-3.4), testConfig.Float32.Value) + require.Equal(t, float32(-3.4), testConfig.Float32.Number) }) t.Run("should error float32 negative value", func(t *testing.T) { @@ -979,9 +924,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigF32.Float32.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[28].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[28].Path, overrideConfig.OverridableConfigTomlValues[28].Value) require.NotNil(t, err) require.Equal(t, "unable to cast value '-3.4e+40' of type to type ", err.Error()) }) @@ -995,11 +938,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigF64.Float64.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[29].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[29].Path, overrideConfig.OverridableConfigTomlValues[29].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[29].Value, testConfig.Float64.Value) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[29].Value, testConfig.Float64.Number) }) t.Run("should work and override float64 negative value", func(t *testing.T) { @@ -1011,11 +952,9 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigF64.Float64.Value" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[30].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[30].Path, overrideConfig.OverridableConfigTomlValues[30].Value) require.NoError(t, err) - require.Equal(t, overrideConfig.OverridableConfigTomlValues[30].Value, testConfig.Float64.Value) + require.Equal(t, overrideConfig.OverridableConfigTomlValues[30].Value, testConfig.Float64.Number) }) t.Run("should work and override struct", func(t *testing.T) { @@ -1027,13 +966,11 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigStruct.ConfigStruct.Description" - expectedNewValue := toml.Description{ Number: 11, } - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[31].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[31].Path, overrideConfig.OverridableConfigTomlValues[31].Value) require.NoError(t, err) require.Equal(t, expectedNewValue, testConfig.TestConfigStruct.ConfigStruct.Description) }) @@ -1047,9 +984,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigStruct.ConfigStruct.Description" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[32].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[32].Path, overrideConfig.OverridableConfigTomlValues[32].Value) require.Equal(t, "field not found or cannot be set", err.Error()) }) @@ -1062,9 +997,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigStruct.ConfigStruct.Description" - - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[33].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[33].Path, overrideConfig.OverridableConfigTomlValues[33].Value) require.Equal(t, "unable to cast value '11' of type to type ", err.Error()) }) @@ -1077,8 +1010,6 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigNestedStruct.ConfigNestedStruct" - expectedNewValue := toml.ConfigNestedStruct{ Text: "Overwritten text", Message: toml.Message{ @@ -1089,7 +1020,7 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { }, } - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[34].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[34].Path, overrideConfig.OverridableConfigTomlValues[34].Value) require.NoError(t, err) require.Equal(t, expectedNewValue, testConfig.TestConfigNestedStruct.ConfigNestedStruct) }) @@ -1103,14 +1034,12 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { overrideConfig, err := loadOverrideConfig("../../testscommon/toml/overwrite.toml") require.NoError(t, err) - path := "TestConfigNestedStruct.ConfigNestedStruct.Message.MessageDescription" - expectedNewValue := []toml.MessageDescription{ {Text: "Overwritten Text1"}, {Text: "Overwritten Text2"}, } - err = AdaptStructureValueBasedOnPath(testConfig, path, overrideConfig.OverridableConfigTomlValues[35].Value) + err = AdaptStructureValueBasedOnPath(testConfig, overrideConfig.OverridableConfigTomlValues[35].Path, overrideConfig.OverridableConfigTomlValues[35].Value) require.NoError(t, err) require.Equal(t, expectedNewValue, testConfig.TestConfigNestedStruct.ConfigNestedStruct.Message.MessageDescription) }) @@ -1193,6 +1122,88 @@ func TestAdaptStructureValueBasedOnPath(t *testing.T) { require.Equal(t, expectedNewValue, testConfig.TestConfigNestedStruct.ConfigNestedStruct.Message.MessageDescription) }) + t.Run("should work on map, override and insert from config", 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[36].Path, overrideConfig.OverridableConfigTomlValues[36].Value) + require.NoError(t, err) + require.Equal(t, 2, len(testConfig.TestMap.Map)) + require.Equal(t, 10, testConfig.TestMap.Map["Key1"].Number) + require.Equal(t, 11, testConfig.TestMap.Map["Key2"].Number) + }) + + t.Run("should work on map and insert from config", 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[37].Path, overrideConfig.OverridableConfigTomlValues[37].Value) + require.NoError(t, err) + require.Equal(t, 3, len(testConfig.TestMap.Map)) + require.Equal(t, 999, testConfig.TestMap.Map["Key1"].Number) + require.Equal(t, 2, testConfig.TestMap.Map["Key2"].Number) + require.Equal(t, 3, testConfig.TestMap.Map["Key3"].Number) + }) + + t.Run("should work on map, override and insert values in map", func(t *testing.T) { + t.Parallel() + + testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") + require.NoError(t, err) + + expectedNewValue := make(map[string]toml.MapValues) + expectedNewValue["Key1"] = toml.MapValues{Number: 100} + expectedNewValue["Key2"] = toml.MapValues{Number: 200} + + path := "TestMap.Map" + + err = AdaptStructureValueBasedOnPath(testConfig, path, expectedNewValue) + require.NoError(t, err) + require.Equal(t, 2, len(testConfig.TestMap.Map)) + require.Equal(t, 100, testConfig.TestMap.Map["Key1"].Number) + require.Equal(t, 200, testConfig.TestMap.Map["Key2"].Number) + }) + + t.Run("should error on map when override different map", func(t *testing.T) { + t.Parallel() + + testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") + require.NoError(t, err) + + expectedNewValue := make(map[string]toml.MessageDescription) + expectedNewValue["Key1"] = toml.MessageDescription{Text: "A"} + expectedNewValue["Key2"] = toml.MessageDescription{Text: "B"} + + path := "TestMap.Map" + + err = AdaptStructureValueBasedOnPath(testConfig, path, expectedNewValue) + require.Equal(t, "field not found or cannot be set", err.Error()) + }) + + t.Run("should error on map when override anything else other than map", func(t *testing.T) { + t.Parallel() + + testConfig, err := loadTestConfig("../../testscommon/toml/config.toml") + require.NoError(t, err) + + expectedNewValue := 1 + + path := "TestMap.Map" + + err = AdaptStructureValueBasedOnPath(testConfig, path, expectedNewValue) + require.Equal(t, "unsupported type when trying to add value in type ", err.Error()) + }) + } func loadTestConfig(filepath string) (*toml.Config, error) { diff --git a/config/config.go b/config/config.go index 49ef257c341..412ab59f776 100644 --- a/config/config.go +++ b/config/config.go @@ -228,6 +228,8 @@ type Config struct { PeersRatingConfig PeersRatingConfig PoolsCleanersConfig PoolsCleanersConfig Redundancy RedundancyConfig + + RelayedTransactionConfig RelayedTransactionConfig } // PeersRatingConfig will hold settings related to peers rating @@ -640,3 +642,8 @@ type PoolsCleanersConfig struct { type RedundancyConfig struct { MaxRoundsOfInactivityAccepted int } + +// RelayedTransactionConfig represents the config options to be used for relayed transactions +type RelayedTransactionConfig struct { + MaxTransactionsAllowed int +} diff --git a/config/epochConfig.go b/config/epochConfig.go index f53f2078f6d..7f965e3c5c5 100644 --- a/config/epochConfig.go +++ b/config/epochConfig.go @@ -117,6 +117,10 @@ type EnableEpochs struct { DynamicESDTEnableEpoch uint32 EGLDInMultiTransferEnableEpoch uint32 CryptoOpcodesV2EnableEpoch uint32 + UnJailCleanupEnableEpoch uint32 + RelayedTransactionsV3EnableEpoch uint32 + FixRelayedBaseCostEnableEpoch uint32 + MultiESDTNFTTransferAndExecuteByUserEnableEpoch uint32 BLSMultiSignerEnableEpoch []MultiSignerConfig } diff --git a/config/overridableConfig/configOverriding_test.go b/config/overridableConfig/configOverriding_test.go index 5e23a2bacda..9f187a8a501 100644 --- a/config/overridableConfig/configOverriding_test.go +++ b/config/overridableConfig/configOverriding_test.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-go/config" p2pConfig "github.com/multiversx/mx-chain-go/p2p/config" + "github.com/stretchr/testify/require" ) @@ -104,16 +105,15 @@ func TestOverrideConfigValues(t *testing.T) { }) t.Run("should work for enableRounds.toml", func(t *testing.T) { - // TODO: fix this test - t.Skip("skipped, as this test requires the fix from this PR: https://github.com/multiversx/mx-chain-go/pull/5851") - t.Parallel() configs := &config.Configs{RoundConfig: &config.RoundConfig{}} + value := make(map[string]config.ActivationRoundByName) + value["DisableAsyncCallV1"] = config.ActivationRoundByName{Round: "37"} - err := OverrideConfigValues([]config.OverridableConfig{{Path: "RoundActivations.DisableAsyncCallV1.Round", Value: "37", File: "enableRounds.toml"}}, configs) + err := OverrideConfigValues([]config.OverridableConfig{{Path: "RoundActivations", Value: value, File: "enableRounds.toml"}}, configs) require.NoError(t, err) - require.Equal(t, uint32(37), configs.RoundConfig.RoundActivations["DisableAsyncCallV1"]) + require.Equal(t, "37", configs.RoundConfig.RoundActivations["DisableAsyncCallV1"].Round) }) t.Run("should work for ratings.toml", func(t *testing.T) { diff --git a/config/tomlConfig_test.go b/config/tomlConfig_test.go index 97232f39f41..c6cecedc774 100644 --- a/config/tomlConfig_test.go +++ b/config/tomlConfig_test.go @@ -872,6 +872,15 @@ func TestEnableEpochConfig(t *testing.T) { # CryptoOpcodesV2EnableEpoch represents the epoch when BLSMultiSig, Secp256r1 and other opcodes are enabled CryptoOpcodesV2EnableEpoch = 98 + # RelayedTransactionsV3EnableEpoch represents the epoch when the relayed transactions V3 will be enabled + RelayedTransactionsV3EnableEpoch = 99 + + # FixRelayedBaseCostEnableEpoch represents the epoch when the fix for relayed base cost will be enabled + FixRelayedBaseCostEnableEpoch = 100 + + # MultiESDTNFTTransferAndExecuteByUserEnableEpoch represents the epoch when enshrined sovereign cross chain opcodes are enabled + MultiESDTNFTTransferAndExecuteByUserEnableEpoch = 101 + # MaxNodesChangeEnableEpoch holds configuration for changing the maximum number of nodes and the enabling epoch MaxNodesChangeEnableEpoch = [ { EpochEnable = 44, MaxNumNodes = 2169, NodesToShufflePerShard = 80 }, @@ -988,6 +997,9 @@ func TestEnableEpochConfig(t *testing.T) { DynamicESDTEnableEpoch: 96, EGLDInMultiTransferEnableEpoch: 97, CryptoOpcodesV2EnableEpoch: 98, + RelayedTransactionsV3EnableEpoch: 99, + FixRelayedBaseCostEnableEpoch: 100, + MultiESDTNFTTransferAndExecuteByUserEnableEpoch: 101, MaxNodesChangeEnableEpoch: []MaxNodesChangeConfig{ { EpochEnable: 44, diff --git a/dataRetriever/txpool/memorytests/memory_test.go b/dataRetriever/txpool/memorytests/memory_test.go index d2d48fbbcd5..a0484f016b8 100644 --- a/dataRetriever/txpool/memorytests/memory_test.go +++ b/dataRetriever/txpool/memorytests/memory_test.go @@ -36,25 +36,25 @@ func TestShardedTxPool_MemoryFootprint(t *testing.T) { journals = append(journals, runScenario(t, newScenario(200, 1, core.MegabyteSize, "0"), memoryAssertion{200, 200}, memoryAssertion{0, 1})) journals = append(journals, runScenario(t, newScenario(10, 1000, 20480, "0"), memoryAssertion{190, 205}, memoryAssertion{1, 4})) journals = append(journals, runScenario(t, newScenario(10000, 1, 1024, "0"), memoryAssertion{10, 16}, memoryAssertion{4, 10})) - journals = append(journals, runScenario(t, newScenario(1, 60000, 256, "0"), memoryAssertion{30, 36}, memoryAssertion{10, 16})) - journals = append(journals, runScenario(t, newScenario(10, 10000, 100, "0"), memoryAssertion{36, 46}, memoryAssertion{16, 24})) - journals = append(journals, runScenario(t, newScenario(100000, 1, 1024, "0"), memoryAssertion{120, 136}, memoryAssertion{56, 60})) + journals = append(journals, runScenario(t, newScenario(1, 60000, 256, "0"), memoryAssertion{30, 40}, memoryAssertion{10, 16})) + journals = append(journals, runScenario(t, newScenario(10, 10000, 100, "0"), memoryAssertion{36, 52}, memoryAssertion{16, 24})) + journals = append(journals, runScenario(t, newScenario(100000, 1, 1024, "0"), memoryAssertion{120, 138}, memoryAssertion{56, 60})) // With larger memory footprint - journals = append(journals, runScenario(t, newScenario(100000, 3, 650, "0"), memoryAssertion{290, 320}, memoryAssertion{95, 120})) - journals = append(journals, runScenario(t, newScenario(150000, 2, 650, "0"), memoryAssertion{290, 320}, memoryAssertion{120, 140})) - journals = append(journals, runScenario(t, newScenario(300000, 1, 650, "0"), memoryAssertion{290, 320}, memoryAssertion{170, 190})) - journals = append(journals, runScenario(t, newScenario(30, 10000, 650, "0"), memoryAssertion{290, 320}, memoryAssertion{60, 75})) - journals = append(journals, runScenario(t, newScenario(300, 1000, 650, "0"), memoryAssertion{290, 320}, memoryAssertion{60, 80})) + journals = append(journals, runScenario(t, newScenario(100000, 3, 650, "0"), memoryAssertion{290, 335}, memoryAssertion{95, 120})) + journals = append(journals, runScenario(t, newScenario(150000, 2, 650, "0"), memoryAssertion{290, 335}, memoryAssertion{120, 140})) + journals = append(journals, runScenario(t, newScenario(300000, 1, 650, "0"), memoryAssertion{290, 335}, memoryAssertion{170, 190})) + journals = append(journals, runScenario(t, newScenario(30, 10000, 650, "0"), memoryAssertion{290, 335}, memoryAssertion{60, 75})) + journals = append(journals, runScenario(t, newScenario(300, 1000, 650, "0"), memoryAssertion{290, 335}, memoryAssertion{60, 80})) // Scenarios where destination == me 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, 136}, memoryAssertion{16, 25})) - journals = append(journals, runScenario(t, newScenario(150000, 1, 128, "1_0"), memoryAssertion{50, 75}, memoryAssertion{30, 40})) - journals = append(journals, runScenario(t, newScenario(1, 150000, 128, "1_0"), memoryAssertion{50, 75}, memoryAssertion{30, 40})) + 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})) for _, journal := range journals { journal.displayFootprintsSummary() diff --git a/docker/keygenerator/Dockerfile b/docker/keygenerator/Dockerfile index c66a732e629..a73d7951d42 100644 --- a/docker/keygenerator/Dockerfile +++ b/docker/keygenerator/Dockerfile @@ -12,5 +12,4 @@ RUN go build FROM ubuntu:22.04 COPY --from=builder /go/mx-chain-go/cmd/keygenerator /go/mx-chain-go/cmd/keygenerator -WORKDIR /go/mx-chain-go/cmd/keygenerator/ -ENTRYPOINT ["./keygenerator"] +ENTRYPOINT ["/go/mx-chain-go/cmd/keygenerator/keygenerator"] diff --git a/docker/node/Dockerfile b/docker/node/Dockerfile index 2513f789dc8..2a341a8409b 100644 --- a/docker/node/Dockerfile +++ b/docker/node/Dockerfile @@ -7,15 +7,24 @@ RUN go mod tidy # Multiversx node WORKDIR /go/mx-chain-go/cmd/node RUN go build -v -ldflags="-X main.appVersion=$(git describe --tags --long --dirty)" -RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-v | sort -n | tail -n -1| awk -F '/' '{print$3}'| sed 's/ /@/g')/wasmer/libwasmer_linux_amd64.so /lib/libwasmer_linux_amd64.so -RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-go | sort -n | tail -n -1| awk -F '/' '{print$3}'| sed 's/ /@/g')/wasmer2/libvmexeccapi.so /lib/libvmexeccapi.so + +RUN mkdir -p /lib_amd64 /lib_arm64 + +RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-v | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer/libwasmer_linux_amd64.so /lib_amd64/ +RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-go | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer2/libvmexeccapi.so /lib_amd64/ + +RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-v | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer/libwasmer_linux_arm64_shim.so /lib_arm64/ +RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-go | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer2/libvmexeccapi_arm.so /lib_arm64/ # ===== SECOND STAGE ====== FROM ubuntu:22.04 +ARG TARGETARCH RUN apt-get update && apt-get upgrade -y COPY --from=builder "/go/mx-chain-go/cmd/node/node" "/go/mx-chain-go/cmd/node/" -COPY --from=builder "/lib/libwasmer_linux_amd64.so" "/lib/libwasmer_linux_amd64.so" -COPY --from=builder "/lib/libvmexeccapi.so" "/lib/libvmexeccapi.so" + +# Copy architecture-specific files +COPY --from=builder "/lib_${TARGETARCH}/*" "/lib/" + WORKDIR /go/mx-chain-go/cmd/node/ EXPOSE 8080 ENTRYPOINT ["/go/mx-chain-go/cmd/node/node"] diff --git a/docker/termui/Dockerfile b/docker/termui/Dockerfile index bcc670e3ce3..e22986033eb 100644 --- a/docker/termui/Dockerfile +++ b/docker/termui/Dockerfile @@ -4,11 +4,18 @@ WORKDIR /go/mx-chain-go COPY . . WORKDIR /go/mx-chain-go/cmd/termui RUN go build -v -RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-v | sort -n | tail -n -1| awk -F '/' '{print$3}'| sed 's/ /@/g')/wasmer/libwasmer_linux_amd64.so /lib/libwasmer_linux_amd64.so +RUN mkdir -p /lib_amd64 /lib_arm64 +RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-v | sort -n | tail -n -1| awk -F '/' '{print$3}'| sed 's/ /@/g')/wasmer/libwasmer_linux_amd64.so /lib_amd64/ +RUN cp /go/pkg/mod/github.com/multiversx/$(cat /go/mx-chain-go/go.mod | grep mx-chain-vm-v | sort -n | tail -n -1 | awk -F '/' '{print$3}' | sed 's/ /@/g')/wasmer/libwasmer_linux_arm64_shim.so /lib_arm64/ + # ===== SECOND STAGE ====== FROM ubuntu:22.04 +ARG TARGETARCH COPY --from=builder /go/mx-chain-go/cmd/termui /go/mx-chain-go/cmd/termui -COPY --from=builder "/lib/libwasmer_linux_amd64.so" "/lib/libwasmer_linux_amd64.so" + +# Copy architecture-specific files +COPY --from=builder "/lib_${TARGETARCH}/*" "/lib/" + WORKDIR /go/mx-chain-go/cmd/termui/ ENTRYPOINT ["./termui"] diff --git a/epochStart/bootstrap/factory/epochStartInterceptorsContainerFactory.go b/epochStart/bootstrap/factory/epochStartInterceptorsContainerFactory.go index d659989896b..0ebf8417d7b 100644 --- a/epochStart/bootstrap/factory/epochStartInterceptorsContainerFactory.go +++ b/epochStart/bootstrap/factory/epochStartInterceptorsContainerFactory.go @@ -14,6 +14,7 @@ import ( disabledFactory "github.com/multiversx/mx-chain-go/factory/disabled" disabledGenesis "github.com/multiversx/mx-chain-go/genesis/process/disabled" "github.com/multiversx/mx-chain-go/process" + processDisabled "github.com/multiversx/mx-chain-go/process/disabled" "github.com/multiversx/mx-chain-go/process/factory/interceptorscontainer" "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/storage/cache" @@ -108,6 +109,7 @@ func NewEpochStartInterceptorsContainer(args ArgsEpochStartInterceptorContainer) FullArchivePeerShardMapper: fullArchivePeerShardMapper, HardforkTrigger: hardforkTrigger, NodeOperationMode: args.NodeOperationMode, + RelayedTxV3Processor: processDisabled.NewRelayedTxV3Processor(), } interceptorsContainerFactory, err := interceptorscontainer.NewMetaInterceptorsContainerFactory(containerFactoryArgs) diff --git a/epochStart/bootstrap/process_test.go b/epochStart/bootstrap/process_test.go index 11a42a22301..552148003d6 100644 --- a/epochStart/bootstrap/process_test.go +++ b/epochStart/bootstrap/process_test.go @@ -221,7 +221,7 @@ func createMockEpochStartBootstrapArgs( RoundHandler: &mock.RoundHandlerStub{}, LatestStorageDataProvider: &mock.LatestStorageDataProviderStub{}, StorageUnitOpener: &storageMocks.UnitOpenerStub{}, - ArgumentsParser: &mock.ArgumentParserMock{}, + ArgumentsParser: &testscommon.ArgumentParserMock{}, StatusHandler: &statusHandlerMock.AppStatusHandlerStub{}, HeaderIntegrityVerifier: &mock.HeaderIntegrityVerifierStub{}, DataSyncerCreator: &scheduledDataSyncer.ScheduledSyncerFactoryStub{ diff --git a/errors/errors.go b/errors/errors.go index dd475327876..b1edc990afc 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -598,3 +598,6 @@ var ErrNilSentSignatureTracker = errors.New("nil sent signature tracker") // ErrNilEpochSystemSCProcessor defines the error for setting a nil EpochSystemSCProcessor var ErrNilEpochSystemSCProcessor = errors.New("nil epoch system SC processor") + +// ErrNilRelayedTxV3Processor signals that a nil relayed tx v3 processor has been provided +var ErrNilRelayedTxV3Processor = errors.New("nil relayed tx v3 processor") diff --git a/factory/disabled/txCoordinator.go b/factory/disabled/txCoordinator.go index e4ada3dc6ab..9d8002fb034 100644 --- a/factory/disabled/txCoordinator.go +++ b/factory/disabled/txCoordinator.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" + "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/processedMb" ) @@ -111,7 +112,7 @@ func (txCoordinator *TxCoordinator) VerifyCreatedMiniBlocks(_ data.HeaderHandler } // AddIntermediateTransactions does nothing as it is disabled -func (txCoordinator *TxCoordinator) AddIntermediateTransactions(_ map[block.Type][]data.TransactionHandler) error { +func (txCoordinator *TxCoordinator) AddIntermediateTransactions(_ map[block.Type][]data.TransactionHandler, _ []byte) error { return nil } diff --git a/factory/interface.go b/factory/interface.go index 0f1c237d0d9..ec92f478992 100644 --- a/factory/interface.go +++ b/factory/interface.go @@ -311,6 +311,7 @@ type ProcessComponentsHolder interface { ReceiptsRepository() ReceiptsRepository SentSignaturesTracker() process.SentSignaturesTracker EpochSystemSCProcessor() process.EpochStartSystemSCProcessor + RelayedTxV3Processor() process.RelayedTxV3Processor IsInterfaceNil() bool } diff --git a/factory/mock/processComponentsStub.go b/factory/mock/processComponentsStub.go index 32bbfaf2df3..4a52413b7cd 100644 --- a/factory/mock/processComponentsStub.go +++ b/factory/mock/processComponentsStub.go @@ -58,6 +58,7 @@ type ProcessComponentsMock struct { ReceiptsRepositoryInternal factory.ReceiptsRepository SentSignaturesTrackerInternal process.SentSignaturesTracker EpochSystemSCProcessorInternal process.EpochStartSystemSCProcessor + RelayedTxV3ProcessorField process.RelayedTxV3Processor } // Create - @@ -290,6 +291,11 @@ func (pcm *ProcessComponentsMock) EpochSystemSCProcessor() process.EpochStartSys return pcm.EpochSystemSCProcessorInternal } +// RelayedTxV3Processor - +func (pcm *ProcessComponentsMock) RelayedTxV3Processor() process.RelayedTxV3Processor { + return pcm.RelayedTxV3ProcessorField +} + // IsInterfaceNil - func (pcm *ProcessComponentsMock) IsInterfaceNil() bool { return pcm == nil diff --git a/factory/processing/blockProcessorCreator.go b/factory/processing/blockProcessorCreator.go index 4c952f4bb25..93f3e1e95a3 100644 --- a/factory/processing/blockProcessorCreator.go +++ b/factory/processing/blockProcessorCreator.go @@ -38,6 +38,7 @@ import ( "github.com/multiversx/mx-chain-go/process/smartContract/scrCommon" "github.com/multiversx/mx-chain-go/process/throttle" "github.com/multiversx/mx-chain-go/process/transaction" + "github.com/multiversx/mx-chain-go/process/transactionLog" "github.com/multiversx/mx-chain-go/state" "github.com/multiversx/mx-chain-go/state/syncer" "github.com/multiversx/mx-chain-go/storage/txcache" @@ -69,6 +70,7 @@ func (pcf *processComponentsFactory) newBlockProcessor( blockCutoffProcessingHandler cutoff.BlockProcessingCutoffHandler, missingTrieNodesNotifier common.MissingTrieNodesNotifier, sentSignaturesTracker process.SentSignaturesTracker, + relayedTxV3Processor process.RelayedTxV3Processor, ) (*blockProcessorAndVmFactories, error) { shardCoordinator := pcf.bootstrapComponents.ShardCoordinator() if shardCoordinator.SelfId() < shardCoordinator.NumberOfShards() { @@ -87,6 +89,7 @@ func (pcf *processComponentsFactory) newBlockProcessor( blockCutoffProcessingHandler, missingTrieNodesNotifier, sentSignaturesTracker, + relayedTxV3Processor, ) } if shardCoordinator.SelfId() == core.MetachainShardId { @@ -128,6 +131,7 @@ func (pcf *processComponentsFactory) newShardBlockProcessor( blockProcessingCutoffHandler cutoff.BlockProcessingCutoffHandler, missingTrieNodesNotifier common.MissingTrieNodesNotifier, sentSignaturesTracker process.SentSignaturesTracker, + relayedTxV3Processor process.RelayedTxV3Processor, ) (*blockProcessorAndVmFactories, error) { argsParser := smartContract.NewArgumentParser() @@ -224,6 +228,11 @@ func (pcf *processComponentsFactory) newShardBlockProcessor( return nil, err } + err = pcf.coreData.EconomicsData().SetTxTypeHandler(txTypeHandler) + if err != nil { + return nil, err + } + gasHandler, err := preprocess.NewGasComputation( pcf.coreData.EconomicsData(), txTypeHandler, @@ -233,30 +242,32 @@ func (pcf *processComponentsFactory) newShardBlockProcessor( return nil, err } + failedTxLogsAccumulator := transactionLog.NewFailedTxLogsAccumulator() txFeeHandler := postprocess.NewFeeAccumulator() argsNewScProcessor := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: vmContainer, - ArgsParser: argsParser, - Hasher: pcf.coreData.Hasher(), - Marshalizer: pcf.coreData.InternalMarshalizer(), - AccountsDB: pcf.state.AccountsAdapter(), - BlockChainHook: vmFactory.BlockChainHookImpl(), - BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), - PubkeyConv: pcf.coreData.AddressPubKeyConverter(), - ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), - ScrForwarder: scForwarder, - TxFeeHandler: txFeeHandler, - EconomicsFee: pcf.coreData.EconomicsData(), - GasHandler: gasHandler, - GasSchedule: pcf.gasSchedule, - TxLogsProcessor: pcf.txLogsProcessor, - TxTypeHandler: txTypeHandler, - IsGenesisProcessing: false, - BadTxForwarder: badTxInterim, - EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), - EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), - VMOutputCacher: txcache.NewDisabledCache(), - WasmVMChangeLocker: wasmVMChangeLocker, + VmContainer: vmContainer, + ArgsParser: argsParser, + Hasher: pcf.coreData.Hasher(), + Marshalizer: pcf.coreData.InternalMarshalizer(), + AccountsDB: pcf.state.AccountsAdapter(), + BlockChainHook: vmFactory.BlockChainHookImpl(), + BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), + PubkeyConv: pcf.coreData.AddressPubKeyConverter(), + ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), + ScrForwarder: scForwarder, + TxFeeHandler: txFeeHandler, + EconomicsFee: pcf.coreData.EconomicsData(), + GasHandler: gasHandler, + GasSchedule: pcf.gasSchedule, + TxLogsProcessor: pcf.txLogsProcessor, + TxTypeHandler: txTypeHandler, + IsGenesisProcessing: false, + BadTxForwarder: badTxInterim, + EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), + EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), + VMOutputCacher: txcache.NewDisabledCache(), + WasmVMChangeLocker: wasmVMChangeLocker, + FailedTxLogsAccumulator: failedTxLogsAccumulator, } scProcessorProxy, err := processProxy.NewSmartContractProcessorProxy(argsNewScProcessor, pcf.epochNotifier) @@ -274,25 +285,27 @@ func (pcf *processComponentsFactory) newShardBlockProcessor( } argsNewTxProcessor := transaction.ArgsNewTxProcessor{ - Accounts: pcf.state.AccountsAdapter(), - Hasher: pcf.coreData.Hasher(), - PubkeyConv: pcf.coreData.AddressPubKeyConverter(), - Marshalizer: pcf.coreData.InternalMarshalizer(), - SignMarshalizer: pcf.coreData.TxMarshalizer(), - ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), - ScProcessor: scProcessorProxy, - TxFeeHandler: txFeeHandler, - TxTypeHandler: txTypeHandler, - EconomicsFee: pcf.coreData.EconomicsData(), - ReceiptForwarder: receiptTxInterim, - BadTxForwarder: badTxInterim, - ArgsParser: argsParser, - ScrForwarder: scForwarder, - EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), - EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), - GuardianChecker: pcf.bootstrapComponents.GuardedAccountHandler(), - TxVersionChecker: pcf.coreData.TxVersionChecker(), - TxLogsProcessor: pcf.txLogsProcessor, + Accounts: pcf.state.AccountsAdapter(), + Hasher: pcf.coreData.Hasher(), + PubkeyConv: pcf.coreData.AddressPubKeyConverter(), + Marshalizer: pcf.coreData.InternalMarshalizer(), + SignMarshalizer: pcf.coreData.TxMarshalizer(), + ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), + ScProcessor: scProcessorProxy, + TxFeeHandler: txFeeHandler, + TxTypeHandler: txTypeHandler, + EconomicsFee: pcf.coreData.EconomicsData(), + ReceiptForwarder: receiptTxInterim, + BadTxForwarder: badTxInterim, + ArgsParser: argsParser, + ScrForwarder: scForwarder, + EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), + EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), + GuardianChecker: pcf.bootstrapComponents.GuardedAccountHandler(), + TxVersionChecker: pcf.coreData.TxVersionChecker(), + TxLogsProcessor: pcf.txLogsProcessor, + RelayedTxV3Processor: relayedTxV3Processor, + FailedTxLogsAccumulator: failedTxLogsAccumulator, } transactionProcessor, err := transaction.NewTxProcessor(argsNewTxProcessor) if err != nil { @@ -552,6 +565,11 @@ func (pcf *processComponentsFactory) newMetaBlockProcessor( return nil, err } + err = pcf.coreData.EconomicsData().SetTxTypeHandler(txTypeHandler) + if err != nil { + return nil, err + } + gasHandler, err := preprocess.NewGasComputation( pcf.coreData.EconomicsData(), txTypeHandler, @@ -561,31 +579,33 @@ func (pcf *processComponentsFactory) newMetaBlockProcessor( return nil, err } + failedTxLogsAccumulator := transactionLog.NewFailedTxLogsAccumulator() txFeeHandler := postprocess.NewFeeAccumulator() enableEpochs := pcf.epochConfig.EnableEpochs argsNewScProcessor := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: vmContainer, - ArgsParser: argsParser, - Hasher: pcf.coreData.Hasher(), - Marshalizer: pcf.coreData.InternalMarshalizer(), - AccountsDB: pcf.state.AccountsAdapter(), - BlockChainHook: vmFactory.BlockChainHookImpl(), - BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), - PubkeyConv: pcf.coreData.AddressPubKeyConverter(), - ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), - ScrForwarder: scForwarder, - TxFeeHandler: txFeeHandler, - EconomicsFee: pcf.coreData.EconomicsData(), - TxTypeHandler: txTypeHandler, - GasHandler: gasHandler, - GasSchedule: pcf.gasSchedule, - TxLogsProcessor: pcf.txLogsProcessor, - IsGenesisProcessing: false, - BadTxForwarder: badTxForwarder, - EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), - EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), - VMOutputCacher: txcache.NewDisabledCache(), - WasmVMChangeLocker: wasmVMChangeLocker, + VmContainer: vmContainer, + ArgsParser: argsParser, + Hasher: pcf.coreData.Hasher(), + Marshalizer: pcf.coreData.InternalMarshalizer(), + AccountsDB: pcf.state.AccountsAdapter(), + BlockChainHook: vmFactory.BlockChainHookImpl(), + BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), + PubkeyConv: pcf.coreData.AddressPubKeyConverter(), + ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), + ScrForwarder: scForwarder, + TxFeeHandler: txFeeHandler, + EconomicsFee: pcf.coreData.EconomicsData(), + TxTypeHandler: txTypeHandler, + GasHandler: gasHandler, + GasSchedule: pcf.gasSchedule, + TxLogsProcessor: pcf.txLogsProcessor, + IsGenesisProcessing: false, + BadTxForwarder: badTxForwarder, + EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), + EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), + VMOutputCacher: txcache.NewDisabledCache(), + WasmVMChangeLocker: wasmVMChangeLocker, + FailedTxLogsAccumulator: failedTxLogsAccumulator, } scProcessorProxy, err := processProxy.NewSmartContractProcessorProxy(argsNewScProcessor, pcf.epochNotifier) diff --git a/factory/processing/blockProcessorCreator_test.go b/factory/processing/blockProcessorCreator_test.go index 099fec4a82d..4fb8f8c5d7d 100644 --- a/factory/processing/blockProcessorCreator_test.go +++ b/factory/processing/blockProcessorCreator_test.go @@ -57,6 +57,7 @@ func Test_newBlockProcessorCreatorForShard(t *testing.T) { &testscommon.BlockProcessingCutoffStub{}, &testscommon.MissingTrieNodesNotifierStub{}, &testscommon.SentSignatureTrackerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) require.NoError(t, err) @@ -184,6 +185,7 @@ func Test_newBlockProcessorCreatorForMeta(t *testing.T) { &testscommon.BlockProcessingCutoffStub{}, &testscommon.MissingTrieNodesNotifierStub{}, &testscommon.SentSignatureTrackerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) require.NoError(t, err) diff --git a/factory/processing/export_test.go b/factory/processing/export_test.go index 76e84d75fee..c82f01b3f6f 100644 --- a/factory/processing/export_test.go +++ b/factory/processing/export_test.go @@ -25,6 +25,7 @@ func (pcf *processComponentsFactory) NewBlockProcessor( blockProcessingCutoff cutoff.BlockProcessingCutoffHandler, missingTrieNodesNotifier common.MissingTrieNodesNotifier, sentSignaturesTracker process.SentSignaturesTracker, + relayedV3TxProcessor process.RelayedTxV3Processor, ) (process.BlockProcessor, process.EpochStartSystemSCProcessor, error) { blockProcessorComponents, err := pcf.newBlockProcessor( requestHandler, @@ -42,6 +43,7 @@ func (pcf *processComponentsFactory) NewBlockProcessor( blockProcessingCutoff, missingTrieNodesNotifier, sentSignaturesTracker, + relayedV3TxProcessor, ) if err != nil { return nil, nil, err @@ -51,6 +53,6 @@ func (pcf *processComponentsFactory) NewBlockProcessor( } // CreateAPITransactionEvaluator - -func (pcf *processComponentsFactory) CreateAPITransactionEvaluator() (factory.TransactionEvaluator, process.VirtualMachinesContainerFactory, error) { - return pcf.createAPITransactionEvaluator() +func (pcf *processComponentsFactory) CreateAPITransactionEvaluator(relayedV3TxProcessor process.RelayedTxV3Processor) (factory.TransactionEvaluator, process.VirtualMachinesContainerFactory, error) { + return pcf.createAPITransactionEvaluator(relayedV3TxProcessor) } diff --git a/factory/processing/processComponents.go b/factory/processing/processComponents.go index 352343ce102..6f711a502ae 100644 --- a/factory/processing/processComponents.go +++ b/factory/processing/processComponents.go @@ -16,6 +16,9 @@ import ( dataBlock "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/data/outport" "github.com/multiversx/mx-chain-core-go/data/receipt" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + vmcommonBuiltInFunctions "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" + nodeFactory "github.com/multiversx/mx-chain-go/cmd/node/factory" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/common/errChan" @@ -59,6 +62,7 @@ import ( "github.com/multiversx/mx-chain-go/process/smartContract" "github.com/multiversx/mx-chain-go/process/sync" "github.com/multiversx/mx-chain-go/process/track" + "github.com/multiversx/mx-chain-go/process/transaction" "github.com/multiversx/mx-chain-go/process/transactionLog" "github.com/multiversx/mx-chain-go/process/txsSender" "github.com/multiversx/mx-chain-go/redundancy" @@ -76,8 +80,6 @@ import ( updateDisabled "github.com/multiversx/mx-chain-go/update/disabled" updateFactory "github.com/multiversx/mx-chain-go/update/factory" "github.com/multiversx/mx-chain-go/update/trigger" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - vmcommonBuiltInFunctions "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" ) // timeSpanForBadHeaders is the expiry time for an added block header hash @@ -132,6 +134,7 @@ type processComponents struct { receiptsRepository mainFactory.ReceiptsRepository sentSignaturesTracker process.SentSignaturesTracker epochSystemSCProcessor process.EpochStartSystemSCProcessor + relayedTxV3Processor process.RelayedTxV3Processor } // ProcessComponentsFactoryArgs holds the arguments needed to create a process components factory @@ -514,6 +517,16 @@ func (pcf *processComponentsFactory) Create() (*processComponents, error) { return nil, err } + argsRelayedTxV3Processor := transaction.ArgRelayedTxV3Processor{ + EconomicsFee: pcf.coreData.EconomicsData(), + ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), + MaxTransactionsAllowed: pcf.config.RelayedTransactionConfig.MaxTransactionsAllowed, + } + relayedTxV3Processor, err := transaction.NewRelayedTxV3Processor(argsRelayedTxV3Processor) + if err != nil { + return nil, err + } + interceptorContainerFactory, blackListHandler, err := pcf.newInterceptorContainerFactory( headerSigVerifier, pcf.bootstrapComponents.HeaderIntegrityVerifier(), @@ -523,6 +536,7 @@ func (pcf *processComponentsFactory) Create() (*processComponents, error) { mainPeerShardMapper, fullArchivePeerShardMapper, hardforkTrigger, + relayedTxV3Processor, ) if err != nil { return nil, err @@ -619,6 +633,7 @@ func (pcf *processComponentsFactory) Create() (*processComponents, error) { blockCutoffProcessingHandler, pcf.state.MissingTrieNodesNotifier(), sentSignaturesTracker, + relayedTxV3Processor, ) if err != nil { return nil, err @@ -708,7 +723,7 @@ func (pcf *processComponentsFactory) Create() (*processComponents, error) { return nil, err } - apiTransactionEvaluator, vmFactoryForTxSimulate, err := pcf.createAPITransactionEvaluator() + apiTransactionEvaluator, vmFactoryForTxSimulate, err := pcf.createAPITransactionEvaluator(relayedTxV3Processor) if err != nil { return nil, fmt.Errorf("%w when assembling components for the transactions simulator processor", err) } @@ -761,6 +776,7 @@ func (pcf *processComponentsFactory) Create() (*processComponents, error) { accountsParser: pcf.accountsParser, receiptsRepository: receiptsRepository, sentSignaturesTracker: sentSignaturesTracker, + relayedTxV3Processor: relayedTxV3Processor, }, nil } @@ -1492,6 +1508,7 @@ func (pcf *processComponentsFactory) newInterceptorContainerFactory( mainPeerShardMapper *networksharding.PeerShardMapper, fullArchivePeerShardMapper *networksharding.PeerShardMapper, hardforkTrigger factory.HardforkTrigger, + relayedTxV3Processor process.RelayedTxV3Processor, ) (process.InterceptorsContainerFactory, process.TimeCacher, error) { nodeOperationMode := common.NormalOperation if pcf.prefConfigs.Preferences.FullArchive { @@ -1510,6 +1527,7 @@ func (pcf *processComponentsFactory) newInterceptorContainerFactory( fullArchivePeerShardMapper, hardforkTrigger, nodeOperationMode, + relayedTxV3Processor, ) } if shardCoordinator.SelfId() == core.MetachainShardId { @@ -1523,6 +1541,7 @@ func (pcf *processComponentsFactory) newInterceptorContainerFactory( fullArchivePeerShardMapper, hardforkTrigger, nodeOperationMode, + relayedTxV3Processor, ) } @@ -1662,6 +1681,7 @@ func (pcf *processComponentsFactory) newShardInterceptorContainerFactory( fullArchivePeerShardMapper *networksharding.PeerShardMapper, hardforkTrigger factory.HardforkTrigger, nodeOperationMode common.NodeOperation, + relayedTxV3Processor process.RelayedTxV3Processor, ) (process.InterceptorsContainerFactory, process.TimeCacher, error) { headerBlackList := cache.NewTimeCache(timeSpanForBadHeaders) shardInterceptorsContainerFactoryArgs := interceptorscontainer.CommonInterceptorsContainerFactoryArgs{ @@ -1695,6 +1715,7 @@ func (pcf *processComponentsFactory) newShardInterceptorContainerFactory( FullArchivePeerShardMapper: fullArchivePeerShardMapper, HardforkTrigger: hardforkTrigger, NodeOperationMode: nodeOperationMode, + RelayedTxV3Processor: relayedTxV3Processor, } interceptorContainerFactory, err := interceptorscontainer.NewShardInterceptorsContainerFactory(shardInterceptorsContainerFactoryArgs) @@ -1715,6 +1736,7 @@ func (pcf *processComponentsFactory) newMetaInterceptorContainerFactory( fullArchivePeerShardMapper *networksharding.PeerShardMapper, hardforkTrigger factory.HardforkTrigger, nodeOperationMode common.NodeOperation, + relayedTxV3Processor process.RelayedTxV3Processor, ) (process.InterceptorsContainerFactory, process.TimeCacher, error) { headerBlackList := cache.NewTimeCache(timeSpanForBadHeaders) metaInterceptorsContainerFactoryArgs := interceptorscontainer.CommonInterceptorsContainerFactoryArgs{ @@ -1748,6 +1770,7 @@ func (pcf *processComponentsFactory) newMetaInterceptorContainerFactory( FullArchivePeerShardMapper: fullArchivePeerShardMapper, HardforkTrigger: hardforkTrigger, NodeOperationMode: nodeOperationMode, + RelayedTxV3Processor: relayedTxV3Processor, } interceptorContainerFactory, err := interceptorscontainer.NewMetaInterceptorsContainerFactory(metaInterceptorsContainerFactoryArgs) diff --git a/factory/processing/processComponentsHandler.go b/factory/processing/processComponentsHandler.go index 28b3c4b0eed..94f21a5b8f2 100644 --- a/factory/processing/processComponentsHandler.go +++ b/factory/processing/processComponentsHandler.go @@ -180,6 +180,9 @@ func (m *managedProcessComponents) CheckSubcomponents() error { if check.IfNil(m.processComponents.epochSystemSCProcessor) { return errors.ErrNilEpochSystemSCProcessor } + if check.IfNil(m.processComponents.relayedTxV3Processor) { + return errors.ErrNilRelayedTxV3Processor + } return nil } @@ -688,6 +691,18 @@ func (m *managedProcessComponents) EpochSystemSCProcessor() process.EpochStartSy return m.processComponents.epochSystemSCProcessor } +// RelayedTxV3Processor returns the relayed tx v3 processor +func (m *managedProcessComponents) RelayedTxV3Processor() process.RelayedTxV3Processor { + m.mutProcessComponents.RLock() + defer m.mutProcessComponents.RUnlock() + + if m.processComponents == nil { + return nil + } + + return m.processComponents.relayedTxV3Processor +} + // IsInterfaceNil returns true if the interface is nil func (m *managedProcessComponents) IsInterfaceNil() bool { return m == nil diff --git a/factory/processing/processComponentsHandler_test.go b/factory/processing/processComponentsHandler_test.go index 2aec3cb8c6e..c999d25b041 100644 --- a/factory/processing/processComponentsHandler_test.go +++ b/factory/processing/processComponentsHandler_test.go @@ -94,6 +94,7 @@ func TestManagedProcessComponents_Create(t *testing.T) { require.True(t, check.IfNil(managedProcessComponents.FullArchiveInterceptorsContainer())) require.True(t, check.IfNil(managedProcessComponents.SentSignaturesTracker())) require.True(t, check.IfNil(managedProcessComponents.EpochSystemSCProcessor())) + require.True(t, check.IfNil(managedProcessComponents.RelayedTxV3Processor())) err := managedProcessComponents.Create() require.NoError(t, err) @@ -139,6 +140,7 @@ func TestManagedProcessComponents_Create(t *testing.T) { require.False(t, check.IfNil(managedProcessComponents.FullArchiveInterceptorsContainer())) require.False(t, check.IfNil(managedProcessComponents.SentSignaturesTracker())) require.False(t, check.IfNil(managedProcessComponents.EpochSystemSCProcessor())) + require.False(t, check.IfNil(managedProcessComponents.RelayedTxV3Processor())) require.Equal(t, factory.ProcessComponentsName, managedProcessComponents.String()) }) diff --git a/factory/processing/txSimulatorProcessComponents.go b/factory/processing/txSimulatorProcessComponents.go index 257a46af1a5..21fe2ddc073 100644 --- a/factory/processing/txSimulatorProcessComponents.go +++ b/factory/processing/txSimulatorProcessComponents.go @@ -27,7 +27,7 @@ import ( datafield "github.com/multiversx/mx-chain-vm-common-go/parsers/dataField" ) -func (pcf *processComponentsFactory) createAPITransactionEvaluator() (factory.TransactionEvaluator, process.VirtualMachinesContainerFactory, error) { +func (pcf *processComponentsFactory) createAPITransactionEvaluator(relayedTxV3Processor process.RelayedTxV3Processor) (factory.TransactionEvaluator, process.VirtualMachinesContainerFactory, error) { simulationAccountsDB, err := transactionEvaluator.NewSimulationAccountsDB(pcf.state.AccountsAdapterAPI()) if err != nil { return nil, nil, err @@ -47,7 +47,7 @@ func (pcf *processComponentsFactory) createAPITransactionEvaluator() (factory.Tr return nil, nil, err } - txSimulatorProcessorArgs, vmContainerFactory, txTypeHandler, err := pcf.createArgsTxSimulatorProcessor(simulationAccountsDB, vmOutputCacher, txLogsProcessor) + txSimulatorProcessorArgs, vmContainerFactory, txTypeHandler, err := pcf.createArgsTxSimulatorProcessor(simulationAccountsDB, vmOutputCacher, txLogsProcessor, relayedTxV3Processor) if err != nil { return nil, nil, err } @@ -89,12 +89,13 @@ func (pcf *processComponentsFactory) createArgsTxSimulatorProcessor( accountsAdapter state.AccountsAdapter, vmOutputCacher storage.Cacher, txLogsProcessor process.TransactionLogProcessor, + relayedTxV3Processor process.RelayedTxV3Processor, ) (transactionEvaluator.ArgsTxSimulator, process.VirtualMachinesContainerFactory, process.TxTypeHandler, error) { shardID := pcf.bootstrapComponents.ShardCoordinator().SelfId() if shardID == core.MetachainShardId { return pcf.createArgsTxSimulatorProcessorForMeta(accountsAdapter, vmOutputCacher, txLogsProcessor) } else { - return pcf.createArgsTxSimulatorProcessorShard(accountsAdapter, vmOutputCacher, txLogsProcessor) + return pcf.createArgsTxSimulatorProcessorShard(accountsAdapter, vmOutputCacher, txLogsProcessor, relayedTxV3Processor) } } @@ -172,29 +173,32 @@ func (pcf *processComponentsFactory) createArgsTxSimulatorProcessorForMeta( return args, nil, nil, err } + failedTxLogsAccumulator := transactionLog.NewFailedTxLogsAccumulator() + scProcArgs := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: vmContainer, - ArgsParser: smartContract.NewArgumentParser(), - Hasher: pcf.coreData.Hasher(), - Marshalizer: pcf.coreData.InternalMarshalizer(), - AccountsDB: accountsAdapter, - BlockChainHook: vmContainerFactory.BlockChainHookImpl(), - BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), - PubkeyConv: pcf.coreData.AddressPubKeyConverter(), - ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), - ScrForwarder: scForwarder, - TxFeeHandler: &processDisabled.FeeHandler{}, - EconomicsFee: pcf.coreData.EconomicsData(), - TxTypeHandler: txTypeHandler, - GasHandler: gasHandler, - GasSchedule: pcf.gasSchedule, - TxLogsProcessor: txLogsProcessor, - EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), - EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), - BadTxForwarder: badTxInterim, - VMOutputCacher: vmOutputCacher, - WasmVMChangeLocker: pcf.coreData.WasmVMChangeLocker(), - IsGenesisProcessing: false, + VmContainer: vmContainer, + ArgsParser: smartContract.NewArgumentParser(), + Hasher: pcf.coreData.Hasher(), + Marshalizer: pcf.coreData.InternalMarshalizer(), + AccountsDB: accountsAdapter, + BlockChainHook: vmContainerFactory.BlockChainHookImpl(), + BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), + PubkeyConv: pcf.coreData.AddressPubKeyConverter(), + ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), + ScrForwarder: scForwarder, + TxFeeHandler: &processDisabled.FeeHandler{}, + EconomicsFee: pcf.coreData.EconomicsData(), + TxTypeHandler: txTypeHandler, + GasHandler: gasHandler, + GasSchedule: pcf.gasSchedule, + TxLogsProcessor: txLogsProcessor, + EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), + EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), + BadTxForwarder: badTxInterim, + VMOutputCacher: vmOutputCacher, + WasmVMChangeLocker: pcf.coreData.WasmVMChangeLocker(), + IsGenesisProcessing: false, + FailedTxLogsAccumulator: failedTxLogsAccumulator, } scProcessor, err := smartContract.NewSmartContractProcessor(scProcArgs) @@ -249,6 +253,7 @@ func (pcf *processComponentsFactory) createArgsTxSimulatorProcessorShard( accountsAdapter state.AccountsAdapter, vmOutputCacher storage.Cacher, txLogsProcessor process.TransactionLogProcessor, + relayedTxV3Processor process.RelayedTxV3Processor, ) (transactionEvaluator.ArgsTxSimulator, process.VirtualMachinesContainerFactory, process.TxTypeHandler, error) { args := transactionEvaluator.ArgsTxSimulator{} @@ -346,29 +351,32 @@ func (pcf *processComponentsFactory) createArgsTxSimulatorProcessorShard( argsParser := smartContract.NewArgumentParser() + failedTxLogsAccumulator := transactionLog.NewFailedTxLogsAccumulator() + scProcArgs := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: vmContainer, - ArgsParser: argsParser, - Hasher: pcf.coreData.Hasher(), - Marshalizer: pcf.coreData.InternalMarshalizer(), - AccountsDB: accountsAdapter, - BlockChainHook: vmContainerFactory.BlockChainHookImpl(), - BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), - PubkeyConv: pcf.coreData.AddressPubKeyConverter(), - ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), - ScrForwarder: scForwarder, - TxFeeHandler: &processDisabled.FeeHandler{}, - EconomicsFee: pcf.coreData.EconomicsData(), - TxTypeHandler: txTypeHandler, - GasHandler: gasHandler, - GasSchedule: pcf.gasSchedule, - TxLogsProcessor: txLogsProcessor, - EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), - EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), - BadTxForwarder: badTxInterim, - VMOutputCacher: vmOutputCacher, - WasmVMChangeLocker: pcf.coreData.WasmVMChangeLocker(), - IsGenesisProcessing: false, + VmContainer: vmContainer, + ArgsParser: argsParser, + Hasher: pcf.coreData.Hasher(), + Marshalizer: pcf.coreData.InternalMarshalizer(), + AccountsDB: accountsAdapter, + BlockChainHook: vmContainerFactory.BlockChainHookImpl(), + BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), + PubkeyConv: pcf.coreData.AddressPubKeyConverter(), + ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), + ScrForwarder: scForwarder, + TxFeeHandler: &processDisabled.FeeHandler{}, + EconomicsFee: pcf.coreData.EconomicsData(), + TxTypeHandler: txTypeHandler, + GasHandler: gasHandler, + GasSchedule: pcf.gasSchedule, + TxLogsProcessor: txLogsProcessor, + EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), + EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), + BadTxForwarder: badTxInterim, + VMOutputCacher: vmOutputCacher, + WasmVMChangeLocker: pcf.coreData.WasmVMChangeLocker(), + IsGenesisProcessing: false, + FailedTxLogsAccumulator: failedTxLogsAccumulator, } scProcessor, err := smartContract.NewSmartContractProcessor(scProcArgs) @@ -377,25 +385,27 @@ func (pcf *processComponentsFactory) createArgsTxSimulatorProcessorShard( } argsTxProcessor := transaction.ArgsNewTxProcessor{ - Accounts: accountsAdapter, - Hasher: pcf.coreData.Hasher(), - PubkeyConv: pcf.coreData.AddressPubKeyConverter(), - Marshalizer: pcf.coreData.InternalMarshalizer(), - SignMarshalizer: pcf.coreData.TxMarshalizer(), - ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), - ScProcessor: scProcessor, - TxFeeHandler: txFeeHandler, - TxTypeHandler: txTypeHandler, - EconomicsFee: pcf.coreData.EconomicsData(), - ReceiptForwarder: receiptTxInterim, - BadTxForwarder: badTxInterim, - ArgsParser: argsParser, - ScrForwarder: scForwarder, - EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), - EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), - TxVersionChecker: pcf.coreData.TxVersionChecker(), - GuardianChecker: pcf.bootstrapComponents.GuardedAccountHandler(), - TxLogsProcessor: txLogsProcessor, + Accounts: accountsAdapter, + Hasher: pcf.coreData.Hasher(), + PubkeyConv: pcf.coreData.AddressPubKeyConverter(), + Marshalizer: pcf.coreData.InternalMarshalizer(), + SignMarshalizer: pcf.coreData.TxMarshalizer(), + ShardCoordinator: pcf.bootstrapComponents.ShardCoordinator(), + ScProcessor: scProcessor, + TxFeeHandler: txFeeHandler, + TxTypeHandler: txTypeHandler, + EconomicsFee: pcf.coreData.EconomicsData(), + ReceiptForwarder: receiptTxInterim, + BadTxForwarder: badTxInterim, + ArgsParser: argsParser, + ScrForwarder: scForwarder, + EnableEpochsHandler: pcf.coreData.EnableEpochsHandler(), + EnableRoundsHandler: pcf.coreData.EnableRoundsHandler(), + TxVersionChecker: pcf.coreData.TxVersionChecker(), + GuardianChecker: pcf.bootstrapComponents.GuardedAccountHandler(), + TxLogsProcessor: txLogsProcessor, + RelayedTxV3Processor: relayedTxV3Processor, + FailedTxLogsAccumulator: failedTxLogsAccumulator, } txProcessor, err := transaction.NewTxProcessor(argsTxProcessor) diff --git a/factory/processing/txSimulatorProcessComponents_test.go b/factory/processing/txSimulatorProcessComponents_test.go index aad848600d8..37944768bfe 100644 --- a/factory/processing/txSimulatorProcessComponents_test.go +++ b/factory/processing/txSimulatorProcessComponents_test.go @@ -8,6 +8,7 @@ import ( "github.com/multiversx/mx-chain-go/factory/processing" "github.com/multiversx/mx-chain-go/process/mock" "github.com/multiversx/mx-chain-go/testscommon/components" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/stretchr/testify/assert" ) @@ -26,7 +27,7 @@ func TestManagedProcessComponents_createAPITransactionEvaluator(t *testing.T) { processArgs.Config.VMOutputCacher.Type = "invalid" pcf, _ := processing.NewProcessComponentsFactory(processArgs) - apiTransactionEvaluator, vmContainerFactory, err := pcf.CreateAPITransactionEvaluator() + apiTransactionEvaluator, vmContainerFactory, err := pcf.CreateAPITransactionEvaluator(&processMocks.RelayedTxV3ProcessorMock{}) assert.NotNil(t, err) assert.True(t, check.IfNil(apiTransactionEvaluator)) assert.True(t, check.IfNil(vmContainerFactory)) @@ -36,7 +37,7 @@ func TestManagedProcessComponents_createAPITransactionEvaluator(t *testing.T) { processArgs := components.GetProcessComponentsFactoryArgs(shardCoordinatorForShardID2) pcf, _ := processing.NewProcessComponentsFactory(processArgs) - apiTransactionEvaluator, vmContainerFactory, err := pcf.CreateAPITransactionEvaluator() + apiTransactionEvaluator, vmContainerFactory, err := pcf.CreateAPITransactionEvaluator(&processMocks.RelayedTxV3ProcessorMock{}) assert.Nil(t, err) assert.False(t, check.IfNil(apiTransactionEvaluator)) assert.False(t, check.IfNil(vmContainerFactory)) @@ -45,7 +46,7 @@ func TestManagedProcessComponents_createAPITransactionEvaluator(t *testing.T) { processArgs := components.GetProcessComponentsFactoryArgs(shardCoordinatorForMetachain) pcf, _ := processing.NewProcessComponentsFactory(processArgs) - apiTransactionEvaluator, vmContainerFactory, err := pcf.CreateAPITransactionEvaluator() + apiTransactionEvaluator, vmContainerFactory, err := pcf.CreateAPITransactionEvaluator(&processMocks.RelayedTxV3ProcessorMock{}) assert.Nil(t, err) assert.False(t, check.IfNil(apiTransactionEvaluator)) assert.False(t, check.IfNil(vmContainerFactory)) diff --git a/genesis/mock/coreComponentsMock.go b/genesis/mock/coreComponentsMock.go index fb0907ef8a0..e44dd801243 100644 --- a/genesis/mock/coreComponentsMock.go +++ b/genesis/mock/coreComponentsMock.go @@ -22,6 +22,12 @@ type CoreComponentsMock struct { StatHandler core.AppStatusHandler EnableEpochsHandlerField common.EnableEpochsHandler TxVersionCheck process.TxVersionCheckerHandler + EconomicsDataField process.EconomicsDataHandler +} + +// EconomicsData - +func (ccm *CoreComponentsMock) EconomicsData() process.EconomicsDataHandler { + return ccm.EconomicsDataField } // InternalMarshalizer - diff --git a/genesis/process/argGenesisBlockCreator.go b/genesis/process/argGenesisBlockCreator.go index 19b5fc9adcc..685e356f31b 100644 --- a/genesis/process/argGenesisBlockCreator.go +++ b/genesis/process/argGenesisBlockCreator.go @@ -29,6 +29,7 @@ type coreComponentsHandler interface { TxVersionChecker() process.TxVersionCheckerHandler ChainID() string EnableEpochsHandler() common.EnableEpochsHandler + EconomicsData() process.EconomicsDataHandler IsInterfaceNil() bool } diff --git a/genesis/process/disabled/feeHandler.go b/genesis/process/disabled/feeHandler.go index 1fc34bbc2b5..f81e7e978eb 100644 --- a/genesis/process/disabled/feeHandler.go +++ b/genesis/process/disabled/feeHandler.go @@ -183,6 +183,11 @@ func (fh *FeeHandler) ComputeTxFeeBasedOnGasUsedInEpoch(tx data.TransactionWithF return big.NewInt(0) } +// ComputeRelayedTxFees returns 0 and 0 +func (fh *FeeHandler) ComputeRelayedTxFees(_ data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) { + return big.NewInt(0), big.NewInt(0), nil +} + // IsInterfaceNil returns true if there is no value under the interface func (fh *FeeHandler) IsInterfaceNil() bool { return fh == nil diff --git a/genesis/process/genesisBlockCreator_test.go b/genesis/process/genesisBlockCreator_test.go index b7b788f0d37..a681a0e271c 100644 --- a/genesis/process/genesisBlockCreator_test.go +++ b/genesis/process/genesisBlockCreator_test.go @@ -76,6 +76,7 @@ func createMockArgument( TxVersionCheck: &testscommon.TxVersionCheckerStub{}, MinTxVersion: 1, EnableEpochsHandlerField: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + EconomicsDataField: &economicsmocks.EconomicsHandlerMock{}, }, Data: &mock.DataComponentsMock{ Storage: &storageCommon.ChainStorerStub{ @@ -307,7 +308,8 @@ func TestNewGenesisBlockCreator(t *testing.T) { arg := createMockArgument(t, "testdata/genesisTest1.json", &mock.InitialNodesHandlerStub{}, big.NewInt(22000)) arg.Core = &mock.CoreComponentsMock{ - AddrPubKeyConv: nil, + AddrPubKeyConv: nil, + EconomicsDataField: &economicsmocks.EconomicsHandlerMock{}, } gbc, err := NewGenesisBlockCreator(arg) diff --git a/genesis/process/metaGenesisBlockCreator.go b/genesis/process/metaGenesisBlockCreator.go index f695c274b42..78546562736 100644 --- a/genesis/process/metaGenesisBlockCreator.go +++ b/genesis/process/metaGenesisBlockCreator.go @@ -28,6 +28,7 @@ import ( "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/preprocess" "github.com/multiversx/mx-chain-go/process/coordinator" + disabledProcess "github.com/multiversx/mx-chain-go/process/disabled" "github.com/multiversx/mx-chain-go/process/factory" "github.com/multiversx/mx-chain-go/process/factory/metachain" disabledGuardian "github.com/multiversx/mx-chain-go/process/guardian/disabled" @@ -430,6 +431,11 @@ func createProcessorsForMetaGenesisBlock(arg ArgsGenesisBlockCreator, enableEpoc return nil, err } + err = arg.Core.EconomicsData().SetTxTypeHandler(txTypeHandler) + if err != nil { + return nil, err + } + gasHandler, err := preprocess.NewGasComputation(arg.Economics, txTypeHandler, enableEpochsHandler) if err != nil { return nil, err @@ -437,28 +443,29 @@ func createProcessorsForMetaGenesisBlock(arg ArgsGenesisBlockCreator, enableEpoc argsParser := smartContract.NewArgumentParser() argsNewSCProcessor := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: vmContainer, - ArgsParser: argsParser, - Hasher: arg.Core.Hasher(), - Marshalizer: arg.Core.InternalMarshalizer(), - AccountsDB: arg.Accounts, - BlockChainHook: virtualMachineFactory.BlockChainHookImpl(), - BuiltInFunctions: builtInFuncs, - PubkeyConv: arg.Core.AddressPubKeyConverter(), - ShardCoordinator: arg.ShardCoordinator, - ScrForwarder: scForwarder, - TxFeeHandler: genesisFeeHandler, - EconomicsFee: genesisFeeHandler, - TxTypeHandler: txTypeHandler, - GasHandler: gasHandler, - GasSchedule: arg.GasSchedule, - TxLogsProcessor: arg.TxLogsProcessor, - BadTxForwarder: badTxForwarder, - EnableRoundsHandler: enableRoundsHandler, - EnableEpochsHandler: enableEpochsHandler, - IsGenesisProcessing: true, - WasmVMChangeLocker: &sync.RWMutex{}, // local Locker as to not interfere with the rest of the components - VMOutputCacher: txcache.NewDisabledCache(), + VmContainer: vmContainer, + ArgsParser: argsParser, + Hasher: arg.Core.Hasher(), + Marshalizer: arg.Core.InternalMarshalizer(), + AccountsDB: arg.Accounts, + BlockChainHook: virtualMachineFactory.BlockChainHookImpl(), + BuiltInFunctions: builtInFuncs, + PubkeyConv: arg.Core.AddressPubKeyConverter(), + ShardCoordinator: arg.ShardCoordinator, + ScrForwarder: scForwarder, + TxFeeHandler: genesisFeeHandler, + EconomicsFee: genesisFeeHandler, + TxTypeHandler: txTypeHandler, + GasHandler: gasHandler, + GasSchedule: arg.GasSchedule, + TxLogsProcessor: arg.TxLogsProcessor, + BadTxForwarder: badTxForwarder, + EnableRoundsHandler: enableRoundsHandler, + EnableEpochsHandler: enableEpochsHandler, + IsGenesisProcessing: true, + WasmVMChangeLocker: &sync.RWMutex{}, // local Locker as to not interfere with the rest of the components + VMOutputCacher: txcache.NewDisabledCache(), + FailedTxLogsAccumulator: disabledProcess.NewFailedTxLogsAccumulator(), } scProcessorProxy, err := processProxy.NewSmartContractProcessorProxy(argsNewSCProcessor, epochNotifier) diff --git a/genesis/process/shardGenesisBlockCreator.go b/genesis/process/shardGenesisBlockCreator.go index 2347632d2d5..b44ed14c207 100644 --- a/genesis/process/shardGenesisBlockCreator.go +++ b/genesis/process/shardGenesisBlockCreator.go @@ -24,6 +24,7 @@ import ( "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/preprocess" "github.com/multiversx/mx-chain-go/process/coordinator" + processDisabled "github.com/multiversx/mx-chain-go/process/disabled" "github.com/multiversx/mx-chain-go/process/factory/shard" disabledGuardian "github.com/multiversx/mx-chain-go/process/guardian/disabled" "github.com/multiversx/mx-chain-go/process/receipts" @@ -500,34 +501,40 @@ func createProcessorsForShardGenesisBlock(arg ArgsGenesisBlockCreator, enableEpo return nil, err } + err = arg.Core.EconomicsData().SetTxTypeHandler(txTypeHandler) + if err != nil { + return nil, err + } + gasHandler, err := preprocess.NewGasComputation(arg.Economics, txTypeHandler, enableEpochsHandler) if err != nil { return nil, err } argsNewScProcessor := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: vmContainer, - ArgsParser: smartContract.NewArgumentParser(), - Hasher: arg.Core.Hasher(), - Marshalizer: arg.Core.InternalMarshalizer(), - AccountsDB: arg.Accounts, - BlockChainHook: vmFactoryImpl.BlockChainHookImpl(), - BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), - PubkeyConv: arg.Core.AddressPubKeyConverter(), - ShardCoordinator: arg.ShardCoordinator, - ScrForwarder: scForwarder, - TxFeeHandler: genesisFeeHandler, - EconomicsFee: genesisFeeHandler, - TxTypeHandler: txTypeHandler, - GasHandler: gasHandler, - GasSchedule: arg.GasSchedule, - TxLogsProcessor: arg.TxLogsProcessor, - BadTxForwarder: badTxInterim, - EnableRoundsHandler: enableRoundsHandler, - EnableEpochsHandler: enableEpochsHandler, - IsGenesisProcessing: true, - VMOutputCacher: txcache.NewDisabledCache(), - WasmVMChangeLocker: genesisWasmVMLocker, + VmContainer: vmContainer, + ArgsParser: smartContract.NewArgumentParser(), + Hasher: arg.Core.Hasher(), + Marshalizer: arg.Core.InternalMarshalizer(), + AccountsDB: arg.Accounts, + BlockChainHook: vmFactoryImpl.BlockChainHookImpl(), + BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), + PubkeyConv: arg.Core.AddressPubKeyConverter(), + ShardCoordinator: arg.ShardCoordinator, + ScrForwarder: scForwarder, + TxFeeHandler: genesisFeeHandler, + EconomicsFee: genesisFeeHandler, + TxTypeHandler: txTypeHandler, + GasHandler: gasHandler, + GasSchedule: arg.GasSchedule, + TxLogsProcessor: arg.TxLogsProcessor, + BadTxForwarder: badTxInterim, + EnableRoundsHandler: enableRoundsHandler, + EnableEpochsHandler: enableEpochsHandler, + IsGenesisProcessing: true, + VMOutputCacher: txcache.NewDisabledCache(), + WasmVMChangeLocker: genesisWasmVMLocker, + FailedTxLogsAccumulator: processDisabled.NewFailedTxLogsAccumulator(), } scProcessorProxy, err := processProxy.NewSmartContractProcessorProxy(argsNewScProcessor, epochNotifier) @@ -545,25 +552,27 @@ func createProcessorsForShardGenesisBlock(arg ArgsGenesisBlockCreator, enableEpo } argsNewTxProcessor := transaction.ArgsNewTxProcessor{ - Accounts: arg.Accounts, - Hasher: arg.Core.Hasher(), - PubkeyConv: arg.Core.AddressPubKeyConverter(), - Marshalizer: arg.Core.InternalMarshalizer(), - SignMarshalizer: arg.Core.TxMarshalizer(), - ShardCoordinator: arg.ShardCoordinator, - ScProcessor: scProcessorProxy, - TxFeeHandler: genesisFeeHandler, - TxTypeHandler: txTypeHandler, - EconomicsFee: genesisFeeHandler, - ReceiptForwarder: receiptTxInterim, - BadTxForwarder: badTxInterim, - ArgsParser: smartContract.NewArgumentParser(), - ScrForwarder: scForwarder, - EnableRoundsHandler: enableRoundsHandler, - EnableEpochsHandler: enableEpochsHandler, - TxVersionChecker: arg.Core.TxVersionChecker(), - GuardianChecker: disabledGuardian.NewDisabledGuardedAccountHandler(), - TxLogsProcessor: arg.TxLogsProcessor, + Accounts: arg.Accounts, + Hasher: arg.Core.Hasher(), + PubkeyConv: arg.Core.AddressPubKeyConverter(), + Marshalizer: arg.Core.InternalMarshalizer(), + SignMarshalizer: arg.Core.TxMarshalizer(), + ShardCoordinator: arg.ShardCoordinator, + ScProcessor: scProcessorProxy, + TxFeeHandler: genesisFeeHandler, + TxTypeHandler: txTypeHandler, + EconomicsFee: genesisFeeHandler, + ReceiptForwarder: receiptTxInterim, + BadTxForwarder: badTxInterim, + ArgsParser: smartContract.NewArgumentParser(), + ScrForwarder: scForwarder, + EnableRoundsHandler: enableRoundsHandler, + EnableEpochsHandler: enableEpochsHandler, + TxVersionChecker: arg.Core.TxVersionChecker(), + GuardianChecker: disabledGuardian.NewDisabledGuardedAccountHandler(), + TxLogsProcessor: arg.TxLogsProcessor, + RelayedTxV3Processor: processDisabled.NewRelayedTxV3Processor(), + FailedTxLogsAccumulator: processDisabled.NewFailedTxLogsAccumulator(), } transactionProcessor, err := transaction.NewTxProcessor(argsNewTxProcessor) if err != nil { diff --git a/go.mod b/go.mod index 6e9c9a23328..4667bd06e7e 100644 --- a/go.mod +++ b/go.mod @@ -14,18 +14,18 @@ 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.0.15-0.20240508074652-e128a1c05c8e - github.com/multiversx/mx-chain-core-go v1.2.21-0.20240508071047-fefea5737840 - github.com/multiversx/mx-chain-crypto-go v1.2.12-0.20240508074452-cc21c1b505df - github.com/multiversx/mx-chain-es-indexer-go v1.7.2-0.20240514103357-929ece92ef86 - github.com/multiversx/mx-chain-logger-go v1.0.15-0.20240508072523-3f00a726af57 - github.com/multiversx/mx-chain-scenario-go v1.4.4-0.20240509103754-9e8129721f00 - github.com/multiversx/mx-chain-storage-go v1.0.16-0.20240508073549-dcb8e6e0370f - github.com/multiversx/mx-chain-vm-common-go v1.5.13-0.20240529093845-2a375eef5cc1 - github.com/multiversx/mx-chain-vm-go v1.5.30-0.20240509104139-8b0eaa8a85d1 - github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68-0.20240509103859-89de3c5da36b - github.com/multiversx/mx-chain-vm-v1_3-go v1.3.69-0.20240509104009-598a37ff36b9 - github.com/multiversx/mx-chain-vm-v1_4-go v1.4.98-0.20240509104102-2a6a709b4041 + github.com/multiversx/mx-chain-communication-go v1.1.0 + github.com/multiversx/mx-chain-core-go v1.2.21 + github.com/multiversx/mx-chain-crypto-go v1.2.12 + github.com/multiversx/mx-chain-es-indexer-go v1.7.4 + 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 + github.com/multiversx/mx-chain-vm-common-go v1.5.13 + github.com/multiversx/mx-chain-vm-go v1.5.32-0.20240808073353-f1fbbf147537 + github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68 + github.com/multiversx/mx-chain-vm-v1_3-go v1.3.69 + github.com/multiversx/mx-chain-vm-v1_4-go v1.4.98 github.com/pelletier/go-toml v1.9.3 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.14.0 diff --git a/go.sum b/go.sum index a98f8ba06c2..11a9bc62556 100644 --- a/go.sum +++ b/go.sum @@ -129,7 +129,6 @@ github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -262,7 +261,6 @@ github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZl github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -270,7 +268,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -388,37 +385,34 @@ 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.0.15-0.20240508074652-e128a1c05c8e h1:Tsmwhu+UleE+l3buPuqXSKTqfu5FbPmzQ4MjMoUvCWA= -github.com/multiversx/mx-chain-communication-go v1.0.15-0.20240508074652-e128a1c05c8e/go.mod h1:2yXl18wUbuV3cRZr7VHxM1xo73kTaC1WUcu2kx8R034= -github.com/multiversx/mx-chain-core-go v1.2.21-0.20240508071047-fefea5737840 h1:2mCrTUmbbA+Xv4UifZY9xptrGjcJBcJ2wavSb4FwejU= -github.com/multiversx/mx-chain-core-go v1.2.21-0.20240508071047-fefea5737840/go.mod h1:B5zU4MFyJezmEzCsAHE9YNULmGCm2zbPHvl9hazNxmE= -github.com/multiversx/mx-chain-crypto-go v1.2.12-0.20240508074452-cc21c1b505df h1:clihfi78bMEOWk/qw6WA4uQbCM2e2NGliqswLAvw19k= -github.com/multiversx/mx-chain-crypto-go v1.2.12-0.20240508074452-cc21c1b505df/go.mod h1:gtJYB4rR21KBSqJlazn+2z6f9gFSqQP3KvAgL7Qgxw4= -github.com/multiversx/mx-chain-es-indexer-go v1.7.2-0.20240514103357-929ece92ef86 h1:rw+u7qv0HO+7lRddCzfciqDcAWL9/fl2LQqU8AmVtdU= -github.com/multiversx/mx-chain-es-indexer-go v1.7.2-0.20240514103357-929ece92ef86/go.mod h1:UDKRXmxsSyPeAcjLUfGeYkAtYp424PIYkL82kzFYobM= -github.com/multiversx/mx-chain-logger-go v1.0.15-0.20240508072523-3f00a726af57 h1:g9t410dqjcb7UUptbVd/H6Ua12sEzWU4v7VplyNvRZ0= -github.com/multiversx/mx-chain-logger-go v1.0.15-0.20240508072523-3f00a726af57/go.mod h1:cY6CIXpndW5g5PTPn4WzPwka/UBEf+mgw+PSY5pHGAU= -github.com/multiversx/mx-chain-scenario-go v1.4.4-0.20240509103754-9e8129721f00 h1:hFEcbGBtXu8UyB9BMhmAIH2R8BtV/NOq/rsxespLCN8= -github.com/multiversx/mx-chain-scenario-go v1.4.4-0.20240509103754-9e8129721f00/go.mod h1:pnIIfWopbDMQ1EW5Ddc6KDMqv8Qtx+hxbH9rorHpCyo= -github.com/multiversx/mx-chain-storage-go v1.0.16-0.20240508073549-dcb8e6e0370f h1:yd/G8iPBGOEAwbaS8zndJpO6bQk7Tk72ZhmlqRasThI= -github.com/multiversx/mx-chain-storage-go v1.0.16-0.20240508073549-dcb8e6e0370f/go.mod h1:E6nfj9EQzGxWDGM3Dn6eZWRC3qFy1G8IqOsYsBOcgWw= -github.com/multiversx/mx-chain-vm-common-go v1.5.13-0.20240509103544-247ce5639c7a h1:7M+jXVlnl43zd2NuimL1KnAVAdpUr/QoHqG0TUKoyaM= -github.com/multiversx/mx-chain-vm-common-go v1.5.13-0.20240509103544-247ce5639c7a/go.mod h1:RgGmPei0suQcFTHfO4cS5dxJSiokp2SM5lmNgp1icMo= -github.com/multiversx/mx-chain-vm-common-go v1.5.13-0.20240529093845-2a375eef5cc1 h1:C6NQcbfusGkhWP2FNvzafX2w7lKGSzZIius/fM5Gm3c= -github.com/multiversx/mx-chain-vm-common-go v1.5.13-0.20240529093845-2a375eef5cc1/go.mod h1:RgGmPei0suQcFTHfO4cS5dxJSiokp2SM5lmNgp1icMo= -github.com/multiversx/mx-chain-vm-go v1.5.30-0.20240509104139-8b0eaa8a85d1 h1:5/h1i7Xd/JH9CiO3ZqvzAjdze+mAbar5sWkh2UqfLgI= -github.com/multiversx/mx-chain-vm-go v1.5.30-0.20240509104139-8b0eaa8a85d1/go.mod h1:N3Oa8QeeHlSip4nbESQpVSLgi/WxtgIwvqfXIZm6gDs= -github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68-0.20240509103859-89de3c5da36b h1:puYO0lUyPGA5kZqsiDjGa+daDGQwj9xFs0S5urhZjU8= -github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68-0.20240509103859-89de3c5da36b/go.mod h1:SY95hGdAIc8YCGb4uNSy1ux8V8qQbF1ReZJDwQ6AqEo= -github.com/multiversx/mx-chain-vm-v1_3-go v1.3.69-0.20240509104009-598a37ff36b9 h1:rrkgAS58jRXc6LThPHY5fm3AnFoUa0VUiYkH5czdlYg= -github.com/multiversx/mx-chain-vm-v1_3-go v1.3.69-0.20240509104009-598a37ff36b9/go.mod h1:TiOTsz2kxHadU0It7okOwcynyNPePXzjyl7lnpGLlUQ= -github.com/multiversx/mx-chain-vm-v1_4-go v1.4.98-0.20240509104102-2a6a709b4041 h1:k0xkmCrJiQzsWk4ZM3oNQ31lheiDvd1qQnNwnyuZzXU= -github.com/multiversx/mx-chain-vm-v1_4-go v1.4.98-0.20240509104102-2a6a709b4041/go.mod h1:XeZNaDMV0hbDlm3JtW0Hj3mCWKaB/XecQlCzEjiK5L8= +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.21 h1:+XVKznPTlUU5EFS1A8chtS8fStW60upRIyF4Pgml19I= +github.com/multiversx/mx-chain-core-go v1.2.21/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.4 h1:SjJk9G9SN8baz0sFIU2jymYCfx3XiikGEB2wW0jwvfw= +github.com/multiversx/mx-chain-es-indexer-go v1.7.4/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= +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.16 h1:l2lJq+EAN3YwLbjJrnoKfFd1/1Xmo9DcAUECND2obLs= +github.com/multiversx/mx-chain-storage-go v1.0.16/go.mod h1:uM/z7YyqTOD3wgyH8TfapyEl5sb+7x/Jaxne4cfG4HI= +github.com/multiversx/mx-chain-vm-common-go v1.5.13 h1:ymnIHJW4Z4mFa0hZzla4fozkF30vjH5O1q+Y7Ftc+pQ= +github.com/multiversx/mx-chain-vm-common-go v1.5.13/go.mod h1:OSvFbzdWThfRbLZbUsEr7bikBSaLrPJQ2iUm9jw9nXQ= +github.com/multiversx/mx-chain-vm-go v1.5.32-0.20240808073353-f1fbbf147537 h1:x1Fn0tlkicBNsRB/co/c9TTjyvCrzmE/rVXA8uUWhII= +github.com/multiversx/mx-chain-vm-go v1.5.32-0.20240808073353-f1fbbf147537/go.mod h1:iq6sCPweoHC9Fx56uf8buPrqlGVGJKUMRFxTunzjvys= +github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68 h1:L3GoAVFtLLzr9ya0rVv1YdTUzS3MyM7kQNBSAjCNO2g= +github.com/multiversx/mx-chain-vm-v1_2-go v1.2.68/go.mod h1:ixxwib+1pXwSDHG5Wa34v0SRScF+BwFzH4wFWY31saI= +github.com/multiversx/mx-chain-vm-v1_3-go v1.3.69 h1:G/PLsyfQV4bMLs2amGRvaLKZoW1DC7M+7ecVaLuaCNc= +github.com/multiversx/mx-chain-vm-v1_3-go v1.3.69/go.mod h1:msY3zaS+K+R10ypqQs/jke6xdNAJzS38PGIaeJj2zhg= +github.com/multiversx/mx-chain-vm-v1_4-go v1.4.98 h1:/fYx4ClVPU48pTKh2qk4QVlve0xjjDpvzOakjFUtXJ8= +github.com/multiversx/mx-chain-vm-v1_4-go v1.4.98/go.mod h1:4vqG8bSmufZx263DMrmr8OLbO6q6//VPC4W9PxZLB5Q= github.com/multiversx/mx-components-big-int v1.0.0 h1:Wkr8lSzK2nDqixOrrBa47VNuqdhV1m/aJhaP1EMaiS8= github.com/multiversx/mx-components-big-int v1.0.0/go.mod h1:maIEMgHlNE2u78JaDD0oLzri+ShgU4okHfzP3LWGdQM= github.com/multiversx/protobuf v1.3.2 h1:RaNkxvGTGbA0lMcnHAN24qE1G1i+Xs5yHA6MDvQ4mSM= github.com/multiversx/protobuf v1.3.2/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d h1:x3S6kxmy49zXVVyhcnrFqxvNVCBPb2KZ9hV2RBdS840= diff --git a/integrationTests/chainSimulator/relayedTx/relayedTx_test.go b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go new file mode 100644 index 00000000000..72bc9575763 --- /dev/null +++ b/integrationTests/chainSimulator/relayedTx/relayedTx_test.go @@ -0,0 +1,707 @@ +package relayedTx + +import ( + "encoding/hex" + "encoding/json" + "math/big" + "strconv" + "strings" + "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/integrationTests/vm/wasm" + "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/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/multiversx/mx-chain-go/sharding" + "github.com/stretchr/testify/require" +) + +const ( + defaultPathToInitialConfig = "../../../cmd/node/config/" + minGasPrice = 1_000_000_000 + minGasLimit = 50_000 + guardAccountCost = 250_000 + extraGasLimitForGuarded = minGasLimit + txVersion = 2 + mockTxSignature = "sig" + maxNumOfBlocksToGenerateWhenExecutingTx = 10 + roundsPerEpoch = 30 +) + +var ( + oneEGLD = big.NewInt(1000000000000000000) + alterConfigsFuncRelayedV3EarlyActivation = func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.RelayedTransactionsV3EnableEpoch = 1 + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = 1 + } +) + +func TestRelayedTransactionInMultiShardEnvironmentWithChainSimulator(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + cs := startChainSimulator(t, alterConfigsFuncRelayedV3EarlyActivation) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(30000)) + relayer, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + receiver, err := cs.GenerateAndMintWalletAddress(1, big.NewInt(0)) + require.NoError(t, err) + + err = cs.GenerateBlocks(1) + require.Nil(t, err) + + innerTx := generateTransaction(sender.Bytes, 0, receiver.Bytes, oneEGLD, "", minGasLimit) + innerTx.RelayerAddr = relayer.Bytes + + sender2, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + receiver2, err := cs.GenerateAndMintWalletAddress(0, big.NewInt(0)) + require.NoError(t, err) + + err = cs.GenerateBlocks(1) + require.Nil(t, err) + + innerTx2 := generateTransaction(sender2.Bytes, 0, receiver2.Bytes, oneEGLD, "", minGasLimit) + innerTx2.RelayerAddr = relayer.Bytes + + pkConv := cs.GetNodeHandler(0).GetCoreComponents().AddressPubKeyConverter() + + // innerTx3Failure should fail due to less gas limit + // deploy a wrapper contract + owner, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + err = cs.GenerateBlocks(1) + require.Nil(t, err) + + scCode := wasm.GetSCCode("testData/egld-esdt-swap.wasm") + params := []string{scCode, wasm.VMTypeHex, wasm.DummyCodeMetadataHex, hex.EncodeToString([]byte("WEGLD"))} + txDataDeploy := strings.Join(params, "@") + deployTx := generateTransaction(owner.Bytes, 0, make([]byte, 32), big.NewInt(0), txDataDeploy, 600000000) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(deployTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + scAddress := result.Logs.Events[0].Address + scAddressBytes, _ := pkConv.Decode(scAddress) + + // try a wrap transaction which will fail as the contract is paused + txDataWrap := "wrapEgld" + gasLimit := 2300000 + innerTx3Failure := generateTransaction(owner.Bytes, 1, scAddressBytes, big.NewInt(1), txDataWrap, uint64(gasLimit)) + innerTx3Failure.RelayerAddr = relayer.Bytes + + innerTx3 := generateTransaction(sender.Bytes, 1, receiver2.Bytes, oneEGLD, "", minGasLimit) + innerTx3.RelayerAddr = relayer.Bytes + + innerTxs := []*transaction.Transaction{innerTx, innerTx2, innerTx3Failure, innerTx3} + + // relayer will consume first a move balance for each inner tx, then the specific gas for each inner tx + relayedTxGasLimit := uint64(0) + for _, tx := range innerTxs { + relayedTxGasLimit += minGasLimit + tx.GasLimit + } + relayedTx := generateTransaction(relayer.Bytes, 0, relayer.Bytes, big.NewInt(0), "", relayedTxGasLimit) + relayedTx.InnerTransactions = innerTxs + + result, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // generate few more blocks for the cross shard scrs to be done + err = cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + economicsData := cs.GetNodeHandler(0).GetCoreComponents().EconomicsData() + relayerMoveBalanceFee := economicsData.ComputeMoveBalanceFee(relayedTx) + expectedRelayerFee := big.NewInt(0).Mul(relayerMoveBalanceFee, big.NewInt(int64(len(relayedTx.InnerTransactions)))) + for _, tx := range innerTxs { + expectedRelayerFee.Add(expectedRelayerFee, economicsData.ComputeTxFee(tx)) + } + checkBalance(t, cs, relayer, big.NewInt(0).Sub(initialBalance, expectedRelayerFee)) + + checkBalance(t, cs, sender, big.NewInt(0).Sub(initialBalance, big.NewInt(0).Mul(oneEGLD, big.NewInt(2)))) + + checkBalance(t, cs, sender2, big.NewInt(0).Sub(initialBalance, oneEGLD)) + + checkBalance(t, cs, receiver, oneEGLD) + + checkBalance(t, cs, receiver2, big.NewInt(0).Mul(oneEGLD, big.NewInt(2))) + + // check SCRs + shardC := cs.GetNodeHandler(0).GetShardCoordinator() + for _, scr := range result.SmartContractResults { + checkSCRSucceeded(t, cs, pkConv, shardC, scr) + } + + // 3 log events from the failed sc call + require.Equal(t, 3, len(result.Logs.Events)) + require.True(t, strings.Contains(string(result.Logs.Events[2].Data), "contract is paused")) +} + +func TestRelayedTransactionInMultiShardEnvironmentWithChainSimulatorScCalls(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + cs := startChainSimulator(t, alterConfigsFuncRelayedV3EarlyActivation) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + pkConv := cs.GetNodeHandler(0).GetCoreComponents().AddressPubKeyConverter() + shardC := cs.GetNodeHandler(0).GetShardCoordinator() + + // deploy adder contract + owner, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + err = cs.GenerateBlocks(1) + require.Nil(t, err) + + ownerNonce := uint64(0) + scCode := wasm.GetSCCode("testData/adder.wasm") + params := []string{scCode, wasm.VMTypeHex, wasm.DummyCodeMetadataHex, "00"} + txDataDeploy := strings.Join(params, "@") + deployTx := generateTransaction(owner.Bytes, ownerNonce, make([]byte, 32), big.NewInt(0), txDataDeploy, 100000000) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(deployTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + scAddress := result.Logs.Events[0].Address + scAddressBytes, _ := pkConv.Decode(scAddress) + scShard := shardC.ComputeId(scAddressBytes) + scShardNodeHandler := cs.GetNodeHandler(scShard) + + // 1st inner tx, successful add 1 + ownerNonce++ + txDataAdd := "add@" + hex.EncodeToString(big.NewInt(1).Bytes()) + innerTx1 := generateTransaction(owner.Bytes, ownerNonce, scAddressBytes, big.NewInt(0), txDataAdd, 5000000) + innerTx1.RelayerAddr = relayer.Bytes + + // 2nd inner tx, successful add 1 + ownerNonce++ + innerTx2 := generateTransaction(owner.Bytes, ownerNonce, scAddressBytes, big.NewInt(0), txDataAdd, 5000000) + innerTx2.RelayerAddr = relayer.Bytes + + // 3rd inner tx, wrong number of parameters + ownerNonce++ + innerTx3 := generateTransaction(owner.Bytes, ownerNonce, scAddressBytes, big.NewInt(0), "add", 5000000) + innerTx3.RelayerAddr = relayer.Bytes + + // 4th inner tx, successful add 1 + ownerNonce++ + innerTx4 := generateTransaction(owner.Bytes, ownerNonce, scAddressBytes, big.NewInt(0), txDataAdd, 5000000) + innerTx4.RelayerAddr = relayer.Bytes + + // 5th inner tx, invalid function + ownerNonce++ + innerTx5 := generateTransaction(owner.Bytes, ownerNonce, scAddressBytes, big.NewInt(0), "substract", 5000000) + innerTx5.RelayerAddr = relayer.Bytes + + // 6th inner tx, successful add 1 + ownerNonce++ + innerTx6 := generateTransaction(owner.Bytes, ownerNonce, scAddressBytes, big.NewInt(0), txDataAdd, 5000000) + innerTx6.RelayerAddr = relayer.Bytes + + // 7th inner tx, not enough gas + ownerNonce++ + innerTx7 := generateTransaction(owner.Bytes, ownerNonce, scAddressBytes, big.NewInt(0), txDataAdd, 100000) + innerTx7.RelayerAddr = relayer.Bytes + + innerTxs := []*transaction.Transaction{innerTx1, innerTx2, innerTx3, innerTx4, innerTx5, innerTx6, innerTx7} + + relayedTxGasLimit := uint64(0) + for _, tx := range innerTxs { + relayedTxGasLimit += minGasLimit + tx.GasLimit + } + relayedTx := generateTransaction(relayer.Bytes, 0, relayer.Bytes, big.NewInt(0), "", relayedTxGasLimit) + relayedTx.InnerTransactions = innerTxs + + result, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + checkSum(t, scShardNodeHandler, scAddressBytes, owner.Bytes, 4) + + // 8 scrs, 4 from the succeeded txs + 4 with refunded gas to relayer + require.Equal(t, 8, len(result.SmartContractResults)) + for _, scr := range result.SmartContractResults { + if strings.Contains(scr.ReturnMessage, "gas refund for relayer") { + continue + } + + checkSCRSucceeded(t, cs, pkConv, shardC, scr) + } + + // 6 events, 3 with signalError + 3 with the actual errors + require.Equal(t, 6, len(result.Logs.Events)) + expectedLogEvents := map[int]string{ + 1: "[wrong number of arguments]", + 3: "[invalid function (not found)] [substract]", + 5: "[not enough gas] [add]", + } + for idx, logEvent := range result.Logs.Events { + if logEvent.Identifier == "signalError" { + continue + } + + expectedLogEvent := expectedLogEvents[idx] + require.True(t, strings.Contains(string(logEvent.Data), expectedLogEvent)) + } +} + +func TestFixRelayedMoveBalanceWithChainSimulator(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + expectedFeeScCallBefore := "815294920000000" + expectedFeeScCallAfter := "873704920000000" + t.Run("sc call", testFixRelayedMoveBalanceWithChainSimulatorScCall(expectedFeeScCallBefore, expectedFeeScCallAfter)) + + expectedFeeMoveBalanceBefore := "797500000000000" // 498 * 1500 + 50000 + 5000 + expectedFeeMoveBalanceAfter := "847000000000000" // 498 * 1500 + 50000 + 50000 + t.Run("move balance", testFixRelayedMoveBalanceWithChainSimulatorMoveBalance(expectedFeeMoveBalanceBefore, expectedFeeMoveBalanceAfter)) +} + +func testFixRelayedMoveBalanceWithChainSimulatorScCall( + expectedFeeBeforeFix string, + expectedFeeAfterFix string, +) func(t *testing.T) { + return func(t *testing.T) { + + providedActivationEpoch := uint32(7) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + pkConv := cs.GetNodeHandler(0).GetCoreComponents().AddressPubKeyConverter() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + // deploy adder contract + owner, 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) + + scCode := wasm.GetSCCode("testData/adder.wasm") + params := []string{scCode, wasm.VMTypeHex, wasm.DummyCodeMetadataHex, "00"} + txDataDeploy := strings.Join(params, "@") + deployTx := generateTransaction(owner.Bytes, 0, make([]byte, 32), big.NewInt(0), txDataDeploy, 100000000) + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(deployTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + scAddress := result.Logs.Events[0].Address + scAddressBytes, _ := pkConv.Decode(scAddress) + + // fast-forward until epoch 4 + err = cs.GenerateBlocksUntilEpochIsReached(int32(4)) + require.NoError(t, err) + + // send relayed tx + txDataAdd := "add@" + hex.EncodeToString(big.NewInt(1).Bytes()) + innerTx := generateTransaction(owner.Bytes, 1, scAddressBytes, big.NewInt(0), txDataAdd, 3000000) + marshalledTx, err := json.Marshal(innerTx) + require.NoError(t, err) + txData := []byte("relayedTx@" + hex.EncodeToString(marshalledTx)) + gasLimit := 50000 + uint64(len(txData))*1500 + innerTx.GasLimit + + relayedTx := generateTransaction(relayer.Bytes, 0, owner.Bytes, big.NewInt(0), string(txData), gasLimit) + + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // send relayed tx, fix still not active + innerTx = generateTransaction(owner.Bytes, 2, scAddressBytes, big.NewInt(0), txDataAdd, 3000000) + marshalledTx, err = json.Marshal(innerTx) + require.NoError(t, err) + txData = []byte("relayedTx@" + hex.EncodeToString(marshalledTx)) + gasLimit = 50000 + uint64(len(txData))*1500 + innerTx.GasLimit + + relayedTx = generateTransaction(relayer.Bytes, 1, owner.Bytes, big.NewInt(0), string(txData), gasLimit) + + relayerBalanceBefore := getBalance(t, cs, relayer) + + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + relayerBalanceAfter := getBalance(t, cs, relayer) + + feeConsumed := big.NewInt(0).Sub(relayerBalanceBefore, relayerBalanceAfter) + + require.Equal(t, expectedFeeBeforeFix, feeConsumed.String()) + + // fast-forward until the fix is active + err = cs.GenerateBlocksUntilEpochIsReached(int32(providedActivationEpoch)) + require.NoError(t, err) + + // send relayed tx after fix + innerTx = generateTransaction(owner.Bytes, 3, scAddressBytes, big.NewInt(0), txDataAdd, 3000000) + marshalledTx, err = json.Marshal(innerTx) + require.NoError(t, err) + txData = []byte("relayedTx@" + hex.EncodeToString(marshalledTx)) + gasLimit = 50000 + uint64(len(txData))*1500 + innerTx.GasLimit + + relayedTx = generateTransaction(relayer.Bytes, 2, owner.Bytes, big.NewInt(0), string(txData), gasLimit) + + relayerBalanceBefore = getBalance(t, cs, relayer) + + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + relayerBalanceAfter = getBalance(t, cs, relayer) + + feeConsumed = big.NewInt(0).Sub(relayerBalanceBefore, relayerBalanceAfter) + + require.Equal(t, expectedFeeAfterFix, feeConsumed.String()) + } +} + +func testFixRelayedMoveBalanceWithChainSimulatorMoveBalance( + expectedFeeBeforeFix string, + expectedFeeAfterFix string, +) func(t *testing.T) { + return func(t *testing.T) { + + providedActivationEpoch := uint32(5) + alterConfigsFunc := func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.FixRelayedBaseCostEnableEpoch = providedActivationEpoch + } + + cs := startChainSimulator(t, alterConfigsFunc) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + receiver, err := cs.GenerateAndMintWalletAddress(0, big.NewInt(0)) + require.NoError(t, err) + + // generate one block so the minting has effect + err = cs.GenerateBlocks(1) + require.NoError(t, err) + + // send relayed tx + innerTx := generateTransaction(sender.Bytes, 0, receiver.Bytes, oneEGLD, "", 50000) + marshalledTx, err := json.Marshal(innerTx) + require.NoError(t, err) + txData := []byte("relayedTx@" + hex.EncodeToString(marshalledTx)) + gasLimit := 50000 + uint64(len(txData))*1500 + innerTx.GasLimit + + relayedTx := generateTransaction(relayer.Bytes, 0, sender.Bytes, big.NewInt(0), string(txData), gasLimit) + + relayerBalanceBefore := getBalance(t, cs, relayer) + + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + relayerBalanceAfter := getBalance(t, cs, relayer) + + feeConsumed := big.NewInt(0).Sub(relayerBalanceBefore, relayerBalanceAfter) + + require.Equal(t, expectedFeeBeforeFix, feeConsumed.String()) + + // fast-forward until the fix is active + err = cs.GenerateBlocksUntilEpochIsReached(int32(providedActivationEpoch)) + require.NoError(t, err) + + // send relayed tx + innerTx = generateTransaction(sender.Bytes, 1, receiver.Bytes, oneEGLD, "", 50000) + marshalledTx, err = json.Marshal(innerTx) + require.NoError(t, err) + txData = []byte("relayedTx@" + hex.EncodeToString(marshalledTx)) + gasLimit = 50000 + uint64(len(txData))*1500 + innerTx.GasLimit + + relayedTx = generateTransaction(relayer.Bytes, 1, sender.Bytes, big.NewInt(0), string(txData), gasLimit) + + relayerBalanceBefore = getBalance(t, cs, relayer) + + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + relayerBalanceAfter = getBalance(t, cs, relayer) + + feeConsumed = big.NewInt(0).Sub(relayerBalanceBefore, relayerBalanceAfter) + + require.Equal(t, expectedFeeAfterFix, feeConsumed.String()) + } +} + +func TestRelayedTransactionInMultiShardEnvironmentWithChainSimulatorInnerNotExecutable(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + cs := startChainSimulator(t, alterConfigsFuncRelayedV3EarlyActivation) + defer cs.Close() + + initialBalance := big.NewInt(0).Mul(oneEGLD, big.NewInt(10)) + relayer, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + sender, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + sender2, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + guardian, err := cs.GenerateAndMintWalletAddress(0, initialBalance) + require.NoError(t, err) + + err = cs.GenerateBlocks(1) + require.Nil(t, err) + + // Set guardian for sender + senderNonce := uint64(0) + 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) + + // fast-forward until the guardian becomes active + err = cs.GenerateBlocks(roundsPerEpoch * 20) + require.NoError(t, err) + + // guard account + senderNonce++ + 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) + + receiver, err := cs.GenerateAndMintWalletAddress(1, big.NewInt(0)) + require.NoError(t, err) + + // move balance inner transaction non-executable due to guardian mismatch + senderNonce++ + innerTx := generateTransaction(sender.Bytes, senderNonce, receiver.Bytes, oneEGLD, "", minGasLimit+extraGasLimitForGuarded) + innerTx.RelayerAddr = relayer.Bytes + innerTx.GuardianAddr = sender.Bytes // this is not the real guardian + innerTx.GuardianSignature = []byte(mockTxSignature) + innerTx.Options = 2 + + // move balance inner transaction non-executable due to higher nonce + nonceTooHigh := uint64(100) + innerTx2 := generateTransaction(sender2.Bytes, nonceTooHigh, receiver.Bytes, oneEGLD, "", minGasLimit) + innerTx2.RelayerAddr = relayer.Bytes + + innerTxs := []*transaction.Transaction{innerTx, innerTx2} + + // relayer will consume first a move balance for each inner tx, then the specific gas for each inner tx + relayedTxGasLimit := uint64(0) + for _, tx := range innerTxs { + relayedTxGasLimit += minGasLimit + tx.GasLimit + } + relayedTx := generateTransaction(relayer.Bytes, 0, relayer.Bytes, big.NewInt(0), "", relayedTxGasLimit) + relayedTx.InnerTransactions = innerTxs + + result, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // generate few more blocks for the cross shard scrs to be done + err = cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // check the inner tx failed with the desired error + require.Equal(t, 2, len(result.SmartContractResults)) + require.True(t, strings.Contains(result.SmartContractResults[0].ReturnMessage, process.ErrTransactionNotExecutable.Error())) + require.True(t, strings.Contains(result.SmartContractResults[0].ReturnMessage, process.ErrTransactionAndAccountGuardianMismatch.Error())) + require.True(t, strings.Contains(result.SmartContractResults[1].ReturnMessage, process.ErrHigherNonceInTransaction.Error())) + + // check events + require.Equal(t, 2, len(result.Logs.Events)) + for _, event := range result.Logs.Events { + require.Equal(t, core.SignalErrorOperation, event.Identifier) + } + + // compute expected consumed fee for relayer + expectedConsumedGasForGuardedInnerTx := minGasLimit + minGasLimit + extraGasLimitForGuarded // invalid guardian + expectedConsumedGasForHigherNonceInnerTx := minGasLimit + minGasLimit // higher nonce + expectedConsumeGas := expectedConsumedGasForGuardedInnerTx + expectedConsumedGasForHigherNonceInnerTx + expectedRelayerFee := core.SafeMul(uint64(expectedConsumeGas), minGasPrice) + checkBalance(t, cs, relayer, big.NewInt(0).Sub(initialBalance, expectedRelayerFee)) + + checkBalance(t, cs, receiver, big.NewInt(0)) + + relayerBalanceBeforeSuccessfullAttempt := getBalance(t, cs, relayer) + + // generate a valid guarded move balance inner tx + // senderNonce would be the same, as previous failed tx didn't increase it(expected) + innerTx = generateTransaction(sender.Bytes, senderNonce, receiver.Bytes, oneEGLD, "", minGasLimit+extraGasLimitForGuarded) + innerTx.RelayerAddr = relayer.Bytes + innerTx.GuardianAddr = guardian.Bytes + innerTx.GuardianSignature = []byte(mockTxSignature) + innerTx.Options = 2 + + innerTxs = []*transaction.Transaction{innerTx} + relayedTx = generateTransaction(relayer.Bytes, 1, relayer.Bytes, big.NewInt(0), "", relayedTxGasLimit) + relayedTx.InnerTransactions = innerTxs + + _, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(relayedTx, maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + // generate few more blocks for the cross shard scrs to be done + err = cs.GenerateBlocks(maxNumOfBlocksToGenerateWhenExecutingTx) + require.NoError(t, err) + + expectedRelayerFee = core.SafeMul(uint64(expectedConsumedGasForGuardedInnerTx), minGasPrice) + checkBalance(t, cs, relayer, big.NewInt(0).Sub(relayerBalanceBeforeSuccessfullAttempt, expectedRelayerFee)) + + checkBalance(t, cs, receiver, oneEGLD) +} + +func startChainSimulator( + t *testing.T, + alterConfigsFunction func(cfg *config.Configs), +) testsChainSimulator.ChainSimulator { + roundDurationInMillis := uint64(6000) + roundsPerEpochOpt := core.OptionalUint64{ + HasValue: true, + Value: roundsPerEpoch, + } + + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: 3, + GenesisTimestamp: time.Now().Unix(), + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpochOpt, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 3, + NumNodesWaitingListShard: 3, + AlterConfigsFunction: alterConfigsFunction, + }) + require.NoError(t, err) + require.NotNil(t, cs) + + err = cs.GenerateBlocksUntilEpochIsReached(1) + require.NoError(t, err) + + return cs +} + +func generateTransaction(sender []byte, nonce uint64, receiver []byte, value *big.Int, data string, gasLimit uint64) *transaction.Transaction { + return &transaction.Transaction{ + Nonce: nonce, + Value: value, + SndAddr: sender, + RcvAddr: receiver, + Data: []byte(data), + GasLimit: gasLimit, + GasPrice: minGasPrice, + ChainID: []byte(configs.ChainID), + Version: txVersion, + Signature: []byte(mockTxSignature), + } +} + +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 checkSCRSucceeded( + t *testing.T, + cs testsChainSimulator.ChainSimulator, + pkConv core.PubkeyConverter, + shardC sharding.Coordinator, + scr *transaction.ApiSmartContractResult, +) { + 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) + } +} + +func getBalance( + t *testing.T, + cs testsChainSimulator.ChainSimulator, + address dtos.WalletAddress, +) *big.Int { + account, err := cs.GetAccount(address) + require.NoError(t, err) + + balance, ok := big.NewInt(0).SetString(account.Balance, 10) + require.True(t, ok) + + return balance +} + +func checkBalance( + t *testing.T, + cs testsChainSimulator.ChainSimulator, + address dtos.WalletAddress, + expectedBalance *big.Int, +) { + balance := getBalance(t, cs, address) + require.Equal(t, expectedBalance.String(), balance.String()) +} diff --git a/integrationTests/chainSimulator/relayedTx/testData/adder.wasm b/integrationTests/chainSimulator/relayedTx/testData/adder.wasm new file mode 100644 index 00000000000..b6bc9b4e13b Binary files /dev/null and b/integrationTests/chainSimulator/relayedTx/testData/adder.wasm differ diff --git a/integrationTests/chainSimulator/relayedTx/testData/egld-esdt-swap.wasm b/integrationTests/chainSimulator/relayedTx/testData/egld-esdt-swap.wasm new file mode 100644 index 00000000000..7244307f1cc Binary files /dev/null and b/integrationTests/chainSimulator/relayedTx/testData/egld-esdt-swap.wasm differ diff --git a/integrationTests/chainSimulator/staking/jail/jail_test.go b/integrationTests/chainSimulator/staking/jail/jail_test.go index d306156d7b3..bb449da993f 100644 --- a/integrationTests/chainSimulator/staking/jail/jail_test.go +++ b/integrationTests/chainSimulator/staking/jail/jail_test.go @@ -67,7 +67,7 @@ func testChainSimulatorJailAndUnJail(t *testing.T, targetEpoch int32, nodeStatus numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -99,6 +99,9 @@ func testChainSimulatorJailAndUnJail(t *testing.T, targetEpoch int32, nodeStatus walletAddress, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(walletAddress.Bytes, 0, vm.ValidatorSCAddress, chainSimulatorIntegrationTests.MinimumStakeValue, txDataField, staking.GasLimitForStakeOperation) stakeTx, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(txStake, staking.MaxNumOfBlockToGenerateWhenExecutingTx) @@ -167,7 +170,7 @@ func TestChainSimulator_FromQueueToAuctionList(t *testing.T) { numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -203,6 +206,9 @@ func TestChainSimulator_FromQueueToAuctionList(t *testing.T) { walletAddress, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(walletAddress.Bytes, 0, vm.ValidatorSCAddress, chainSimulatorIntegrationTests.MinimumStakeValue, txDataField, staking.GasLimitForStakeOperation) stakeTx, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(txStake, staking.MaxNumOfBlockToGenerateWhenExecutingTx) diff --git a/integrationTests/chainSimulator/staking/stake/simpleStake_test.go b/integrationTests/chainSimulator/staking/stake/simpleStake_test.go index 33ac33fecb7..bfc9f3c11b6 100644 --- a/integrationTests/chainSimulator/staking/stake/simpleStake_test.go +++ b/integrationTests/chainSimulator/staking/stake/simpleStake_test.go @@ -66,7 +66,7 @@ func testChainSimulatorSimpleStake(t *testing.T, targetEpoch int32, nodesStatus numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -94,6 +94,9 @@ func testChainSimulatorSimpleStake(t *testing.T, targetEpoch int32, nodesStatus wallet3, err := cs.GenerateAndMintWalletAddress(0, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + _, blsKeys, err := chainSimulator.GenerateBlsPrivateKeys(3) require.Nil(t, err) @@ -159,7 +162,7 @@ func TestChainSimulator_StakingV4Step2APICalls(t *testing.T) { stakingV4Step3Epoch := uint32(4) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -201,6 +204,9 @@ func TestChainSimulator_StakingV4Step2APICalls(t *testing.T) { validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + // Stake a new validator that should end up in auction in step 1 txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, chainSimulatorIntegrationTests.MinimumStakeValue, txDataField, staking.GasLimitForStakeOperation) diff --git a/integrationTests/chainSimulator/staking/stake/stakeAndUnStake_test.go b/integrationTests/chainSimulator/staking/stake/stakeAndUnStake_test.go index 8344c757d80..acb0c7537ed 100644 --- a/integrationTests/chainSimulator/staking/stake/stakeAndUnStake_test.go +++ b/integrationTests/chainSimulator/staking/stake/stakeAndUnStake_test.go @@ -57,7 +57,7 @@ func TestChainSimulator_AddValidatorKey(t *testing.T) { numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -103,6 +103,9 @@ func TestChainSimulator_AddValidatorKey(t *testing.T) { }) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + // Step 3 --- generate and send a stake transaction with the BLS key of the validator key that was added at step 1 stakeValue, _ := big.NewInt(0).SetString("2500000000000000000000", 10) tx := &transaction.Transaction{ @@ -189,7 +192,7 @@ func TestChainSimulator_AddANewValidatorAfterStakingV4(t *testing.T) { } numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -237,6 +240,9 @@ func TestChainSimulator_AddANewValidatorAfterStakingV4(t *testing.T) { }) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + // Step 3 --- generate and send a stake transaction with the BLS keys of the validators key that were added at step 1 validatorData := "" for _, blsKey := range blsKeys { @@ -318,7 +324,7 @@ func testStakeUnStakeUnBond(t *testing.T, targetEpoch int32) { } numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -353,6 +359,9 @@ func testStakeUnStakeUnBond(t *testing.T, targetEpoch int32) { walletAddress, err := cs.GenerateAndMintWalletAddress(walletAddressShardID, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(walletAddress.Bytes, 0, vm.ValidatorSCAddress, chainSimulatorIntegrationTests.MinimumStakeValue, txDataField, staking.GasLimitForStakeOperation) stakeTx, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(txStake, staking.MaxNumOfBlockToGenerateWhenExecutingTx) @@ -446,7 +455,7 @@ func TestChainSimulator_DirectStakingNodes_StakeFunds(t *testing.T) { t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -476,7 +485,7 @@ func TestChainSimulator_DirectStakingNodes_StakeFunds(t *testing.T) { t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -506,7 +515,7 @@ func TestChainSimulator_DirectStakingNodes_StakeFunds(t *testing.T) { t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -536,7 +545,7 @@ func TestChainSimulator_DirectStakingNodes_StakeFunds(t *testing.T) { t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -583,6 +592,9 @@ func testChainSimulatorDirectStakedNodesStakingFunds(t *testing.T, cs chainSimul validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + stakeValue := big.NewInt(0).Set(chainSimulatorIntegrationTests.MinimumStakeValue) txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, stakeValue, txDataField, staking.GasLimitForStakeOperation) @@ -668,7 +680,7 @@ func TestChainSimulator_DirectStakingNodes_UnstakeFundsWithDeactivation(t *testi t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -699,7 +711,7 @@ func TestChainSimulator_DirectStakingNodes_UnstakeFundsWithDeactivation(t *testi t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -731,7 +743,7 @@ func TestChainSimulator_DirectStakingNodes_UnstakeFundsWithDeactivation(t *testi t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -763,7 +775,7 @@ func TestChainSimulator_DirectStakingNodes_UnstakeFundsWithDeactivation(t *testi t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -811,6 +823,9 @@ func testChainSimulatorDirectStakedUnstakeFundsWithDeactivation(t *testing.T, cs validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + stakeValue := big.NewInt(0).Set(chainSimulatorIntegrationTests.MinimumStakeValue) txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, stakeValue, txDataField, staking.GasLimitForStakeOperation) @@ -949,7 +964,7 @@ func TestChainSimulator_DirectStakingNodes_UnstakeFundsWithDeactivation_WithReac t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -980,7 +995,7 @@ func TestChainSimulator_DirectStakingNodes_UnstakeFundsWithDeactivation_WithReac t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1012,7 +1027,7 @@ func TestChainSimulator_DirectStakingNodes_UnstakeFundsWithDeactivation_WithReac t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1044,7 +1059,7 @@ func TestChainSimulator_DirectStakingNodes_UnstakeFundsWithDeactivation_WithReac t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1092,6 +1107,9 @@ func testChainSimulatorDirectStakedUnstakeFundsWithDeactivationAndReactivation(t validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + stakeValue := big.NewInt(0).Set(chainSimulatorIntegrationTests.MinimumStakeValue) txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, stakeValue, txDataField, staking.GasLimitForStakeOperation) @@ -1186,7 +1204,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedFundsBeforeUnbonding( t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1216,7 +1234,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedFundsBeforeUnbonding( t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1246,7 +1264,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedFundsBeforeUnbonding( t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1276,7 +1294,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedFundsBeforeUnbonding( t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1322,6 +1340,9 @@ func testChainSimulatorDirectStakedWithdrawUnstakedFundsBeforeUnbonding(t *testi validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + stakeValue := big.NewInt(0).Mul(chainSimulatorIntegrationTests.OneEGLD, big.NewInt(2600)) txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, stakeValue, txDataField, staking.GasLimitForStakeOperation) @@ -1420,7 +1441,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInWithdrawEpoch(t *te t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1450,7 +1471,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInWithdrawEpoch(t *te t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1480,7 +1501,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInWithdrawEpoch(t *te t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1510,7 +1531,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInWithdrawEpoch(t *te t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1556,6 +1577,9 @@ func testChainSimulatorDirectStakedWithdrawUnstakedFundsInFirstEpoch(t *testing. validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + stakeValue := big.NewInt(0).Mul(chainSimulatorIntegrationTests.OneEGLD, big.NewInt(2600)) txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, stakeValue, txDataField, staking.GasLimitForStakeOperation) @@ -1683,7 +1707,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInBatches(t *testing. t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1715,7 +1739,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInBatches(t *testing. t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1747,7 +1771,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInBatches(t *testing. t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1779,7 +1803,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInBatches(t *testing. t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1827,6 +1851,9 @@ func testChainSimulatorDirectStakedWithdrawUnstakedFundsInBatches(t *testing.T, validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + stakeValue := big.NewInt(0).Mul(chainSimulatorIntegrationTests.OneEGLD, big.NewInt(2600)) txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, stakeValue, txDataField, staking.GasLimitForStakeOperation) @@ -2039,7 +2066,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInEpoch(t *testing.T) t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -2071,7 +2098,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInEpoch(t *testing.T) t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -2103,7 +2130,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInEpoch(t *testing.T) t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -2135,7 +2162,7 @@ func TestChainSimulator_DirectStakingNodes_WithdrawUnstakedInEpoch(t *testing.T) t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -2183,6 +2210,9 @@ func testChainSimulatorDirectStakedWithdrawUnstakedFundsInEpoch(t *testing.T, cs validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + stakeValue := big.NewInt(0).Mul(chainSimulatorIntegrationTests.OneEGLD, big.NewInt(2600)) txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) txStake := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, stakeValue, txDataField, staking.GasLimitForStakeOperation) @@ -2332,7 +2362,7 @@ func TestChainSimulator_UnStakeOneActiveNodeAndCheckAPIAuctionList(t *testing.T) numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -2411,7 +2441,7 @@ func TestChainSimulator_EdgeCaseLowWaitingList(t *testing.T) { numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -2524,6 +2554,9 @@ func createStakeTransaction(t *testing.T, cs chainSimulatorIntegrationTests.Chai validatorOwner, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + txDataField := fmt.Sprintf("stake@01@%s@%s", blsKeys[0], staking.MockBLSSignature) return chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.ValidatorSCAddress, chainSimulatorIntegrationTests.MinimumStakeValue, txDataField, staking.GasLimitForStakeOperation) } diff --git a/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go b/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go index 4697affa054..423faa3fbab 100644 --- a/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go +++ b/integrationTests/chainSimulator/staking/stakingProvider/delegation_test.go @@ -69,7 +69,7 @@ func TestChainSimulator_MakeNewContractFromValidatorData(t *testing.T) { // 6. Execute 2 unDelegate operations of 100 EGLD each, check the topup is back to 500 t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -113,7 +113,7 @@ func TestChainSimulator_MakeNewContractFromValidatorData(t *testing.T) { // 6. Execute 2 unDelegate operations of 100 EGLD each, check the topup is back to 500 t.Run("staking ph 4 is not active and all is done in epoch 0", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -164,7 +164,7 @@ func TestChainSimulator_MakeNewContractFromValidatorData(t *testing.T) { // 6. Execute 2 unDelegate operations of 100 EGLD each, check the topup is back to 500 t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -201,7 +201,7 @@ func TestChainSimulator_MakeNewContractFromValidatorData(t *testing.T) { // 6. Execute 2 unDelegate operations of 100 EGLD each, check the topup is back to 500 t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -238,7 +238,7 @@ func TestChainSimulator_MakeNewContractFromValidatorData(t *testing.T) { // 6. Execute 2 unDelegate operations of 100 EGLD each, check the topup is back to 500 t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -292,6 +292,9 @@ func testChainSimulatorMakeNewContractFromValidatorData(t *testing.T, cs chainSi delegator2, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + log.Info("working with the following addresses", "newValidatorOwner", validatorOwner.Bech32, "delegator1", delegator1.Bech32, "delegator2", delegator2.Bech32) @@ -487,7 +490,7 @@ func TestChainSimulator_MakeNewContractFromValidatorDataWith2StakingContracts(t t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -516,7 +519,7 @@ func TestChainSimulator_MakeNewContractFromValidatorDataWith2StakingContracts(t }) t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -545,7 +548,7 @@ func TestChainSimulator_MakeNewContractFromValidatorDataWith2StakingContracts(t }) t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -574,7 +577,7 @@ func TestChainSimulator_MakeNewContractFromValidatorDataWith2StakingContracts(t }) t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -625,6 +628,9 @@ func testChainSimulatorMakeNewContractFromValidatorDataWith2StakingContracts(t * validatorOwnerB, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + log.Info("working with the following addresses", "validatorOwnerA", validatorOwnerA.Bech32, "validatorOwnerB", validatorOwnerB.Bech32) @@ -712,7 +718,7 @@ func TestChainSimulatorMakeNewContractFromValidatorDataWith1StakingContractUnsta t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -743,7 +749,7 @@ func TestChainSimulatorMakeNewContractFromValidatorDataWith1StakingContractUnsta }) t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -775,7 +781,7 @@ func TestChainSimulatorMakeNewContractFromValidatorDataWith1StakingContractUnsta }) t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -807,7 +813,7 @@ func TestChainSimulatorMakeNewContractFromValidatorDataWith1StakingContractUnsta }) t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -866,6 +872,9 @@ func testChainSimulatorMakeNewContractFromValidatorDataWith1StakingContractUnsta delegator, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + log.Info("working with the following addresses", "owner", owner.Bech32, "", delegator.Bech32) @@ -1032,7 +1041,7 @@ func TestChainSimulator_CreateNewDelegationContract(t *testing.T) { // 6. Check the node is unstaked in the next epoch t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1071,7 +1080,7 @@ func TestChainSimulator_CreateNewDelegationContract(t *testing.T) { // 6. Check the node is unstaked in the next epoch t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1110,7 +1119,7 @@ func TestChainSimulator_CreateNewDelegationContract(t *testing.T) { // 6. Check the node is unstaked in the next epoch t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1149,7 +1158,7 @@ func TestChainSimulator_CreateNewDelegationContract(t *testing.T) { // 6. Check the node is unstaked in the next epoch t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1194,6 +1203,9 @@ func testChainSimulatorCreateNewDelegationContract(t *testing.T, cs chainSimulat delegator2, err := cs.GenerateAndMintWalletAddress(core.AllShardId, initialFunds) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + maxDelegationCap := big.NewInt(0).Mul(chainSimulatorIntegrationTests.OneEGLD, big.NewInt(51000)) // 51000 EGLD cap txCreateDelegationContract := chainSimulatorIntegrationTests.GenerateTransaction(validatorOwner.Bytes, 0, vm.DelegationManagerSCAddress, staking.InitialDelegationValue, fmt.Sprintf("createNewDelegationContract@%s@%s", hex.EncodeToString(maxDelegationCap.Bytes()), hexServiceFee), @@ -1400,7 +1412,7 @@ func TestChainSimulator_MaxDelegationCap(t *testing.T) { // 10. Delegate from user B 20 EGLD, check it fails t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1441,7 +1453,7 @@ func TestChainSimulator_MaxDelegationCap(t *testing.T) { // 10. Delegate from user B 20 EGLD, check it fails t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1482,7 +1494,7 @@ func TestChainSimulator_MaxDelegationCap(t *testing.T) { // 10. Delegate from user B 20 EGLD, check it fails t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1523,7 +1535,7 @@ func TestChainSimulator_MaxDelegationCap(t *testing.T) { // 10. Delegate from user B 20 EGLD, check it fails t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1571,6 +1583,9 @@ func testChainSimulatorMaxDelegationCap(t *testing.T, cs chainSimulatorIntegrati delegatorC, err := cs.GenerateAndMintWalletAddress(core.AllShardId, initialFunds) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + // Step 3: Create a new delegation contract maxDelegationCap := big.NewInt(0).Mul(chainSimulatorIntegrationTests.OneEGLD, big.NewInt(3000)) // 3000 EGLD cap @@ -1810,7 +1825,7 @@ func TestChainSimulator_MergeDelegation(t *testing.T) { t.Run("staking ph 4 is not active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1841,7 +1856,7 @@ func TestChainSimulator_MergeDelegation(t *testing.T) { t.Run("staking ph 4 step 1 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1873,7 +1888,7 @@ func TestChainSimulator_MergeDelegation(t *testing.T) { t.Run("staking ph 4 step 2 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1905,7 +1920,7 @@ func TestChainSimulator_MergeDelegation(t *testing.T) { t.Run("staking ph 4 step 3 is active", func(t *testing.T) { cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -1956,6 +1971,9 @@ func testChainSimulatorMergingDelegation(t *testing.T, cs chainSimulatorIntegrat validatorB, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + log.Info("Step 1. User A: - stake 1 node to have 100 egld more than minimum stake value") stakeValue := big.NewInt(0).Set(chainSimulatorIntegrationTests.MinimumStakeValue) addedStakedValue := big.NewInt(0).Mul(chainSimulatorIntegrationTests.OneEGLD, big.NewInt(100)) diff --git a/integrationTests/chainSimulator/staking/stakingProvider/stakingProviderWithNodesinQueue_test.go b/integrationTests/chainSimulator/staking/stakingProvider/stakingProviderWithNodesinQueue_test.go index f47cf1eec9e..dd89ecf2c28 100644 --- a/integrationTests/chainSimulator/staking/stakingProvider/stakingProviderWithNodesinQueue_test.go +++ b/integrationTests/chainSimulator/staking/stakingProvider/stakingProviderWithNodesinQueue_test.go @@ -52,7 +52,7 @@ func testStakingProviderWithNodesReStakeUnStaked(t *testing.T, stakingV4Activati } cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -75,6 +75,8 @@ func testStakingProviderWithNodesReStakeUnStaked(t *testing.T, stakingV4Activati mintValue := big.NewInt(0).Mul(big.NewInt(5000), chainSimulatorIntegrationTests.OneEGLD) validatorOwner, err := cs.GenerateAndMintWalletAddress(0, mintValue) require.Nil(t, err) + + err = cs.GenerateBlocks(1) require.Nil(t, err) err = cs.GenerateBlocksUntilEpochIsReached(1) diff --git a/integrationTests/chainSimulator/testing.go b/integrationTests/chainSimulator/testing.go index 605bf76ac7f..212021a8fbd 100644 --- a/integrationTests/chainSimulator/testing.go +++ b/integrationTests/chainSimulator/testing.go @@ -196,6 +196,9 @@ func CheckGenerateTransactions(t *testing.T, chainSimulator ChainSimulator) { wallet4, err := chainSimulator.GenerateAndMintWalletAddress(2, InitialAmount) require.Nil(t, err) + err = chainSimulator.GenerateBlocks(1) + require.Nil(t, err) + gasLimit := uint64(50000) tx0 := GenerateTransaction(wallet0.Bytes, 0, wallet2.Bytes, transferValue, "", gasLimit) tx1 := GenerateTransaction(wallet1.Bytes, 0, wallet2.Bytes, transferValue, "", gasLimit) diff --git a/integrationTests/chainSimulator/vm/egldMultiTransfer_test.go b/integrationTests/chainSimulator/vm/egldMultiTransfer_test.go new file mode 100644 index 00000000000..10a10cee5ad --- /dev/null +++ b/integrationTests/chainSimulator/vm/egldMultiTransfer_test.go @@ -0,0 +1,763 @@ +package vm + +import ( + "encoding/hex" + "fmt" + "math/big" + "strings" + "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" + "github.com/multiversx/mx-chain-go/integrationTests/vm/txsFee" + "github.com/multiversx/mx-chain-go/integrationTests/vm/txsFee/utils" + "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/configs" + "github.com/multiversx/mx-chain-go/vm" + "github.com/stretchr/testify/require" +) + +func TestChainSimulator_EGLD_MultiTransfer(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + activationEpoch := uint32(4) + + baseIssuingCost := "1000" + + numOfShards := uint32(3) + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: numOfShards, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.EGLDInMultiTransferEnableEpoch = activationEpoch + cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + require.Nil(t, err) + + // issue metaESDT + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + metaESDTTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], metaESDTTokenID, roles) + nonce++ + + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) + + // issue NFT + nftTicker := []byte("NFTTICKER") + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + sftTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[0], sftTokenID, roles) + nonce++ + + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + esdtMetaData := txsFee.GetDefaultMetaData() + esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + metaESDTTokenID, + } + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + esdtMetaData, + } + + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + fmt.Println(txResult) + fmt.Println(string(txResult.Logs.Events[0].Topics[0])) + fmt.Println(string(txResult.Logs.Events[0].Topics[1])) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + account0, err := cs.GetAccount(addrs[0]) + require.Nil(t, err) + + beforeBalanceStr0 := account0.Balance + + account1, err := cs.GetAccount(addrs[1]) + require.Nil(t, err) + + beforeBalanceStr1 := account1.Balance + + egldValue := oneEGLD.Mul(oneEGLD, big.NewInt(3)) + tx = multiESDTNFTTransferWithEGLDTx(nonce, addrs[0].Bytes, addrs[1].Bytes, tokenIDs, egldValue) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + egldLog := string(txResult.Logs.Events[0].Topics[0]) + require.Equal(t, "EGLD-000000", egldLog) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + // check accounts balance + account0, err = cs.GetAccount(addrs[0]) + require.Nil(t, err) + + beforeBalance0, _ := big.NewInt(0).SetString(beforeBalanceStr0, 10) + + expectedBalance0 := big.NewInt(0).Sub(beforeBalance0, egldValue) + txsFee, _ := big.NewInt(0).SetString(txResult.Fee, 10) + expectedBalanceWithFee0 := big.NewInt(0).Sub(expectedBalance0, txsFee) + + require.Equal(t, expectedBalanceWithFee0.String(), account0.Balance) + + account1, err = cs.GetAccount(addrs[1]) + require.Nil(t, err) + + beforeBalance1, _ := big.NewInt(0).SetString(beforeBalanceStr1, 10) + expectedBalance1 := big.NewInt(0).Add(beforeBalance1, egldValue) + + require.Equal(t, expectedBalance1.String(), account1.Balance) +} + +func TestChainSimulator_EGLD_MultiTransfer_Insufficient_Funds(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + activationEpoch := uint32(4) + + baseIssuingCost := "1000" + + numOfShards := uint32(3) + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: numOfShards, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.EGLDInMultiTransferEnableEpoch = activationEpoch + cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + require.Nil(t, err) + + // issue NFT + nftTicker := []byte("NFTTICKER") + nonce := uint64(0) + tx := issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + account0, err := cs.GetAccount(addrs[0]) + require.Nil(t, err) + + beforeBalanceStr0 := account0.Balance + + account1, err := cs.GetAccount(addrs[1]) + require.Nil(t, err) + + beforeBalanceStr1 := account1.Balance + + egldValue, _ := big.NewInt(0).SetString(beforeBalanceStr0, 10) + egldValue = egldValue.Add(egldValue, big.NewInt(13)) + tx = multiESDTNFTTransferWithEGLDTx(nonce, addrs[0].Bytes, addrs[1].Bytes, [][]byte{nftTokenID}, egldValue) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.NotEqual(t, "success", txResult.Status.String()) + + eventLog := string(txResult.Logs.Events[0].Topics[1]) + require.Equal(t, "insufficient funds for token EGLD-000000", eventLog) + + // check accounts balance + account0, err = cs.GetAccount(addrs[0]) + require.Nil(t, err) + + beforeBalance0, _ := big.NewInt(0).SetString(beforeBalanceStr0, 10) + + txsFee, _ := big.NewInt(0).SetString(txResult.Fee, 10) + expectedBalanceWithFee0 := big.NewInt(0).Sub(beforeBalance0, txsFee) + + require.Equal(t, expectedBalanceWithFee0.String(), account0.Balance) + + account1, err = cs.GetAccount(addrs[1]) + require.Nil(t, err) + + require.Equal(t, beforeBalanceStr1, account1.Balance) +} + +func TestChainSimulator_EGLD_MultiTransfer_Invalid_Value(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + activationEpoch := uint32(4) + + baseIssuingCost := "1000" + + numOfShards := uint32(3) + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: numOfShards, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.EGLDInMultiTransferEnableEpoch = activationEpoch + cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + require.Nil(t, err) + + // issue NFT + nftTicker := []byte("NFTTICKER") + nonce := uint64(0) + tx := issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + account0, err := cs.GetAccount(addrs[0]) + require.Nil(t, err) + + beforeBalanceStr0 := account0.Balance + + account1, err := cs.GetAccount(addrs[1]) + require.Nil(t, err) + + beforeBalanceStr1 := account1.Balance + + egldValue := oneEGLD.Mul(oneEGLD, big.NewInt(3)) + tx = multiESDTNFTTransferWithEGLDTx(nonce, addrs[0].Bytes, addrs[1].Bytes, [][]byte{nftTokenID}, egldValue) + tx.Value = egldValue // invalid value field + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.NotEqual(t, "success", txResult.Status.String()) + + eventLog := string(txResult.Logs.Events[0].Topics[1]) + require.Equal(t, "built in function called with tx value is not allowed", eventLog) + + // check accounts balance + account0, err = cs.GetAccount(addrs[0]) + require.Nil(t, err) + + beforeBalance0, _ := big.NewInt(0).SetString(beforeBalanceStr0, 10) + + txsFee, _ := big.NewInt(0).SetString(txResult.Fee, 10) + expectedBalanceWithFee0 := big.NewInt(0).Sub(beforeBalance0, txsFee) + + require.Equal(t, expectedBalanceWithFee0.String(), account0.Balance) + + account1, err = cs.GetAccount(addrs[1]) + require.Nil(t, err) + + require.Equal(t, beforeBalanceStr1, account1.Balance) +} + +func TestChainSimulator_Multiple_EGLD_Transfers(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + activationEpoch := uint32(4) + + baseIssuingCost := "1000" + + numOfShards := uint32(3) + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: numOfShards, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.EGLDInMultiTransferEnableEpoch = activationEpoch + cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + require.Nil(t, err) + + // issue NFT + nftTicker := []byte("NFTTICKER") + nonce := uint64(0) + tx := issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + account0, err := cs.GetAccount(addrs[0]) + require.Nil(t, err) + + beforeBalanceStr0 := account0.Balance + + account1, err := cs.GetAccount(addrs[1]) + require.Nil(t, err) + + beforeBalanceStr1 := account1.Balance + + // multi nft transfer with multiple EGLD-000000 tokens + numTransfers := 3 + encodedReceiver := hex.EncodeToString(addrs[1].Bytes) + egldValue := oneEGLD.Mul(oneEGLD, big.NewInt(3)) + + txDataField := []byte(strings.Join( + []string{ + core.BuiltInFunctionMultiESDTNFTTransfer, + encodedReceiver, + hex.EncodeToString(big.NewInt(int64(numTransfers)).Bytes()), + hex.EncodeToString([]byte("EGLD-000000")), + "00", + hex.EncodeToString(egldValue.Bytes()), + hex.EncodeToString(nftTokenID), + hex.EncodeToString(big.NewInt(1).Bytes()), + hex.EncodeToString(big.NewInt(int64(1)).Bytes()), + hex.EncodeToString([]byte("EGLD-000000")), + "00", + hex.EncodeToString(egldValue.Bytes()), + }, "@"), + ) + + tx = &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: addrs[0].Bytes, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Data: txDataField, + Value: big.NewInt(0), + Version: 1, + Signature: []byte("dummySig"), + ChainID: []byte(configs.ChainID), + } + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + // check accounts balance + account0, err = cs.GetAccount(addrs[0]) + require.Nil(t, err) + + beforeBalance0, _ := big.NewInt(0).SetString(beforeBalanceStr0, 10) + + expectedBalance0 := big.NewInt(0).Sub(beforeBalance0, egldValue) + expectedBalance0 = big.NewInt(0).Sub(expectedBalance0, egldValue) + txsFee, _ := big.NewInt(0).SetString(txResult.Fee, 10) + expectedBalanceWithFee0 := big.NewInt(0).Sub(expectedBalance0, txsFee) + + require.Equal(t, expectedBalanceWithFee0.String(), account0.Balance) + + account1, err = cs.GetAccount(addrs[1]) + require.Nil(t, err) + + beforeBalance1, _ := big.NewInt(0).SetString(beforeBalanceStr1, 10) + expectedBalance1 := big.NewInt(0).Add(beforeBalance1, egldValue) + expectedBalance1 = big.NewInt(0).Add(expectedBalance1, egldValue) + + require.Equal(t, expectedBalance1.String(), account1.Balance) +} + +func multiESDTNFTTransferWithEGLDTx(nonce uint64, sndAdr, rcvAddr []byte, tokens [][]byte, egldValue *big.Int) *transaction.Transaction { + transferData := make([]*utils.TransferESDTData, 0) + + for _, tokenID := range tokens { + transferData = append(transferData, &utils.TransferESDTData{ + Token: tokenID, + Nonce: 1, + Value: big.NewInt(1), + }) + } + + numTransfers := len(tokens) + encodedReceiver := hex.EncodeToString(rcvAddr) + hexEncodedNumTransfers := hex.EncodeToString(big.NewInt(int64(numTransfers)).Bytes()) + hexEncodedEGLD := hex.EncodeToString([]byte("EGLD-000000")) + hexEncodedEGLDNonce := "00" + + txDataField := []byte(strings.Join( + []string{ + core.BuiltInFunctionMultiESDTNFTTransfer, + encodedReceiver, + hexEncodedNumTransfers, + hexEncodedEGLD, + hexEncodedEGLDNonce, + hex.EncodeToString(egldValue.Bytes()), + }, "@"), + ) + + for _, td := range transferData { + hexEncodedToken := hex.EncodeToString(td.Token) + esdtValueEncoded := hex.EncodeToString(td.Value.Bytes()) + hexEncodedNonce := "00" + if td.Nonce != 0 { + hexEncodedNonce = hex.EncodeToString(big.NewInt(int64(td.Nonce)).Bytes()) + } + + txDataField = []byte(strings.Join([]string{string(txDataField), hexEncodedToken, hexEncodedNonce, esdtValueEncoded}, "@")) + } + + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: sndAdr, + RcvAddr: sndAdr, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Data: txDataField, + Value: big.NewInt(0), + Version: 1, + Signature: []byte("dummySig"), + ChainID: []byte(configs.ChainID), + } + + return tx +} + +func TestChainSimulator_IssueToken_EGLDTicker(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + activationEpoch := uint32(4) + + baseIssuingCost := "1000" + + numOfShards := uint32(3) + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: numOfShards, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.EGLDInMultiTransferEnableEpoch = activationEpoch + cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch) - 1) + require.Nil(t, err) + + log.Info("Initial setup: Issue token (before the activation of EGLDInMultiTransferFlag)") + + // issue NFT + nftTicker := []byte("EGLD") + nonce := uint64(0) + tx := issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + require.Nil(t, err) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + log.Info("Issue token (after activation of EGLDInMultiTransferFlag)") + + // should fail issuing token with EGLD ticker + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + errMessage := string(txResult.Logs.Events[0].Topics[1]) + require.Equal(t, vm.ErrCouldNotCreateNewTokenIdentifier.Error(), errMessage) + + require.Equal(t, "success", txResult.Status.String()) +} diff --git a/integrationTests/chainSimulator/vm/esdtImprovements_test.go b/integrationTests/chainSimulator/vm/esdtImprovements_test.go index 608c24ee3b0..438660658f3 100644 --- a/integrationTests/chainSimulator/vm/esdtImprovements_test.go +++ b/integrationTests/chainSimulator/vm/esdtImprovements_test.go @@ -3,7 +3,9 @@ package vm import ( "bytes" "encoding/hex" + "fmt" "math/big" + "strings" "testing" "time" @@ -18,6 +20,7 @@ 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" + "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/state" "github.com/multiversx/mx-chain-go/vm" logger "github.com/multiversx/mx-chain-logger-go" @@ -86,7 +89,7 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -113,11 +116,13 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch) - 1) require.Nil(t, err) - log.Info("Initial setup: Create fungible, NFT, SFT and metaESDT tokens (before the activation of DynamicEsdtFlag)") + log.Info("Initial setup: Create NFT, SFT and metaESDT tokens (before the activation of DynamicEsdtFlag)") // issue metaESDT - metaESDTTicker := []byte("METATTICKER") - tx := issueMetaESDTTx(0, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) @@ -130,27 +135,24 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran []byte(core.ESDTRoleNFTCreate), []byte(core.ESDTRoleTransfer), } - setAddressEsdtRoles(t, cs, addrs[0], metaESDTTokenID, roles) + setAddressEsdtRoles(t, cs, nonce, addrs[0], metaESDTTokenID, roles) + nonce++ - log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) - - // issue fungible - fungibleTicker := []byte("FUNTICKER") - tx = issueTx(1, addrs[0].Bytes, fungibleTicker, baseIssuingCost) + rolesTransfer := [][]byte{[]byte(core.ESDTRoleTransfer)} + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[1].Bytes, metaESDTTokenID, rolesTransfer) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) - fungibleTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, addrs[0], fungibleTokenID, roles) - - log.Info("Issued fungible token id", "tokenID", string(fungibleTokenID)) + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) // issue NFT nftTicker := []byte("NFTTICKER") - tx = issueNonFungibleTx(2, addrs[0].Bytes, nftTicker, baseIssuingCost) + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) @@ -158,13 +160,23 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran require.Equal(t, "success", txResult.Status.String()) nftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, addrs[0], nftTokenID, roles) + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[1].Bytes, nftTokenID, rolesTransfer) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) // issue SFT sftTicker := []byte("SFTTICKER") - tx = issueSemiFungibleTx(3, addrs[0].Bytes, sftTicker, baseIssuingCost) + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) @@ -172,7 +184,16 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran require.Equal(t, "success", txResult.Status.String()) sftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, addrs[0], sftTokenID, roles) + setAddressEsdtRoles(t, cs, nonce, addrs[0], sftTokenID, roles) + nonce++ + + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[1].Bytes, sftTokenID, rolesTransfer) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) @@ -185,24 +206,18 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran esdtMetaData := txsFee.GetDefaultMetaData() esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - fungibleMetaData := txsFee.GetDefaultMetaData() - fungibleMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - tokenIDs := [][]byte{ nftTokenID, sftTokenID, metaESDTTokenID, - fungibleTokenID, } tokensMetadata := []*txsFee.MetaData{ nftMetaData, sftMetaData, esdtMetaData, - fungibleMetaData, } - nonce := uint64(4) for i := range tokenIDs { tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) @@ -225,7 +240,6 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, sftMetaData) checkMetaData(t, cs, core.SystemAccountAddress, metaESDTTokenID, shardID, esdtMetaData) - checkMetaData(t, cs, core.SystemAccountAddress, fungibleTokenID, shardID, fungibleMetaData) log.Info("Step 2. wait for DynamicEsdtFlag activation") @@ -268,7 +282,6 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, sftMetaData) checkMetaData(t, cs, core.SystemAccountAddress, metaESDTTokenID, shardID, esdtMetaData) - checkMetaData(t, cs, core.SystemAccountAddress, fungibleTokenID, shardID, fungibleMetaData) log.Info("Step 5. make an updateTokenID@tokenID function call on the ESDTSystem SC for all token types") @@ -293,21 +306,30 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, sftMetaData) checkMetaData(t, cs, core.SystemAccountAddress, metaESDTTokenID, shardID, esdtMetaData) - checkMetaData(t, cs, core.SystemAccountAddress, fungibleTokenID, shardID, fungibleMetaData) log.Info("Step 7. transfer the tokens to another account") nonce = uint64(0) - for _, tokenID := range tokenIDs { - log.Info("transfering token id", "tokenID", tokenID) + if isMultiTransfer { + tx = multiESDTNFTTransferTx(nonce, addrs[1].Bytes, addrs[2].Bytes, tokenIDs) - tx = esdtNFTTransferTx(nonce, addrs[1].Bytes, addrs[2].Bytes, tokenID) txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + } else { + for _, tokenID := range tokenIDs { + log.Info("transfering token id", "tokenID", tokenID) - nonce++ + tx = esdtNFTTransferTx(nonce, addrs[1].Bytes, addrs[2].Bytes, tokenID) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } } log.Info("Step 8. check that the metaData for the NFT was removed from the system account and moved to the user account") @@ -327,9 +349,6 @@ func transferAndCheckTokensMetaData(t *testing.T, isCrossShard bool, isMultiTran checkMetaData(t, cs, core.SystemAccountAddress, metaESDTTokenID, shardID, esdtMetaData) checkMetaDataNotInAcc(t, cs, addrs[2].Bytes, metaESDTTokenID, shardID) - - checkMetaData(t, cs, core.SystemAccountAddress, fungibleTokenID, shardID, fungibleMetaData) - checkMetaDataNotInAcc(t, cs, addrs[2].Bytes, fungibleTokenID, shardID) } func createAddresses( @@ -356,6 +375,9 @@ func createAddresses( address3, err := cs.GenerateAndMintWalletAddress(shardIDs[2], mintValue) require.Nil(t, err) + err = cs.GenerateBlocks(1) + require.Nil(t, err) + return []dtos.WalletAddress{address, address2, address3} } @@ -613,6 +635,34 @@ func nftCreateTx( } } +func modifyCreatorTx( + nonce uint64, + sndAdr []byte, + tokenID []byte, +) *transaction.Transaction { + txDataField := bytes.Join( + [][]byte{ + []byte(core.ESDTModifyCreator), + []byte(hex.EncodeToString(tokenID)), + []byte(hex.EncodeToString(big.NewInt(1).Bytes())), + }, + []byte("@"), + ) + + return &transaction.Transaction{ + Nonce: nonce, + SndAddr: sndAdr, + RcvAddr: sndAdr, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: big.NewInt(0), + ChainID: []byte(configs.ChainID), + Version: 1, + } +} + func getESDTDataFromAcc( t *testing.T, cs testsChainSimulator.ChainSimulator, @@ -653,41 +703,62 @@ func getMetaDataFromAcc( return esdtData.TokenMetaData } +func setSpecialRoleTx( + nonce uint64, + sndAddr []byte, + address []byte, + token []byte, + roles [][]byte, +) *transaction.Transaction { + txDataBytes := [][]byte{ + []byte("setSpecialRole"), + []byte(hex.EncodeToString(token)), + []byte(hex.EncodeToString(address)), + } + + for _, role := range roles { + txDataBytes = append(txDataBytes, []byte(hex.EncodeToString(role))) + } + + txDataField := bytes.Join( + txDataBytes, + []byte("@"), + ) + + return &transaction.Transaction{ + Nonce: nonce, + SndAddr: sndAddr, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 60_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: big.NewInt(0), + ChainID: []byte(configs.ChainID), + Version: 1, + } +} + func setAddressEsdtRoles( t *testing.T, cs testsChainSimulator.ChainSimulator, + nonce uint64, address dtos.WalletAddress, token []byte, roles [][]byte, ) { - marshaller := cs.GetNodeHandler(0).GetCoreComponents().InternalMarshalizer() - - rolesKey := append([]byte(core.ProtectedKeyPrefix), append([]byte(core.ESDTRoleIdentifier), []byte(core.ESDTKeyIdentifier)...)...) - rolesKey = append(rolesKey, token...) + tx := setSpecialRoleTx(nonce, address.Bytes, address.Bytes, token, roles) - rolesData := &esdt.ESDTRoles{ - Roles: roles, - } - - rolesDataBytes, err := marshaller.Marshal(rolesData) + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) + require.NotNil(t, txResult) - keys := make(map[string]string) - keys[hex.EncodeToString(rolesKey)] = hex.EncodeToString(rolesDataBytes) - - err = cs.SetStateMultiple([]*dtos.AddressState{ - { - Address: address.Bech32, - Balance: "10000000000000000000000", - Pairs: keys, - }, - }) - require.Nil(t, err) + require.Equal(t, "success", txResult.Status.String()) } // Test scenario #3 // -// Initial setup: Create fungible, NFT, SFT and metaESDT tokens +// Initial setup: Create NFT, SFT and metaESDT tokens // (after the activation of DynamicEsdtFlag) // // 1. check that the metaData for the NFT was saved in the user account and not on the system account @@ -697,54 +768,20 @@ func TestChainSimulator_CreateTokensAfterActivation(t *testing.T) { t.Skip("this is not a short test") } - startTime := time.Now().Unix() - roundDurationInMillis := uint64(6000) - roundsPerEpoch := core.OptionalUint64{ - HasValue: true, - Value: 20, - } - - activationEpoch := uint32(2) - baseIssuingCost := "1000" - numOfShards := uint32(3) - cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, - TempDir: t.TempDir(), - PathToInitialConfig: defaultPathToInitialConfig, - NumOfShards: numOfShards, - GenesisTimestamp: startTime, - RoundDurationInMillis: roundDurationInMillis, - RoundsPerEpoch: roundsPerEpoch, - ApiInterface: api.NewNoApiInterface(), - MinNodesPerShard: 3, - MetaChainMinNodes: 3, - NumNodesWaitingListMeta: 0, - NumNodesWaitingListShard: 0, - AlterConfigsFunction: func(cfg *config.Configs) { - cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch - cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost - }, - }) - require.Nil(t, err) - require.NotNil(t, cs) - + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) defer cs.Close() addrs := createAddresses(t, cs, false) - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) - require.Nil(t, err) - - err = cs.GenerateBlocks(10) - require.Nil(t, err) - - log.Info("Initial setup: Create fungible, NFT, SFT and metaESDT tokens (after the activation of DynamicEsdtFlag)") + log.Info("Initial setup: Create NFT, SFT and metaESDT tokens (after the activation of DynamicEsdtFlag)") // issue metaESDT - metaESDTTicker := []byte("METATTICKER") - tx := issueMetaESDTTx(0, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) @@ -757,27 +794,15 @@ func TestChainSimulator_CreateTokensAfterActivation(t *testing.T) { []byte(core.ESDTRoleNFTCreate), []byte(core.ESDTRoleTransfer), } - setAddressEsdtRoles(t, cs, addrs[0], metaESDTTokenID, roles) + setAddressEsdtRoles(t, cs, nonce, addrs[0], metaESDTTokenID, roles) + nonce++ log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) - // issue fungible - fungibleTicker := []byte("FUNTICKER") - tx = issueTx(1, addrs[0].Bytes, fungibleTicker, baseIssuingCost) - - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) - require.Nil(t, err) - require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) - - fungibleTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, addrs[0], fungibleTokenID, roles) - - log.Info("Issued fungible token id", "tokenID", string(fungibleTokenID)) - // issue NFT nftTicker := []byte("NFTTICKER") - tx = issueNonFungibleTx(2, addrs[0].Bytes, nftTicker, baseIssuingCost) + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) @@ -785,13 +810,15 @@ func TestChainSimulator_CreateTokensAfterActivation(t *testing.T) { require.Equal(t, "success", txResult.Status.String()) nftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, addrs[0], nftTokenID, roles) + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) // issue SFT sftTicker := []byte("SFTTICKER") - tx = issueSemiFungibleTx(3, addrs[0].Bytes, sftTicker, baseIssuingCost) + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) @@ -799,7 +826,8 @@ func TestChainSimulator_CreateTokensAfterActivation(t *testing.T) { require.Equal(t, "success", txResult.Status.String()) sftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, addrs[0], sftTokenID, roles) + setAddressEsdtRoles(t, cs, nonce, addrs[0], sftTokenID, roles) + nonce++ log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) @@ -807,7 +835,6 @@ func TestChainSimulator_CreateTokensAfterActivation(t *testing.T) { nftTokenID, sftTokenID, metaESDTTokenID, - fungibleTokenID, } nftMetaData := txsFee.GetDefaultMetaData() @@ -819,17 +846,12 @@ func TestChainSimulator_CreateTokensAfterActivation(t *testing.T) { esdtMetaData := txsFee.GetDefaultMetaData() esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - fungibleMetaData := txsFee.GetDefaultMetaData() - fungibleMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - tokensMetadata := []*txsFee.MetaData{ nftMetaData, sftMetaData, esdtMetaData, - fungibleMetaData, } - nonce := uint64(4) for i := range tokenIDs { tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) @@ -858,367 +880,2128 @@ func TestChainSimulator_CreateTokensAfterActivation(t *testing.T) { checkMetaData(t, cs, core.SystemAccountAddress, metaESDTTokenID, shardID, esdtMetaData) checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, metaESDTTokenID, shardID) - - checkMetaData(t, cs, core.SystemAccountAddress, fungibleTokenID, shardID, fungibleMetaData) - checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, fungibleTokenID, shardID) } // Test scenario #4 // -// Initial setup: Create NFT +// Initial setup: Create NFT, SFT, metaESDT tokens // // Call ESDTMetaDataRecreate to rewrite the meta data for the nft // (The sender must have the ESDTMetaDataRecreate role) -func TestChainSimulator_NFT_ESDTMetaDataRecreate(t *testing.T) { +func TestChainSimulator_ESDTMetaDataRecreate(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") } - startTime := time.Now().Unix() - roundDurationInMillis := uint64(6000) - roundsPerEpoch := core.OptionalUint64{ - HasValue: true, - Value: 20, - } - - activationEpoch := uint32(2) - baseIssuingCost := "1000" - numOfShards := uint32(3) - cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, - TempDir: t.TempDir(), - PathToInitialConfig: defaultPathToInitialConfig, - NumOfShards: numOfShards, - GenesisTimestamp: startTime, - RoundDurationInMillis: roundDurationInMillis, - RoundsPerEpoch: roundsPerEpoch, - ApiInterface: api.NewNoApiInterface(), - MinNodesPerShard: 3, - MetaChainMinNodes: 3, - NumNodesWaitingListMeta: 0, - NumNodesWaitingListShard: 0, - AlterConfigsFunction: func(cfg *config.Configs) { - cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch - cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost - }, - }) - require.Nil(t, err) - require.NotNil(t, cs) - + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) defer cs.Close() - mintValue := big.NewInt(10) - mintValue = mintValue.Mul(oneEGLD, mintValue) - - address, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) - require.Nil(t, err) - - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) - require.Nil(t, err) + log.Info("Initial setup: Create NFT, SFT and metaESDT tokens (after the activation of DynamicEsdtFlag)") - err = cs.GenerateBlocks(10) - require.Nil(t, err) - - log.Info("Initial setup: Create NFT") + addrs := createAddresses(t, cs, false) - nftTicker := []byte("NFTTICKER") - tx := issueNonFungibleTx(0, address.Bytes, nftTicker, baseIssuingCost) + // issue metaESDT + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) + metaESDTTokenID := txResult.Logs.Events[0].Topics[0] + roles := [][]byte{ []byte(core.ESDTRoleNFTCreate), - []byte(core.ESDTMetaDataRecreate), } + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, metaESDTTokenID, roles) + nonce++ - nftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, address, nftTokenID, roles) - - log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) - nftMetaData := txsFee.GetDefaultMetaData() - nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) - tx = nftCreateTx(1, address.Bytes, nftTokenID, nftMetaData) + // issue NFT + nftTicker := []byte("NFTTICKER") + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) - err = cs.GenerateBlocks(10) - require.Nil(t, err) - - log.Info("Call ESDTMetaDataRecreate to rewrite the meta data for the nft") + nftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, nftTokenID, roles) + nonce++ - nonce := []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - nftMetaData.Name = []byte(hex.EncodeToString([]byte("name2"))) - nftMetaData.Hash = []byte(hex.EncodeToString([]byte("hash2"))) - nftMetaData.Attributes = []byte(hex.EncodeToString([]byte("attributes2"))) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) - txDataField := bytes.Join( - [][]byte{ - []byte(core.ESDTMetaDataRecreate), - []byte(hex.EncodeToString(nftTokenID)), - nonce, - nftMetaData.Name, - []byte(hex.EncodeToString(big.NewInt(10).Bytes())), - nftMetaData.Hash, - nftMetaData.Attributes, - nftMetaData.Uris[0], - nftMetaData.Uris[1], - nftMetaData.Uris[2], - }, - []byte("@"), - ) + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) - tx = &transaction.Transaction{ - Nonce: 2, - SndAddr: address.Bytes, - RcvAddr: address.Bytes, - GasLimit: 10_000_000, - GasPrice: minGasPrice, - Signature: []byte("dummySig"), - Data: txDataField, - Value: big.NewInt(0), - ChainID: []byte(configs.ChainID), - Version: 1, - } + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) - shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(address.Bytes) + sftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, sftTokenID, roles) + nonce++ - checkMetaData(t, cs, address.Bytes, nftTokenID, shardID, nftMetaData) -} + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) -// Test scenario #5 -// -// Initial setup: Create NFT -// -// Call ESDTMetaDataUpdate to update some of the meta data parameters -// (The sender must have the ESDTRoleNFTUpdate role) -func TestChainSimulator_NFT_ESDTMetaDataUpdate(t *testing.T) { - if testing.Short() { - t.Skip("this is not a short test") - } + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) - startTime := time.Now().Unix() - roundDurationInMillis := uint64(6000) - roundsPerEpoch := core.OptionalUint64{ - HasValue: true, - Value: 20, + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + metaESDTTokenID, } - activationEpoch := uint32(2) + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + esdtMetaData := txsFee.GetDefaultMetaData() + esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + esdtMetaData, + } + + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + + tx = changeToDynamicTx(nonce, addrs[0].Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + + roles := [][]byte{ + []byte(core.ESDTRoleNFTRecreate), + } + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, tokenIDs[i], roles) + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + log.Info("Call ESDTMetaDataRecreate to rewrite the meta data for the nft") + + for i := range tokenIDs { + newMetaData := txsFee.GetDefaultMetaData() + newMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + newMetaData.Name = []byte(hex.EncodeToString([]byte("name2"))) + newMetaData.Hash = []byte(hex.EncodeToString([]byte("hash2"))) + newMetaData.Attributes = []byte(hex.EncodeToString([]byte("attributes2"))) + + txDataField := bytes.Join( + [][]byte{ + []byte(core.ESDTMetaDataRecreate), + []byte(hex.EncodeToString(tokenIDs[i])), + newMetaData.Nonce, + newMetaData.Name, + []byte(hex.EncodeToString(big.NewInt(10).Bytes())), + newMetaData.Hash, + newMetaData.Attributes, + newMetaData.Uris[0], + newMetaData.Uris[1], + newMetaData.Uris[2], + }, + []byte("@"), + ) + + tx = &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: addrs[0].Bytes, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: big.NewInt(0), + ChainID: []byte(configs.ChainID), + Version: 1, + } + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + if bytes.Equal(tokenIDs[i], tokenIDs[0]) { // nft token + checkMetaData(t, cs, addrs[0].Bytes, tokenIDs[i], shardID, newMetaData) + } else { + checkMetaData(t, cs, core.SystemAccountAddress, tokenIDs[i], shardID, newMetaData) + } + + nonce++ + } +} + +// Test scenario #5 +// +// Initial setup: Create NFT, SFT, metaESDT tokens +// +// Call ESDTMetaDataUpdate to update some of the meta data parameters +// (The sender must have the ESDTRoleNFTUpdate role) +func TestChainSimulator_ESDTMetaDataUpdate(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + log.Info("Initial setup: Create NFT, SFT and metaESDT tokens (after the activation of DynamicEsdtFlag)") + + addrs := createAddresses(t, cs, false) + + // issue metaESDT + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + metaESDTTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, metaESDTTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) + + // issue NFT + nftTicker := []byte("NFTTICKER") + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, nftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + sftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, sftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + metaESDTTokenID, + } + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + esdtMetaData := txsFee.GetDefaultMetaData() + esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + esdtMetaData, + } + + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + + tx = changeToDynamicTx(nonce, addrs[0].Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + + roles := [][]byte{ + []byte(core.ESDTRoleNFTUpdate), + } + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, tokenIDs[i], roles) + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + log.Info("Call ESDTMetaDataUpdate to rewrite the meta data for the nft") + + for i := range tokenIDs { + newMetaData := txsFee.GetDefaultMetaData() + newMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + newMetaData.Name = []byte(hex.EncodeToString([]byte("name2"))) + newMetaData.Hash = []byte(hex.EncodeToString([]byte("hash2"))) + newMetaData.Attributes = []byte(hex.EncodeToString([]byte("attributes2"))) + + txDataField := bytes.Join( + [][]byte{ + []byte(core.ESDTMetaDataUpdate), + []byte(hex.EncodeToString(tokenIDs[i])), + newMetaData.Nonce, + newMetaData.Name, + []byte(hex.EncodeToString(big.NewInt(10).Bytes())), + newMetaData.Hash, + newMetaData.Attributes, + newMetaData.Uris[0], + newMetaData.Uris[1], + newMetaData.Uris[2], + }, + []byte("@"), + ) + + tx = &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: addrs[0].Bytes, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: big.NewInt(0), + ChainID: []byte(configs.ChainID), + Version: 1, + } + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + if bytes.Equal(tokenIDs[i], tokenIDs[0]) { // nft token + checkMetaData(t, cs, addrs[0].Bytes, tokenIDs[i], shardID, newMetaData) + } else { + checkMetaData(t, cs, core.SystemAccountAddress, tokenIDs[i], shardID, newMetaData) + } + + nonce++ + } +} + +// Test scenario #6 +// +// Initial setup: Create NFT, SFT, metaESDT tokens +// +// Call ESDTModifyCreator and check that the creator was modified +// (The sender must have the ESDTRoleModifyCreator role) +func TestChainSimulator_ESDTModifyCreator(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + log.Info("Initial setup: Create NFT, SFT and metaESDT tokens (after the activation of DynamicEsdtFlag). Register NFT directly as dynamic") + + addrs := createAddresses(t, cs, false) + + // issue metaESDT + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[1].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + metaESDTTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, addrs[1].Bytes, metaESDTTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) + + // register dynamic NFT + nftTicker := []byte("NFTTICKER") + nftTokenName := []byte("tokenName") + + txDataField := bytes.Join( + [][]byte{ + []byte("registerDynamic"), + []byte(hex.EncodeToString(nftTokenName)), + []byte(hex.EncodeToString(nftTicker)), + []byte(hex.EncodeToString([]byte("NFT"))), + }, + []byte("@"), + ) + + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + tx = &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[1].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, addrs[1].Bytes, nftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[1].Bytes, sftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + sftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, addrs[1].Bytes, sftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + metaESDTTokenID, + } + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + esdtMetaData := txsFee.GetDefaultMetaData() + esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + esdtMetaData, + } + + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[1].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + log.Info("Change to DYNAMIC type") + + for i := range tokenIDs { + tx = changeToDynamicTx(nonce, addrs[1].Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + log.Info("Call ESDTModifyCreator and check that the creator was modified") + + mintValue := big.NewInt(10) + mintValue = mintValue.Mul(oneEGLD, mintValue) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[1].Bytes) + + for i := range tokenIDs { + log.Info("Modify creator for token", "tokenID", tokenIDs[i]) + + newCreatorAddress, err := cs.GenerateAndMintWalletAddress(shardID, mintValue) + require.Nil(t, err) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + roles = [][]byte{ + []byte(core.ESDTRoleModifyCreator), + } + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, newCreatorAddress.Bytes, tokenIDs[i], roles) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + tx = modifyCreatorTx(0, newCreatorAddress.Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + retrievedMetaData := getMetaDataFromAcc(t, cs, core.SystemAccountAddress, tokenIDs[i], shardID) + + require.Equal(t, newCreatorAddress.Bytes, retrievedMetaData.Creator) + } +} + +func TestChainSimulator_ESDTModifyCreator_CrossShard(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + // issue metaESDT + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[1].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + metaESDTTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, addrs[1].Bytes, metaESDTTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) + + // register dynamic NFT + nftTicker := []byte("NFTTICKER") + nftTokenName := []byte("tokenName") + + txDataField := bytes.Join( + [][]byte{ + []byte("registerDynamic"), + []byte(hex.EncodeToString(nftTokenName)), + []byte(hex.EncodeToString(nftTicker)), + []byte(hex.EncodeToString([]byte("NFT"))), + }, + []byte("@"), + ) + + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + tx = &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[1].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, addrs[1].Bytes, nftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[1].Bytes, sftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + sftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, addrs[1].Bytes, sftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + metaESDTTokenID, + } + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + esdtMetaData := txsFee.GetDefaultMetaData() + esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + esdtMetaData, + } + + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[1].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + log.Info("Change to DYNAMIC type") + + for i := range tokenIDs { + tx = changeToDynamicTx(nonce, addrs[1].Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + log.Info("Call ESDTModifyCreator and check that the creator was modified") + + mintValue := big.NewInt(10) + mintValue = mintValue.Mul(oneEGLD, mintValue) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[1].Bytes) + + crossShardID := uint32(2) + if shardID == uint32(2) { + crossShardID = uint32(1) + } + + for i := range tokenIDs { + log.Info("Modify creator for token", "tokenID", string(tokenIDs[i])) + + newCreatorAddress, err := cs.GenerateAndMintWalletAddress(crossShardID, mintValue) + require.Nil(t, err) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + roles = [][]byte{ + []byte(core.ESDTRoleModifyCreator), + } + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, newCreatorAddress.Bytes, tokenIDs[i], roles) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("transfering token id", "tokenID", tokenIDs[i]) + + tx = esdtNFTTransferTx(nonce, addrs[1].Bytes, newCreatorAddress.Bytes, tokenIDs[i]) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + tx = modifyCreatorTx(0, newCreatorAddress.Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(newCreatorAddress.Bytes) + retrievedMetaData := getMetaDataFromAcc(t, cs, core.SystemAccountAddress, tokenIDs[i], shardID) + + require.Equal(t, newCreatorAddress.Bytes, retrievedMetaData.Creator) + + nonce++ + } +} + +// Test scenario #7 +// +// Initial setup: Create NFT, SFT, metaESDT tokens +// +// Call ESDTSetNewURIs and check that the new URIs were set for the token +// (The sender must have the ESDTRoleSetNewURI role) +func TestChainSimulator_ESDTSetNewURIs(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + // issue metaESDT + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + metaESDTTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, metaESDTTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) + + // issue NFT + nftTicker := []byte("NFTTICKER") + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, nftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + sftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, sftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + metaESDTTokenID, + } + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + esdtMetaData := txsFee.GetDefaultMetaData() + esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + esdtMetaData, + } + + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + + tx = changeToDynamicTx(nonce, addrs[0].Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + + roles := [][]byte{ + []byte(core.ESDTRoleSetNewURI), + } + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, tokenIDs[i], roles) + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + log.Info("Call ESDTSetNewURIs and check that the new URIs were set for the tokens") + + metaDataNonce := []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + uris := [][]byte{ + []byte(hex.EncodeToString([]byte("uri0"))), + []byte(hex.EncodeToString([]byte("uri1"))), + []byte(hex.EncodeToString([]byte("uri2"))), + } + + expUris := [][]byte{ + []byte("uri0"), + []byte("uri1"), + []byte("uri2"), + } + + for i := range tokenIDs { + log.Info("Set new uris for token", "tokenID", string(tokenIDs[i])) + + txDataField := bytes.Join( + [][]byte{ + []byte(core.ESDTSetNewURIs), + []byte(hex.EncodeToString(tokenIDs[i])), + metaDataNonce, + uris[0], + uris[1], + uris[2], + }, + []byte("@"), + ) + + tx = &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: addrs[0].Bytes, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: big.NewInt(0), + ChainID: []byte(configs.ChainID), + Version: 1, + } + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + var retrievedMetaData *esdt.MetaData + if bytes.Equal(tokenIDs[i], tokenIDs[0]) { // nft token + retrievedMetaData = getMetaDataFromAcc(t, cs, addrs[0].Bytes, tokenIDs[i], shardID) + } else { + retrievedMetaData = getMetaDataFromAcc(t, cs, core.SystemAccountAddress, tokenIDs[i], shardID) + } + + require.Equal(t, expUris, retrievedMetaData.URIs) + + nonce++ + } +} + +// Test scenario #8 +// +// Initial setup: Create NFT, SFT, metaESDT tokens +// +// Call ESDTModifyRoyalties and check that the royalties were changed +// (The sender must have the ESDTRoleModifyRoyalties role) +func TestChainSimulator_ESDTModifyRoyalties(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + // issue metaESDT + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + metaESDTTokenID := txResult.Logs.Events[0].Topics[0] + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, metaESDTTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) + + // issue NFT + nftTicker := []byte("NFTTICKER") + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, nftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + sftTokenID := txResult.Logs.Events[0].Topics[0] + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, sftTokenID, roles) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + metaESDTTokenID, + } + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + esdtMetaData := txsFee.GetDefaultMetaData() + esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + esdtMetaData, + } + + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + + tx = changeToDynamicTx(nonce, addrs[0].Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + + roles := [][]byte{ + []byte(core.ESDTRoleModifyRoyalties), + } + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[0].Bytes, tokenIDs[i], roles) + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + log.Info("Call ESDTModifyRoyalties and check that the royalties were changed") + + metaDataNonce := []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + royalties := []byte(hex.EncodeToString(big.NewInt(20).Bytes())) + + for i := range tokenIDs { + log.Info("Set new royalties for token", "tokenID", string(tokenIDs[i])) + + txDataField := bytes.Join( + [][]byte{ + []byte(core.ESDTModifyRoyalties), + []byte(hex.EncodeToString(tokenIDs[i])), + metaDataNonce, + royalties, + }, + []byte("@"), + ) + + tx = &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: addrs[0].Bytes, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: big.NewInt(0), + ChainID: []byte(configs.ChainID), + Version: 1, + } + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + shardID := cs.GetNodeHandler(0).GetShardCoordinator().ComputeId(addrs[0].Bytes) + retrievedMetaData := getMetaDataFromAcc(t, cs, addrs[0].Bytes, nftTokenID, shardID) + + require.Equal(t, uint32(big.NewInt(20).Uint64()), retrievedMetaData.Royalties) + + nonce++ + } +} + +// Test scenario #9 +// +// Initial setup: Create NFT +// +// 1. Change the nft to DYNAMIC type - the metadata should be on the system account +// 2. Send the NFT cross shard +// 3. The meta data should still be present on the system account +func TestChainSimulator_NFT_ChangeToDynamicType(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + activationEpoch := uint32(4) + + baseIssuingCost := "1000" + + numOfShards := uint32(3) + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: numOfShards, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch + cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + addrs := createAddresses(t, cs, true) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch) - 2) + require.Nil(t, err) + + log.Info("Initial setup: Create NFT") + + nftTicker := []byte("NFTTICKER") + nonce := uint64(0) + tx := issueNonFungibleTx(nonce, addrs[1].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + } + + nftTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[1], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[1].Bytes, nftTokenID, nftMetaData) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + require.Nil(t, err) + + log.Info("Step 1. Change the nft to DYNAMIC type - the metadata should be on the system account") + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[1].Bytes) + + tx = changeToDynamicTx(nonce, addrs[1].Bytes, nftTokenID) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + roles = [][]byte{ + []byte(core.ESDTRoleNFTUpdate), + } + + setAddressEsdtRoles(t, cs, nonce, addrs[1], nftTokenID, roles) + nonce++ + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) + + log.Info("Step 2. Send the NFT cross shard") + + tx = esdtNFTTransferTx(nonce, addrs[1].Bytes, addrs[2].Bytes, nftTokenID) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Step 3. The meta data should still be present on the system account") + + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) +} + +// Test scenario #10 +// +// Initial setup: Create SFT and send in another shard +// +// 1. change the sft meta data (differently from the previous one) in the other shard +// 2. check that the newest metadata is saved +func TestChainSimulator_ChangeMetaData(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + t.Run("sft change metadata", func(t *testing.T) { + testChainSimulatorChangeMetaData(t, issueSemiFungibleTx) + }) + + t.Run("metaESDT change metadata", func(t *testing.T) { + testChainSimulatorChangeMetaData(t, issueMetaESDTTx) + }) +} + +type issueTxFunc func(uint64, []byte, []byte, string) *transaction.Transaction + +func testChainSimulatorChangeMetaData(t *testing.T, issueFn issueTxFunc) { + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, true) + + log.Info("Initial setup: Create token and send in another shard") + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + []byte(core.ESDTRoleNFTAddQuantity), + } + + ticker := []byte("TICKER") + nonce := uint64(0) + tx := issueFn(nonce, addrs[1].Bytes, ticker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + tokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[1], tokenID, roles) + nonce++ + + log.Info("Issued token id", "tokenID", string(tokenID)) + + metaData := txsFee.GetDefaultMetaData() + metaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + txDataField := bytes.Join( + [][]byte{ + []byte(core.BuiltInFunctionESDTNFTCreate), + []byte(hex.EncodeToString(tokenID)), + []byte(hex.EncodeToString(big.NewInt(2).Bytes())), // quantity + metaData.Name, + []byte(hex.EncodeToString(big.NewInt(10).Bytes())), + metaData.Hash, + metaData.Attributes, + metaData.Uris[0], + metaData.Uris[1], + metaData.Uris[2], + }, + []byte("@"), + ) + + tx = &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[1].Bytes, + RcvAddr: addrs[1].Bytes, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: big.NewInt(0), + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + tx = changeToDynamicTx(nonce, addrs[1].Bytes, tokenID) + nonce++ + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Send to separate shards") + + tx = esdtNFTTransferTx(nonce, addrs[1].Bytes, addrs[2].Bytes, tokenID) + nonce++ + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + tx = esdtNFTTransferTx(nonce, addrs[1].Bytes, addrs[0].Bytes, tokenID) + nonce++ + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + roles = [][]byte{ + []byte(core.ESDTRoleTransfer), + []byte(core.ESDTRoleNFTUpdate), + } + tx = setSpecialRoleTx(nonce, addrs[1].Bytes, addrs[0].Bytes, tokenID, roles) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + log.Info("Step 1. change the sft meta data in one shard") + + sftMetaData2 := txsFee.GetDefaultMetaData() + sftMetaData2.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData2.Name = []byte(hex.EncodeToString([]byte("name2"))) + sftMetaData2.Hash = []byte(hex.EncodeToString([]byte("hash2"))) + sftMetaData2.Attributes = []byte(hex.EncodeToString([]byte("attributes2"))) + + txDataField = bytes.Join( + [][]byte{ + []byte(core.ESDTMetaDataUpdate), + []byte(hex.EncodeToString(tokenID)), + sftMetaData2.Nonce, + sftMetaData2.Name, + []byte(hex.EncodeToString(big.NewInt(10).Bytes())), + sftMetaData2.Hash, + sftMetaData2.Attributes, + sftMetaData2.Uris[0], + sftMetaData2.Uris[1], + sftMetaData2.Uris[2], + }, + []byte("@"), + ) + + tx = &transaction.Transaction{ + Nonce: 0, + SndAddr: addrs[0].Bytes, + RcvAddr: addrs[0].Bytes, + GasLimit: 10_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: big.NewInt(0), + ChainID: []byte(configs.ChainID), + Version: 1, + } + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + log.Info("Step 2. check that the newest metadata is saved") + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + checkMetaData(t, cs, core.SystemAccountAddress, tokenID, shardID, sftMetaData2) +} + +func TestChainSimulator_NFT_RegisterDynamic(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, true) + + log.Info("Register dynamic nft token") + + nftTicker := []byte("NFTTICKER") + nftTokenName := []byte("tokenName") + + txDataField := bytes.Join( + [][]byte{ + []byte("registerDynamic"), + []byte(hex.EncodeToString(nftTokenName)), + []byte(hex.EncodeToString(nftTicker)), + []byte(hex.EncodeToString([]byte("NFT"))), + }, + []byte("@"), + ) + + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + nonce := uint64(0) + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) + + log.Info("Check that token type is Dynamic") + + scQuery := &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + FuncName: "getTokenProperties", + CallValue: big.NewInt(0), + Arguments: [][]byte{nftTokenID}, + } + result, _, err := cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) + + tokenType := result.ReturnData[1] + require.Equal(t, core.DynamicNFTESDT, string(tokenType)) +} + +func TestChainSimulator_MetaESDT_RegisterDynamic(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } baseIssuingCost := "1000" - numOfShards := uint32(3) - cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, - TempDir: t.TempDir(), - PathToInitialConfig: defaultPathToInitialConfig, - NumOfShards: numOfShards, - GenesisTimestamp: startTime, - RoundDurationInMillis: roundDurationInMillis, - RoundsPerEpoch: roundsPerEpoch, - ApiInterface: api.NewNoApiInterface(), - MinNodesPerShard: 3, - MetaChainMinNodes: 3, - NumNodesWaitingListMeta: 0, - NumNodesWaitingListShard: 0, - AlterConfigsFunction: func(cfg *config.Configs) { - cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch - cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, true) + + log.Info("Register dynamic metaESDT token") + + metaTicker := []byte("METATICKER") + metaTokenName := []byte("tokenName") + + decimals := big.NewInt(15) + + txDataField := bytes.Join( + [][]byte{ + []byte("registerDynamic"), + []byte(hex.EncodeToString(metaTokenName)), + []byte(hex.EncodeToString(metaTicker)), + []byte(hex.EncodeToString([]byte("META"))), + []byte(hex.EncodeToString(decimals.Bytes())), }, - }) + []byte("@"), + ) + + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + nonce := uint64(0) + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) + + log.Info("Check that token type is Dynamic") + + scQuery := &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + FuncName: "getTokenProperties", + CallValue: big.NewInt(0), + Arguments: [][]byte{nftTokenID}, + } + result, _, err := cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) + + tokenType := result.ReturnData[1] + require.Equal(t, core.Dynamic+core.MetaESDT, string(tokenType)) +} + +func TestChainSimulator_FNG_RegisterDynamic(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, true) + + log.Info("Register dynamic fungible token") + + metaTicker := []byte("FNGTICKER") + metaTokenName := []byte("tokenName") + + decimals := big.NewInt(15) + + txDataField := bytes.Join( + [][]byte{ + []byte("registerDynamic"), + []byte(hex.EncodeToString(metaTokenName)), + []byte(hex.EncodeToString(metaTicker)), + []byte(hex.EncodeToString([]byte("FNG"))), + []byte(hex.EncodeToString(decimals.Bytes())), + }, + []byte("@"), + ) + + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + tx := &transaction.Transaction{ + Nonce: 0, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + signalErrorTopic := string(txResult.Logs.Events[0].Topics[1]) + + require.Equal(t, fmt.Sprintf("cannot create %s tokens as dynamic", core.FungibleESDT), signalErrorTopic) +} + +func TestChainSimulator_NFT_RegisterAndSetAllRolesDynamic(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, true) + + log.Info("Register dynamic nft token") + + nftTicker := []byte("NFTTICKER") + nftTokenName := []byte("tokenName") + + txDataField := bytes.Join( + [][]byte{ + []byte("registerAndSetAllRolesDynamic"), + []byte(hex.EncodeToString(nftTokenName)), + []byte(hex.EncodeToString(nftTicker)), + []byte(hex.EncodeToString([]byte("NFT"))), + }, + []byte("@"), + ) + + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + nonce := uint64(0) + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) + + log.Info("Check that token type is Dynamic") + + scQuery := &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + FuncName: "getTokenProperties", + CallValue: big.NewInt(0), + Arguments: [][]byte{nftTokenID}, + } + result, _, err := cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) + + tokenType := result.ReturnData[1] + require.Equal(t, core.DynamicNFTESDT, string(tokenType)) + + log.Info("Check token roles") + + scQuery = &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + FuncName: "getAllAddressesAndRoles", + CallValue: big.NewInt(0), + Arguments: [][]byte{nftTokenID}, + } + result, _, err = cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) + + expectedRoles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleNFTBurn), + []byte(core.ESDTRoleNFTUpdateAttributes), + []byte(core.ESDTRoleNFTAddURI), + []byte(core.ESDTRoleNFTRecreate), + []byte(core.ESDTRoleModifyCreator), + []byte(core.ESDTRoleModifyRoyalties), + []byte(core.ESDTRoleSetNewURI), + []byte(core.ESDTRoleNFTUpdate), + } + + checkTokenRoles(t, result.ReturnData, expectedRoles) +} + +func TestChainSimulator_SFT_RegisterAndSetAllRolesDynamic(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, true) + + log.Info("Register dynamic sft token") + + sftTicker := []byte("SFTTICKER") + sftTokenName := []byte("tokenName") + + txDataField := bytes.Join( + [][]byte{ + []byte("registerAndSetAllRolesDynamic"), + []byte(hex.EncodeToString(sftTokenName)), + []byte(hex.EncodeToString(sftTicker)), + []byte(hex.EncodeToString([]byte("SFT"))), + }, + []byte("@"), + ) + + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + nonce := uint64(0) + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) - require.NotNil(t, cs) + require.NotNil(t, txResult) - defer cs.Close() + require.Equal(t, "success", txResult.Status.String()) - mintValue := big.NewInt(10) - mintValue = mintValue.Mul(oneEGLD, mintValue) + sftTokenID := txResult.Logs.Events[0].Topics[0] + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], sftTokenID, roles) + nonce++ - address, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) - require.Nil(t, err) + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + tx = nftCreateTx(nonce, addrs[0].Bytes, sftTokenID, nftMetaData) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) err = cs.GenerateBlocks(10) require.Nil(t, err) - log.Info("Initial setup: Create NFT") + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) - nftTicker := []byte("NFTTICKER") - tx := issueNonFungibleTx(0, address.Bytes, nftTicker, baseIssuingCost) + checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, nftMetaData) - txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + log.Info("Check that token type is Dynamic") + + scQuery := &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + FuncName: "getTokenProperties", + CallValue: big.NewInt(0), + Arguments: [][]byte{sftTokenID}, + } + result, _, err := cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) require.Nil(t, err) - require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) - roles := [][]byte{ + tokenType := result.ReturnData[1] + require.Equal(t, core.DynamicSFTESDT, string(tokenType)) + + log.Info("Check token roles") + + scQuery = &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + FuncName: "getAllAddressesAndRoles", + CallValue: big.NewInt(0), + Arguments: [][]byte{sftTokenID}, + } + result, _, err = cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) + + expectedRoles := [][]byte{ []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleNFTBurn), + []byte(core.ESDTRoleNFTUpdateAttributes), + []byte(core.ESDTRoleNFTAddURI), + []byte(core.ESDTRoleNFTRecreate), + []byte(core.ESDTRoleModifyCreator), + []byte(core.ESDTRoleModifyRoyalties), + []byte(core.ESDTRoleSetNewURI), []byte(core.ESDTRoleNFTUpdate), } - nftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, address, nftTokenID, roles) + checkTokenRoles(t, result.ReturnData, expectedRoles) +} - log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) +func TestChainSimulator_FNG_RegisterAndSetAllRolesDynamic(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } - nftMetaData := txsFee.GetDefaultMetaData() - nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + baseIssuingCost := "1000" - tx = nftCreateTx(1, address.Bytes, nftTokenID, nftMetaData) + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) - require.Nil(t, err) - require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) + addrs := createAddresses(t, cs, true) - log.Info("Call ESDTMetaDataUpdate to rewrite the meta data for the nft") + log.Info("Register dynamic fungible token") - nonce := []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - nftMetaData.Name = []byte(hex.EncodeToString([]byte("name2"))) - nftMetaData.Hash = []byte(hex.EncodeToString([]byte("hash2"))) - nftMetaData.Attributes = []byte(hex.EncodeToString([]byte("attributes2"))) + fngTicker := []byte("FNGTICKER") + fngTokenName := []byte("tokenName") txDataField := bytes.Join( [][]byte{ - []byte(core.ESDTMetaDataUpdate), - []byte(hex.EncodeToString(nftTokenID)), - nonce, - nftMetaData.Name, + []byte("registerAndSetAllRolesDynamic"), + []byte(hex.EncodeToString(fngTokenName)), + []byte(hex.EncodeToString(fngTicker)), + []byte(hex.EncodeToString([]byte("FNG"))), []byte(hex.EncodeToString(big.NewInt(10).Bytes())), - nftMetaData.Hash, - nftMetaData.Attributes, - nftMetaData.Uris[0], - nftMetaData.Uris[1], - nftMetaData.Uris[2], }, []byte("@"), ) - tx = &transaction.Transaction{ - Nonce: 2, - SndAddr: address.Bytes, - RcvAddr: address.Bytes, - GasLimit: 10_000_000, + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + tx := &transaction.Transaction{ + Nonce: 0, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, GasPrice: minGasPrice, Signature: []byte("dummySig"), Data: txDataField, - Value: big.NewInt(0), + Value: callValue, ChainID: []byte(configs.ChainID), Version: 1, } - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) - - shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(address.Bytes) + signalErrorTopic := string(txResult.Logs.Events[0].Topics[1]) - checkMetaData(t, cs, address.Bytes, nftTokenID, shardID, nftMetaData) + require.Equal(t, fmt.Sprintf("cannot create %s tokens as dynamic", core.FungibleESDT), signalErrorTopic) } -// Test scenario #6 -// -// Initial setup: Create SFT -// -// Call ESDTModifyCreator and check that the creator was modified -// (The sender must have the ESDTRoleModifyCreator role) -func TestChainSimulator_NFT_ESDTModifyCreator(t *testing.T) { +func TestChainSimulator_MetaESDT_RegisterAndSetAllRolesDynamic(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") } - startTime := time.Now().Unix() - roundDurationInMillis := uint64(6000) - roundsPerEpoch := core.OptionalUint64{ - HasValue: true, - Value: 20, - } - - activationEpoch := uint32(4) - baseIssuingCost := "1000" - numOfShards := uint32(3) - cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, - TempDir: t.TempDir(), - PathToInitialConfig: defaultPathToInitialConfig, - NumOfShards: numOfShards, - GenesisTimestamp: startTime, - RoundDurationInMillis: roundDurationInMillis, - RoundsPerEpoch: roundsPerEpoch, - ApiInterface: api.NewNoApiInterface(), - MinNodesPerShard: 3, - MetaChainMinNodes: 3, - NumNodesWaitingListMeta: 0, - NumNodesWaitingListShard: 0, - AlterConfigsFunction: func(cfg *config.Configs) { - cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch - cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost - }, - }) - require.Nil(t, err) - require.NotNil(t, cs) - + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) defer cs.Close() - mintValue := big.NewInt(10) - mintValue = mintValue.Mul(oneEGLD, mintValue) + addrs := createAddresses(t, cs, true) - shardID := uint32(1) - address, err := cs.GenerateAndMintWalletAddress(shardID, mintValue) - require.Nil(t, err) + log.Info("Register dynamic meta esdt token") - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch) - 2) - require.Nil(t, err) + ticker := []byte("META" + "TICKER") + tokenName := []byte("tokenName") - err = cs.GenerateBlocks(10) - require.Nil(t, err) + decimals := big.NewInt(10) + + txDataField := bytes.Join( + [][]byte{ + []byte("registerAndSetAllRolesDynamic"), + []byte(hex.EncodeToString(tokenName)), + []byte(hex.EncodeToString(ticker)), + []byte(hex.EncodeToString([]byte("META"))), + []byte(hex.EncodeToString(decimals.Bytes())), + }, + []byte("@"), + ) - log.Info("Initial setup: Create SFT") + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) - sftTicker := []byte("SFTTICKER") - tx := issueSemiFungibleTx(0, address.Bytes, sftTicker, baseIssuingCost) + nonce := uint64(0) + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + metaTokenID := txResult.Logs.Events[0].Topics[0] roles := [][]byte{ []byte(core.ESDTRoleNFTCreate), - []byte(core.ESDTRoleNFTUpdate), + []byte(core.ESDTRoleTransfer), } - - sft := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, address, sft, roles) - - log.Info("Issued SFT token id", "tokenID", string(sft)) + setAddressEsdtRoles(t, cs, nonce, addrs[0], metaTokenID, roles) + nonce++ nftMetaData := txsFee.GetDefaultMetaData() nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - tx = nftCreateTx(1, address.Bytes, sft, nftMetaData) + tx = nftCreateTx(nonce, addrs[0].Bytes, metaTokenID, nftMetaData) txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) @@ -1226,76 +3009,174 @@ func TestChainSimulator_NFT_ESDTModifyCreator(t *testing.T) { require.Equal(t, "success", txResult.Status.String()) - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + err = cs.GenerateBlocks(10) require.Nil(t, err) - log.Info("Change to DYNAMIC type") + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) - tx = changeToDynamicTx(2, address.Bytes, sft) + checkMetaData(t, cs, core.SystemAccountAddress, metaTokenID, shardID, nftMetaData) - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) - require.Nil(t, err) - require.NotNil(t, txResult) + log.Info("Check that token type is Dynamic") - require.Equal(t, "success", txResult.Status.String()) + scQuery := &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + FuncName: "getTokenProperties", + CallValue: big.NewInt(0), + Arguments: [][]byte{metaTokenID}, + } + result, _, err := cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) - log.Info("Call ESDTModifyCreator and check that the creator was modified") + tokenType := result.ReturnData[1] + require.Equal(t, core.Dynamic+core.MetaESDT, string(tokenType)) - newCreatorAddress, err := cs.GenerateAndMintWalletAddress(shardID, mintValue) - require.Nil(t, err) + log.Info("Check token roles") - err = cs.GenerateBlocks(10) + scQuery = &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + FuncName: "getAllAddressesAndRoles", + CallValue: big.NewInt(0), + Arguments: [][]byte{metaTokenID}, + } + result, _, err = cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) - roles = [][]byte{ - []byte(core.ESDTRoleModifyCreator), + expectedRoles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleNFTBurn), + []byte(core.ESDTRoleNFTAddQuantity), + []byte(core.ESDTRoleNFTUpdateAttributes), + []byte(core.ESDTRoleNFTAddURI), } - setAddressEsdtRoles(t, cs, newCreatorAddress, sft, roles) - txDataField := bytes.Join( - [][]byte{ - []byte(core.ESDTModifyCreator), - []byte(hex.EncodeToString(sft)), - []byte(hex.EncodeToString(big.NewInt(1).Bytes())), - }, - []byte("@"), - ) + checkTokenRoles(t, result.ReturnData, expectedRoles) +} - tx = &transaction.Transaction{ - Nonce: 0, - SndAddr: newCreatorAddress.Bytes, - RcvAddr: newCreatorAddress.Bytes, - GasLimit: 10_000_000, - GasPrice: minGasPrice, - Signature: []byte("dummySig"), - Data: txDataField, - Value: big.NewInt(0), - ChainID: []byte(configs.ChainID), - Version: 1, +func checkTokenRoles(t *testing.T, returnData [][]byte, expectedRoles [][]byte) { + for _, expRole := range expectedRoles { + found := false + + for _, item := range returnData { + if bytes.Equal(expRole, item) { + found = true + } + } + + require.True(t, found) } +} - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) +func TestChainSimulator_NFTcreatedBeforeSaveToSystemAccountEnabled(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + cs, epochForDynamicNFT := getTestChainSimulatorWithSaveToSystemAccountDisabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + log.Info("Initial setup: Create NFT that will have it's metadata saved to the user account") + + nftTicker := []byte("NFTTICKER") + tx := issueNonFungibleTx(0, addrs[0].Bytes, nftTicker, baseIssuingCost) + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + nftTokenID := txResult.Logs.Events[0].Topics[0] + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + createTokenUpdateTokenIDAndTransfer(t, cs, addrs[0].Bytes, addrs[1].Bytes, nftTokenID, nftMetaData, epochForDynamicNFT, addrs[0]) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + checkMetaData(t, cs, addrs[1].Bytes, nftTokenID, shardID, nftMetaData) + checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, nftTokenID, shardID) + checkMetaDataNotInAcc(t, cs, core.SystemAccountAddress, nftTokenID, shardID) +} + +func TestChainSimulator_SFTcreatedBeforeSaveToSystemAccountEnabled(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + cs, epochForDynamicNFT := getTestChainSimulatorWithSaveToSystemAccountDisabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + log.Info("Initial setup: Create SFT that will have it's metadata saved to the user account") + + sftTicker := []byte("SFTTICKER") + tx := issueSemiFungibleTx(0, addrs[0].Bytes, sftTicker, baseIssuingCost) + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) + sftTokenID := txResult.Logs.Events[0].Topics[0] + + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + metaData := txsFee.GetDefaultMetaData() + metaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + createTokenUpdateTokenIDAndTransfer(t, cs, addrs[0].Bytes, addrs[1].Bytes, sftTokenID, metaData, epochForDynamicNFT, addrs[0]) - retrievedMetaData := getMetaDataFromAcc(t, cs, core.SystemAccountAddress, sft, shardID) + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) - require.Equal(t, newCreatorAddress.Bytes, retrievedMetaData.Creator) + checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, metaData) + checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, sftTokenID, shardID) + checkMetaDataNotInAcc(t, cs, addrs[1].Bytes, sftTokenID, shardID) } -// Test scenario #7 -// -// Initial setup: Create NFT -// -// Call ESDTSetNewURIs and check that the new URIs were set for the NFT -// (The sender must have the ESDTRoleSetNewURI role) -func TestChainSimulator_NFT_ESDTSetNewURIs(t *testing.T) { +func TestChainSimulator_MetaESDTCreatedBeforeSaveToSystemAccountEnabled(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") } + baseIssuingCost := "1000" + cs, epochForDynamicNFT := getTestChainSimulatorWithSaveToSystemAccountDisabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + log.Info("Initial setup: Create MetaESDT that will have it's metadata saved to the user account") + + metaTicker := []byte("METATICKER") + tx := issueMetaESDTTx(0, addrs[0].Bytes, metaTicker, baseIssuingCost) + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + metaTokenID := txResult.Logs.Events[0].Topics[0] + + log.Info("Issued MetaESDT token id", "tokenID", string(metaTokenID)) + + metaData := txsFee.GetDefaultMetaData() + metaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + createTokenUpdateTokenIDAndTransfer(t, cs, addrs[0].Bytes, addrs[1].Bytes, metaTokenID, metaData, epochForDynamicNFT, addrs[0]) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + checkMetaData(t, cs, core.SystemAccountAddress, metaTokenID, shardID, metaData) + checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, metaTokenID, shardID) + checkMetaDataNotInAcc(t, cs, addrs[1].Bytes, metaTokenID, shardID) +} + +func getTestChainSimulatorWithDynamicNFTEnabled(t *testing.T, baseIssuingCost string) (testsChainSimulator.ChainSimulator, int32) { startTime := time.Now().Unix() roundDurationInMillis := uint64(6000) roundsPerEpoch := core.OptionalUint64{ @@ -1303,13 +3184,11 @@ func TestChainSimulator_NFT_ESDTSetNewURIs(t *testing.T) { Value: 20, } - activationEpoch := uint32(2) - - baseIssuingCost := "1000" + activationEpochForDynamicNFT := uint32(2) numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -1322,125 +3201,20 @@ func TestChainSimulator_NFT_ESDTSetNewURIs(t *testing.T) { NumNodesWaitingListMeta: 0, NumNodesWaitingListShard: 0, AlterConfigsFunction: func(cfg *config.Configs) { - cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch + cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpochForDynamicNFT cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost }, }) require.Nil(t, err) require.NotNil(t, cs) - defer cs.Close() - - mintValue := big.NewInt(10) - mintValue = mintValue.Mul(oneEGLD, mintValue) - - address, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) - require.Nil(t, err) - - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) - require.Nil(t, err) - - err = cs.GenerateBlocks(10) - require.Nil(t, err) - - log.Info("Initial setup: Create NFT") - - nftTicker := []byte("NFTTICKER") - tx := issueNonFungibleTx(0, address.Bytes, nftTicker, baseIssuingCost) - - txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) - require.Nil(t, err) - require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) - - roles := [][]byte{ - []byte(core.ESDTRoleNFTCreate), - []byte(core.ESDTRoleNFTUpdate), - } - - nftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, address, nftTokenID, roles) - - log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) - - nftMetaData := txsFee.GetDefaultMetaData() - nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - - tx = nftCreateTx(1, address.Bytes, nftTokenID, nftMetaData) - - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) - require.Nil(t, err) - require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) - - log.Info("Call ESDTSetNewURIs and check that the new URIs were set for the NFT") - - roles = [][]byte{ - []byte(core.ESDTRoleSetNewURI), - } - setAddressEsdtRoles(t, cs, address, nftTokenID, roles) - - nonce := []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - uris := [][]byte{ - []byte(hex.EncodeToString([]byte("uri0"))), - []byte(hex.EncodeToString([]byte("uri1"))), - []byte(hex.EncodeToString([]byte("uri2"))), - } - - expUris := [][]byte{ - []byte("uri0"), - []byte("uri1"), - []byte("uri2"), - } - - txDataField := bytes.Join( - [][]byte{ - []byte(core.ESDTSetNewURIs), - []byte(hex.EncodeToString(nftTokenID)), - nonce, - uris[0], - uris[1], - uris[2], - }, - []byte("@"), - ) - - tx = &transaction.Transaction{ - Nonce: 2, - SndAddr: address.Bytes, - RcvAddr: address.Bytes, - GasLimit: 10_000_000, - GasPrice: minGasPrice, - Signature: []byte("dummySig"), - Data: txDataField, - Value: big.NewInt(0), - ChainID: []byte(configs.ChainID), - Version: 1, - } - - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpochForDynamicNFT)) require.Nil(t, err) - require.NotNil(t, txResult) - - require.Equal(t, "success", txResult.Status.String()) - - shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(address.Bytes) - retrievedMetaData := getMetaDataFromAcc(t, cs, address.Bytes, nftTokenID, shardID) - require.Equal(t, expUris, retrievedMetaData.URIs) + return cs, int32(activationEpochForDynamicNFT) } -// Test scenario #8 -// -// Initial setup: Create NFT -// -// Call ESDTModifyRoyalties and check that the royalties were changed -// (The sender must have the ESDTRoleModifyRoyalties role) -func TestChainSimulator_NFT_ESDTModifyRoyalties(t *testing.T) { - if testing.Short() { - t.Skip("this is not a short test") - } - +func getTestChainSimulatorWithSaveToSystemAccountDisabled(t *testing.T, baseIssuingCost string) (testsChainSimulator.ChainSimulator, int32) { startTime := time.Now().Unix() roundDurationInMillis := uint64(6000) roundsPerEpoch := core.OptionalUint64{ @@ -1448,13 +3222,12 @@ func TestChainSimulator_NFT_ESDTModifyRoyalties(t *testing.T) { Value: 20, } - activationEpoch := uint32(2) - - baseIssuingCost := "1000" + activationEpochForSaveToSystemAccount := uint32(4) + activationEpochForDynamicNFT := uint32(6) numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -1467,110 +3240,242 @@ func TestChainSimulator_NFT_ESDTModifyRoyalties(t *testing.T) { NumNodesWaitingListMeta: 0, NumNodesWaitingListShard: 0, AlterConfigsFunction: func(cfg *config.Configs) { - cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch + cfg.EpochConfig.EnableEpochs.OptimizeNFTStoreEnableEpoch = activationEpochForSaveToSystemAccount + cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpochForDynamicNFT cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost }, }) require.Nil(t, err) require.NotNil(t, cs) - defer cs.Close() + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpochForSaveToSystemAccount) - 2) + require.Nil(t, err) - mintValue := big.NewInt(10) - mintValue = mintValue.Mul(oneEGLD, mintValue) + return cs, int32(activationEpochForDynamicNFT) +} + +func createTokenUpdateTokenIDAndTransfer( + t *testing.T, + cs testsChainSimulator.ChainSimulator, + originAddress []byte, + targetAddress []byte, + tokenID []byte, + metaData *txsFee.MetaData, + epochForDynamicNFT int32, + walletWithRoles dtos.WalletAddress, +) { + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + setAddressEsdtRoles(t, cs, 1, walletWithRoles, tokenID, roles) + + tx := nftCreateTx(2, originAddress, tokenID, metaData) + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + log.Info("check that the metadata is saved on the user account") + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(originAddress) + checkMetaData(t, cs, originAddress, tokenID, shardID, metaData) + checkMetaDataNotInAcc(t, cs, core.SystemAccountAddress, tokenID, shardID) - address, err := cs.GenerateAndMintWalletAddress(core.AllShardId, mintValue) + err = cs.GenerateBlocksUntilEpochIsReached(epochForDynamicNFT) require.Nil(t, err) - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + tx = updateTokenIDTx(3, originAddress, tokenID) + + log.Info("updating token id", "tokenID", tokenID) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) err = cs.GenerateBlocks(10) require.Nil(t, err) - log.Info("Initial setup: Create NFT") + log.Info("transferring token id", "tokenID", tokenID) - nftTicker := []byte("NFTTICKER") - tx := issueNonFungibleTx(0, address.Bytes, nftTicker, baseIssuingCost) + tx = esdtNFTTransferTx(4, originAddress, targetAddress, tokenID) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) +} + +func TestChainSimulator_ChangeToDynamic_OldTokens(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + baseIssuingCost := "1000" + + cs, epochForDynamicNFT := getTestChainSimulatorWithSaveToSystemAccountDisabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, false) + + // issue metaESDT + metaESDTTicker := []byte("METATICKER") + nonce := uint64(0) + tx := issueMetaESDTTx(nonce, addrs[0].Bytes, metaESDTTicker, baseIssuingCost) + nonce++ txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) + metaESDTTokenID := txResult.Logs.Events[0].Topics[0] + roles := [][]byte{ []byte(core.ESDTRoleNFTCreate), - []byte(core.ESDTRoleNFTUpdate), + []byte(core.ESDTRoleTransfer), } + setAddressEsdtRoles(t, cs, nonce, addrs[0], metaESDTTokenID, roles) + nonce++ + + log.Info("Issued metaESDT token id", "tokenID", string(metaESDTTokenID)) + + // issue NFT + nftTicker := []byte("NFTTICKER") + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) nftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, address, nftTokenID, roles) + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) - nftMetaData := txsFee.GetDefaultMetaData() - nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - - tx = nftCreateTx(1, address.Bytes, nftTokenID, nftMetaData) + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) - log.Info("Call ESDTModifyRoyalties and check that the royalties were changed") + sftTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[0], sftTokenID, roles) + nonce++ - roles = [][]byte{ - []byte(core.ESDTRoleModifyRoyalties), + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + metaESDTTokenID, } - setAddressEsdtRoles(t, cs, address, nftTokenID, roles) - nonce := []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - royalties := []byte(hex.EncodeToString(big.NewInt(20).Bytes())) + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - txDataField := bytes.Join( - [][]byte{ - []byte(core.ESDTModifyRoyalties), - []byte(hex.EncodeToString(nftTokenID)), - nonce, - royalties, - }, - []byte("@"), - ) + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - tx = &transaction.Transaction{ - Nonce: 2, - SndAddr: address.Bytes, - RcvAddr: address.Bytes, - GasLimit: 10_000_000, - GasPrice: minGasPrice, - Signature: []byte("dummySig"), - Data: txDataField, - Value: big.NewInt(0), - ChainID: []byte(configs.ChainID), - Version: 1, + esdtMetaData := txsFee.GetDefaultMetaData() + esdtMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + esdtMetaData, } - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + // meta data should be saved on account, since it is before `OptimizeNFTStoreEnableEpoch` + checkMetaData(t, cs, addrs[0].Bytes, nftTokenID, shardID, nftMetaData) + checkMetaDataNotInAcc(t, cs, core.SystemAccountAddress, nftTokenID, shardID) + + checkMetaData(t, cs, addrs[0].Bytes, sftTokenID, shardID, sftMetaData) + checkMetaDataNotInAcc(t, cs, core.SystemAccountAddress, sftTokenID, shardID) + + checkMetaData(t, cs, addrs[0].Bytes, metaESDTTokenID, shardID, esdtMetaData) + checkMetaDataNotInAcc(t, cs, core.SystemAccountAddress, metaESDTTokenID, shardID) + + err = cs.GenerateBlocksUntilEpochIsReached(int32(epochForDynamicNFT)) require.Nil(t, err) - require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) + log.Info("Change to DYNAMIC type") + + // it will not be able to change nft to dynamic type + for i := range tokenIDs { + tx = changeToDynamicTx(nonce, addrs[0].Bytes, tokenIDs[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + for _, tokenID := range tokenIDs { + tx = updateTokenIDTx(nonce, addrs[0].Bytes, tokenID) + + log.Info("updating token id", "tokenID", tokenID) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + for _, tokenID := range tokenIDs { + log.Info("transfering token id", "tokenID", tokenID) + + tx = esdtNFTTransferTx(nonce, addrs[0].Bytes, addrs[1].Bytes, tokenID) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, sftMetaData) + checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, sftTokenID, shardID) + checkMetaDataNotInAcc(t, cs, addrs[1].Bytes, sftTokenID, shardID) - shardID := cs.GetNodeHandler(0).GetShardCoordinator().ComputeId(address.Bytes) - retrievedMetaData := getMetaDataFromAcc(t, cs, address.Bytes, nftTokenID, shardID) + checkMetaData(t, cs, core.SystemAccountAddress, metaESDTTokenID, shardID, esdtMetaData) + checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, metaESDTTokenID, shardID) + checkMetaDataNotInAcc(t, cs, addrs[1].Bytes, metaESDTTokenID, shardID) - require.Equal(t, uint32(big.NewInt(20).Uint64()), retrievedMetaData.Royalties) + checkMetaData(t, cs, addrs[1].Bytes, nftTokenID, shardID, nftMetaData) + checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, nftTokenID, shardID) + checkMetaDataNotInAcc(t, cs, core.SystemAccountAddress, nftTokenID, shardID) } -// Test scenario #9 -// -// Initial setup: Create NFT -// -// 1. Change the nft to DYNAMIC type - the metadata should be on the system account -// 2. Send the NFT cross shard -// 3. The meta data should still be present on the system account -func TestChainSimulator_NFT_ChangeToDynamicType(t *testing.T) { +func TestChainSimulator_CreateAndPause_NFT(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") } @@ -1588,7 +3493,7 @@ func TestChainSimulator_NFT_ChangeToDynamicType(t *testing.T) { numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -1610,15 +3515,40 @@ func TestChainSimulator_NFT_ChangeToDynamicType(t *testing.T) { defer cs.Close() - addrs := createAddresses(t, cs, true) + addrs := createAddresses(t, cs, false) - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch) - 2) + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch) - 1) require.Nil(t, err) - log.Info("Initial setup: Create NFT") - + // issue NFT nftTicker := []byte("NFTTICKER") - tx := issueNonFungibleTx(0, addrs[1].Bytes, nftTicker, baseIssuingCost) + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + txDataField := bytes.Join( + [][]byte{ + []byte("issueNonFungible"), + []byte(hex.EncodeToString([]byte("asdname"))), + []byte(hex.EncodeToString(nftTicker)), + []byte(hex.EncodeToString([]byte("canPause"))), + []byte(hex.EncodeToString([]byte("true"))), + }, + []byte("@"), + ) + + nonce := uint64(0) + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: core.ESDTSCAddress, + GasLimit: 100_000_000, + GasPrice: minGasPrice, + Signature: []byte("dummySig"), + Data: txDataField, + Value: callValue, + ChainID: []byte(configs.ChainID), + Version: 1, + } + nonce++ txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) @@ -1627,66 +3557,96 @@ func TestChainSimulator_NFT_ChangeToDynamicType(t *testing.T) { roles := [][]byte{ []byte(core.ESDTRoleNFTCreate), - []byte(core.ESDTRoleNFTUpdate), + []byte(core.ESDTRoleTransfer), } - nftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, addrs[1], nftTokenID, roles) + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) nftMetaData := txsFee.GetDefaultMetaData() nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - tx = nftCreateTx(1, addrs[1].Bytes, nftTokenID, nftMetaData) + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + nonce++ txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + log.Info("check that the metadata for all tokens is saved on the system account") + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) + + log.Info("Pause all tokens") + + scQuery := &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + CallerAddr: addrs[0].Bytes, + FuncName: "pause", + CallValue: big.NewInt(0), + Arguments: [][]byte{nftTokenID}, + } + result, _, err := cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) + + log.Info("wait for DynamicEsdtFlag activation") + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) require.Nil(t, err) - log.Info("Step 1. Change the nft to DYNAMIC type - the metadata should be on the system account") + log.Info("make an updateTokenID@tokenID function call on the ESDTSystem SC for all token types") - shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[1].Bytes) + tx = updateTokenIDTx(nonce, addrs[0].Bytes, nftTokenID) + nonce++ - tx = changeToDynamicTx(2, addrs[1].Bytes, nftTokenID) + log.Info("updating token id", "tokenID", nftTokenID) txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) + log.Info("check that the metadata for all tokens is saved on the system account") + err = cs.GenerateBlocks(10) require.Nil(t, err) checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) - log.Info("Step 2. Send the NFT cross shard") + log.Info("transfer the tokens to another account") - tx = esdtNFTTransferTx(3, addrs[1].Bytes, addrs[2].Bytes, nftTokenID) + log.Info("transfering token id", "tokenID", nftTokenID) + + tx = esdtNFTTransferTx(nonce, addrs[0].Bytes, addrs[1].Bytes, nftTokenID) txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) - log.Info("Step 3. The meta data should still be present on the system account") + log.Info("check that the metaData for the NFT is still on the system account") - checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + shardID = cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[2].Bytes) + + checkMetaData(t, cs, addrs[1].Bytes, nftTokenID, shardID, nftMetaData) + checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, nftTokenID, shardID) + checkMetaDataNotInAcc(t, cs, core.SystemAccountAddress, nftTokenID, shardID) } -// Test scenario #10 -// -// Initial setup: Create SFT and send in 2 shards -// -// 1. change the sft meta data in one shard -// 2. change the sft meta data (differently from the previous one) in the other shard -// 3. send sft from one shard to another -// 4. check that the newest metadata is saved -func TestChainSimulator_SFT_ChangeMetaData(t *testing.T) { +func TestChainSimulator_CreateAndPauseTokens_DynamicNFT(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") } @@ -1698,13 +3658,13 @@ func TestChainSimulator_SFT_ChangeMetaData(t *testing.T) { Value: 20, } - activationEpoch := uint32(2) + activationEpoch := uint32(4) baseIssuingCost := "1000" numOfShards := uint32(3) cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: numOfShards, @@ -1726,209 +3686,231 @@ func TestChainSimulator_SFT_ChangeMetaData(t *testing.T) { defer cs.Close() - addrs := createAddresses(t, cs, true) - - err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) - require.Nil(t, err) + addrs := createAddresses(t, cs, false) - err = cs.GenerateBlocks(10) + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch) - 1) require.Nil(t, err) - log.Info("Initial setup: Create SFT and send in 2 shards") - - roles := [][]byte{ - []byte(core.ESDTRoleNFTCreate), - []byte(core.ESDTRoleNFTUpdate), - []byte(core.ESDTRoleNFTAddQuantity), - } - - sftTicker := []byte("SFTTICKER") - tx := issueSemiFungibleTx(0, addrs[1].Bytes, sftTicker, baseIssuingCost) + log.Info("Step 2. wait for DynamicEsdtFlag activation") - txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) require.Nil(t, err) - require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) - - sftTokenID := txResult.Logs.Events[0].Topics[0] - setAddressEsdtRoles(t, cs, addrs[1], sftTokenID, roles) - - setAddressEsdtRoles(t, cs, addrs[0], sftTokenID, roles) - setAddressEsdtRoles(t, cs, addrs[2], sftTokenID, roles) - - log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) - - sftMetaData := txsFee.GetDefaultMetaData() - sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + // register dynamic NFT + nftTicker := []byte("NFTTICKER") + nftTokenName := []byte("tokenName") txDataField := bytes.Join( [][]byte{ - []byte(core.BuiltInFunctionESDTNFTCreate), - []byte(hex.EncodeToString(sftTokenID)), - []byte(hex.EncodeToString(big.NewInt(2).Bytes())), // quantity - sftMetaData.Name, - []byte(hex.EncodeToString(big.NewInt(10).Bytes())), - sftMetaData.Hash, - sftMetaData.Attributes, - sftMetaData.Uris[0], - sftMetaData.Uris[1], - sftMetaData.Uris[2], + []byte("registerDynamic"), + []byte(hex.EncodeToString(nftTokenName)), + []byte(hex.EncodeToString(nftTicker)), + []byte(hex.EncodeToString([]byte("NFT"))), + []byte(hex.EncodeToString([]byte("canPause"))), + []byte(hex.EncodeToString([]byte("true"))), }, []byte("@"), ) - tx = &transaction.Transaction{ - Nonce: 1, - SndAddr: addrs[1].Bytes, - RcvAddr: addrs[1].Bytes, - GasLimit: 10_000_000, + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + nonce := uint64(0) + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, GasPrice: minGasPrice, Signature: []byte("dummySig"), Data: txDataField, - Value: big.NewInt(0), + Value: callValue, ChainID: []byte(configs.ChainID), Version: 1, } + nonce++ - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + []byte(core.ESDTRoleNFTUpdate), + } + + nftTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + err = cs.GenerateBlocks(10) require.Nil(t, err) - log.Info("Send to separate shards") + log.Info("Step 1. check that the metadata for all tokens is saved on the system account") + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) + + log.Info("Step 1b. Pause all tokens") + + scQuery := &process.SCQuery{ + ScAddress: vm.ESDTSCAddress, + CallerAddr: addrs[0].Bytes, + FuncName: "pause", + CallValue: big.NewInt(0), + Arguments: [][]byte{nftTokenID}, + } + result, _, err := cs.GetNodeHandler(core.MetachainShardId).GetFacadeHandler().ExecuteSCQuery(scQuery) + require.Nil(t, err) + require.Equal(t, "", result.ReturnMessage) + require.Equal(t, testsChainSimulator.OkReturnCode, result.ReturnCode) + + tx = updateTokenIDTx(nonce, addrs[0].Bytes, nftTokenID) + nonce++ + + log.Info("updating token id", "tokenID", nftTokenID) - tx = esdtNFTTransferTx(2, addrs[1].Bytes, addrs[2].Bytes, sftTokenID) txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) - tx = esdtNFTTransferTx(3, addrs[1].Bytes, addrs[0].Bytes, sftTokenID) + log.Info("change to dynamic token") + + tx = changeToDynamicTx(nonce, addrs[0].Bytes, nftTokenID) + nonce++ + + log.Info("updating token id", "tokenID", nftTokenID) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) + log.Info("check that the metadata for all tokens is saved on the system account") + err = cs.GenerateBlocks(10) require.Nil(t, err) - log.Info("Step 1. change the sft meta data in one shard") - - sftMetaData2 := txsFee.GetDefaultMetaData() - sftMetaData2.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) - - sftMetaData2.Name = []byte(hex.EncodeToString([]byte("name2"))) - sftMetaData2.Hash = []byte(hex.EncodeToString([]byte("hash2"))) - sftMetaData2.Attributes = []byte(hex.EncodeToString([]byte("attributes2"))) - - txDataField = bytes.Join( - [][]byte{ - []byte(core.ESDTMetaDataUpdate), - []byte(hex.EncodeToString(sftTokenID)), - sftMetaData2.Nonce, - sftMetaData2.Name, - []byte(hex.EncodeToString(big.NewInt(10).Bytes())), - sftMetaData2.Hash, - sftMetaData2.Attributes, - sftMetaData2.Uris[0], - sftMetaData2.Uris[1], - sftMetaData2.Uris[2], - }, - []byte("@"), - ) + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) - tx = &transaction.Transaction{ - Nonce: 0, - SndAddr: addrs[0].Bytes, - RcvAddr: addrs[0].Bytes, - GasLimit: 10_000_000, - GasPrice: minGasPrice, - Signature: []byte("dummySig"), - Data: txDataField, - Value: big.NewInt(0), - ChainID: []byte(configs.ChainID), - Version: 1, - } + log.Info("transfering token id", "tokenID", nftTokenID) + tx = esdtNFTTransferTx(nonce, addrs[0].Bytes, addrs[1].Bytes, nftTokenID) txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) - require.Equal(t, "success", txResult.Status.String()) - shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + log.Info("check that the metaData for the NFT is still on the system account") + + err = cs.GenerateBlocks(10) + require.Nil(t, err) - checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, sftMetaData2) + shardID = cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[2].Bytes) - log.Info("Step 2. change the sft meta data (differently from the previous one) in the other shard") + checkMetaData(t, cs, core.SystemAccountAddress, nftTokenID, shardID, nftMetaData) + checkMetaDataNotInAcc(t, cs, addrs[0].Bytes, nftTokenID, shardID) + checkMetaDataNotInAcc(t, cs, addrs[1].Bytes, nftTokenID, shardID) +} - sftMetaData3 := txsFee.GetDefaultMetaData() - sftMetaData3.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) +func TestChainSimulator_CheckRolesWhichHasToBeSingular(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } - sftMetaData3.Name = []byte(hex.EncodeToString([]byte("name3"))) - sftMetaData3.Hash = []byte(hex.EncodeToString([]byte("hash3"))) - sftMetaData3.Attributes = []byte(hex.EncodeToString([]byte("attributes3"))) + baseIssuingCost := "1000" - txDataField = bytes.Join( + cs, _ := getTestChainSimulatorWithDynamicNFTEnabled(t, baseIssuingCost) + defer cs.Close() + + addrs := createAddresses(t, cs, true) + + // register dynamic NFT + nftTicker := []byte("NFTTICKER") + nftTokenName := []byte("tokenName") + + txDataField := bytes.Join( [][]byte{ - []byte(core.ESDTMetaDataUpdate), - []byte(hex.EncodeToString(sftTokenID)), - sftMetaData3.Nonce, - sftMetaData3.Name, - []byte(hex.EncodeToString(big.NewInt(10).Bytes())), - sftMetaData3.Hash, - sftMetaData3.Attributes, - sftMetaData3.Uris[0], - sftMetaData3.Uris[1], - sftMetaData3.Uris[2], + []byte("registerDynamic"), + []byte(hex.EncodeToString(nftTokenName)), + []byte(hex.EncodeToString(nftTicker)), + []byte(hex.EncodeToString([]byte("NFT"))), + []byte(hex.EncodeToString([]byte("canPause"))), + []byte(hex.EncodeToString([]byte("true"))), }, []byte("@"), ) - tx = &transaction.Transaction{ - Nonce: 0, - SndAddr: addrs[2].Bytes, - RcvAddr: addrs[2].Bytes, - GasLimit: 10_000_000, + callValue, _ := big.NewInt(0).SetString(baseIssuingCost, 10) + + nonce := uint64(0) + tx := &transaction.Transaction{ + Nonce: nonce, + SndAddr: addrs[0].Bytes, + RcvAddr: vm.ESDTSCAddress, + GasLimit: 100_000_000, GasPrice: minGasPrice, Signature: []byte("dummySig"), Data: txDataField, - Value: big.NewInt(0), + Value: callValue, ChainID: []byte(configs.ChainID), Version: 1, } + nonce++ - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) require.Nil(t, err) require.NotNil(t, txResult) require.Equal(t, "success", txResult.Status.String()) - shardID = cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[2].Bytes) - - checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, sftMetaData3) - - log.Info("Step 3. send sft from one shard to another") - - tx = esdtNFTTransferTx(1, addrs[0].Bytes, addrs[2].Bytes, sftTokenID) - txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) - require.Nil(t, err) - require.NotNil(t, txResult) + nftTokenID := txResult.Logs.Events[0].Topics[0] - require.Equal(t, "success", txResult.Status.String()) + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) - err = cs.GenerateBlocks(10) - require.Nil(t, err) + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleNFTUpdateAttributes), + []byte(core.ESDTRoleNFTAddURI), + []byte(core.ESDTRoleSetNewURI), + []byte(core.ESDTRoleModifyCreator), + []byte(core.ESDTRoleModifyRoyalties), + []byte(core.ESDTRoleNFTRecreate), + []byte(core.ESDTRoleNFTUpdate), + } + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ - log.Info("Step 4. check that the newest metadata is saved") + for _, role := range roles { + tx = setSpecialRoleTx(nonce, addrs[0].Bytes, addrs[1].Bytes, nftTokenID, [][]byte{role}) + nonce++ - shardID = cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[2].Bytes) + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) - checkMetaData(t, cs, core.SystemAccountAddress, sftTokenID, shardID, sftMetaData2) + if txResult.Logs != nil && len(txResult.Logs.Events) > 0 { + returnMessage := string(txResult.Logs.Events[0].Topics[1]) + require.True(t, strings.Contains(returnMessage, "already exists")) + } else { + require.Fail(t, "should have been return error message") + } + } } diff --git a/integrationTests/chainSimulator/vm/esdtTokens_test.go b/integrationTests/chainSimulator/vm/esdtTokens_test.go new file mode 100644 index 00000000000..d12bfcbb550 --- /dev/null +++ b/integrationTests/chainSimulator/vm/esdtTokens_test.go @@ -0,0 +1,401 @@ +package vm + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "net/http" + "testing" + "time" + + "github.com/multiversx/mx-chain-core-go/core" + "github.com/multiversx/mx-chain-go/api/groups" + "github.com/multiversx/mx-chain-go/config" + "github.com/multiversx/mx-chain-go/integrationTests/vm/txsFee" + "github.com/multiversx/mx-chain-go/node/chainSimulator" + "github.com/multiversx/mx-chain-go/node/chainSimulator/components/api" + "github.com/stretchr/testify/require" +) + +type esdtTokensCompleteResponseData struct { + Tokens map[string]groups.ESDTNFTTokenData `json:"esdts"` +} + +type esdtTokensCompleteResponse struct { + Data esdtTokensCompleteResponseData `json:"data"` + Error string `json:"error"` + Code string +} + +func TestChainSimulator_Api_TokenType(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + activationEpoch := uint32(2) + + baseIssuingCost := "1000" + + numOfShards := uint32(3) + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: numOfShards, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewFreePortAPIConfigurator("localhost"), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch + cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + require.Nil(t, err) + + log.Info("Initial setup: Create tokens") + + addrs := createAddresses(t, cs, false) + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + + // issue fungible + fungibleTicker := []byte("FUNTICKER") + nonce := uint64(0) + tx := issueTx(nonce, addrs[0].Bytes, fungibleTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + fungibleTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[0], fungibleTokenID, roles) + nonce++ + + log.Info("Issued fungible token id", "tokenID", string(fungibleTokenID)) + + // issue NFT + nftTicker := []byte("NFTTICKER") + tx = issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + // issue SFT + sftTicker := []byte("SFTTICKER") + tx = issueSemiFungibleTx(nonce, addrs[0].Bytes, sftTicker, baseIssuingCost) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + sftTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[0], sftTokenID, roles) + nonce++ + + log.Info("Issued SFT token id", "tokenID", string(sftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + sftMetaData := txsFee.GetDefaultMetaData() + sftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + fungibleMetaData := txsFee.GetDefaultMetaData() + fungibleMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tokenIDs := [][]byte{ + nftTokenID, + sftTokenID, + } + + tokensMetadata := []*txsFee.MetaData{ + nftMetaData, + sftMetaData, + } + + for i := range tokenIDs { + tx = nftCreateTx(nonce, addrs[0].Bytes, tokenIDs[i], tokensMetadata[i]) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + nonce++ + } + + err = cs.GenerateBlocks(10) + require.Nil(t, err) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + restAPIInterfaces := cs.GetRestAPIInterfaces() + require.NotNil(t, restAPIInterfaces) + + url := fmt.Sprintf("http://%s/address/%s/esdt", restAPIInterfaces[shardID], addrs[0].Bech32) + response := &esdtTokensCompleteResponse{} + + doHTTPClientGetReq(t, url, response) + + allTokens := response.Data.Tokens + + require.Equal(t, 3, len(allTokens)) + + expTokenID := string(fungibleTokenID) + tokenData, ok := allTokens[expTokenID] + require.True(t, ok) + require.Equal(t, expTokenID, tokenData.TokenIdentifier) + require.Equal(t, core.FungibleESDT, tokenData.Type) + + expTokenID = string(nftTokenID) + "-01" + tokenData, ok = allTokens[expTokenID] + require.True(t, ok) + require.Equal(t, expTokenID, tokenData.TokenIdentifier) + require.Equal(t, core.NonFungibleESDTv2, tokenData.Type) + + expTokenID = string(sftTokenID) + "-01" + tokenData, ok = allTokens[expTokenID] + require.True(t, ok) + require.Equal(t, expTokenID, tokenData.TokenIdentifier) + require.Equal(t, core.SemiFungibleESDT, tokenData.Type) +} + +func TestChainSimulator_Api_NFTToken(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + + activationEpoch := uint32(2) + + baseIssuingCost := "1000" + + numOfShards := uint32(3) + cs, err := chainSimulator.NewChainSimulator(chainSimulator.ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: numOfShards, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewFreePortAPIConfigurator("localhost"), + MinNodesPerShard: 3, + MetaChainMinNodes: 3, + NumNodesWaitingListMeta: 0, + NumNodesWaitingListShard: 0, + AlterConfigsFunction: func(cfg *config.Configs) { + cfg.EpochConfig.EnableEpochs.DynamicESDTEnableEpoch = activationEpoch + cfg.SystemSCConfig.ESDTSystemSCConfig.BaseIssuingCost = baseIssuingCost + }, + }) + require.Nil(t, err) + require.NotNil(t, cs) + + defer cs.Close() + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch) - 1) + require.Nil(t, err) + + log.Info("Initial setup: Create NFT token before activation") + + addrs := createAddresses(t, cs, false) + + roles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleTransfer), + } + + // issue NFT + nftTicker := []byte("NFTTICKER") + nonce := uint64(0) + tx := issueNonFungibleTx(nonce, addrs[0].Bytes, nftTicker, baseIssuingCost) + nonce++ + + txResult, err := cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + nftTokenID := txResult.Logs.Events[0].Topics[0] + setAddressEsdtRoles(t, cs, nonce, addrs[0], nftTokenID, roles) + nonce++ + + log.Info("Issued NFT token id", "tokenID", string(nftTokenID)) + + nftMetaData := txsFee.GetDefaultMetaData() + nftMetaData.Nonce = []byte(hex.EncodeToString(big.NewInt(1).Bytes())) + + tx = nftCreateTx(nonce, addrs[0].Bytes, nftTokenID, nftMetaData) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + err = cs.GenerateBlocks(5) + require.Nil(t, err) + + shardID := cs.GetNodeHandler(0).GetProcessComponents().ShardCoordinator().ComputeId(addrs[0].Bytes) + + restAPIInterfaces := cs.GetRestAPIInterfaces() + require.NotNil(t, restAPIInterfaces) + + url := fmt.Sprintf("http://%s/address/%s/esdt", restAPIInterfaces[shardID], addrs[0].Bech32) + response := &esdtTokensCompleteResponse{} + + doHTTPClientGetReq(t, url, response) + + allTokens := response.Data.Tokens + + require.Equal(t, 1, len(allTokens)) + + expTokenID := string(nftTokenID) + "-01" + tokenData, ok := allTokens[expTokenID] + require.True(t, ok) + require.Equal(t, expTokenID, tokenData.TokenIdentifier) + require.Equal(t, "", tokenData.Type) + + log.Info("Wait for DynamicESDTFlag activation") + + err = cs.GenerateBlocksUntilEpochIsReached(int32(activationEpoch)) + require.Nil(t, err) + + doHTTPClientGetReq(t, url, response) + + allTokens = response.Data.Tokens + + require.Equal(t, 1, len(allTokens)) + + expTokenID = string(nftTokenID) + "-01" + tokenData, ok = allTokens[expTokenID] + require.True(t, ok) + require.Equal(t, expTokenID, tokenData.TokenIdentifier) + require.Equal(t, "", tokenData.Type) + + log.Info("Update token id", "tokenID", nftTokenID) + + tx = updateTokenIDTx(nonce, addrs[0].Bytes, nftTokenID) + nonce++ + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + doHTTPClientGetReq(t, url, response) + + allTokens = response.Data.Tokens + + require.Equal(t, 1, len(allTokens)) + + expTokenID = string(nftTokenID) + "-01" + tokenData, ok = allTokens[expTokenID] + require.True(t, ok) + require.Equal(t, expTokenID, tokenData.TokenIdentifier) + require.Equal(t, "", tokenData.Type) + + log.Info("Transfer token id", "tokenID", nftTokenID) + + tx = esdtNFTTransferTx(nonce, addrs[0].Bytes, addrs[1].Bytes, nftTokenID) + nonce++ + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + require.Equal(t, "success", txResult.Status.String()) + + url = fmt.Sprintf("http://%s/address/%s/esdt", restAPIInterfaces[1], addrs[1].Bech32) + doHTTPClientGetReq(t, url, response) + + allTokens = response.Data.Tokens + + require.Equal(t, 1, len(allTokens)) + + expTokenID = string(nftTokenID) + "-01" + tokenData, ok = allTokens[expTokenID] + require.True(t, ok) + require.Equal(t, expTokenID, tokenData.TokenIdentifier) + require.Equal(t, core.NonFungibleESDTv2, tokenData.Type) + + log.Info("Change to DYNAMIC type") + + tx = changeToDynamicTx(nonce, addrs[0].Bytes, nftTokenID) + + txResult, err = cs.SendTxAndGenerateBlockTilTxIsExecuted(tx, maxNumOfBlockToGenerateWhenExecutingTx) + require.Nil(t, err) + require.NotNil(t, txResult) + + require.Equal(t, "success", txResult.Status.String()) + + response = &esdtTokensCompleteResponse{} + doHTTPClientGetReq(t, url, response) + + allTokens = response.Data.Tokens + + require.Equal(t, 1, len(allTokens)) + + expTokenID = string(nftTokenID) + "-01" + tokenData, ok = allTokens[expTokenID] + require.True(t, ok) + require.Equal(t, expTokenID, tokenData.TokenIdentifier) + require.Equal(t, core.NonFungibleESDTv2, tokenData.Type) +} + +func doHTTPClientGetReq(t *testing.T, url string, response interface{}) { + httpClient := &http.Client{} + + req, err := http.NewRequest(http.MethodGet, url, nil) + require.Nil(t, err) + + resp, err := httpClient.Do(req) + require.Nil(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode) + + jsonParser := json.NewDecoder(resp.Body) + err = jsonParser.Decode(&response) + require.Nil(t, err) +} diff --git a/integrationTests/mock/intermediateTransactionHandlerMock.go b/integrationTests/mock/intermediateTransactionHandlerMock.go index 77e60169ee7..f86d69ff63e 100644 --- a/integrationTests/mock/intermediateTransactionHandlerMock.go +++ b/integrationTests/mock/intermediateTransactionHandlerMock.go @@ -7,7 +7,7 @@ import ( // IntermediateTransactionHandlerMock - type IntermediateTransactionHandlerMock struct { - AddIntermediateTransactionsCalled func(txs []data.TransactionHandler) error + AddIntermediateTransactionsCalled func(txs []data.TransactionHandler, key []byte) error GetNumOfCrossInterMbsAndTxsCalled func() (int, int) CreateAllInterMiniBlocksCalled func() []*block.MiniBlock VerifyInterMiniBlocksCalled func(body *block.Body) error @@ -16,7 +16,7 @@ type IntermediateTransactionHandlerMock struct { CreateMarshalledDataCalled func(txHashes [][]byte) ([][]byte, error) GetAllCurrentFinishedTxsCalled func() map[string]data.TransactionHandler RemoveProcessedResultsCalled func(key []byte) [][]byte - InitProcessedResultsCalled func(key []byte) + InitProcessedResultsCalled func(key []byte, parentKey []byte) intermediateTransactions []data.TransactionHandler } @@ -29,9 +29,9 @@ func (ith *IntermediateTransactionHandlerMock) RemoveProcessedResults(key []byte } // InitProcessedResults - -func (ith *IntermediateTransactionHandlerMock) InitProcessedResults(key []byte) { +func (ith *IntermediateTransactionHandlerMock) InitProcessedResults(key []byte, parentKey []byte) { if ith.InitProcessedResultsCalled != nil { - ith.InitProcessedResultsCalled(key) + ith.InitProcessedResultsCalled(key, parentKey) } } @@ -57,12 +57,12 @@ func (ith *IntermediateTransactionHandlerMock) CreateMarshalledData(txHashes [][ } // AddIntermediateTransactions - -func (ith *IntermediateTransactionHandlerMock) AddIntermediateTransactions(txs []data.TransactionHandler) error { +func (ith *IntermediateTransactionHandlerMock) AddIntermediateTransactions(txs []data.TransactionHandler, key []byte) error { if ith.AddIntermediateTransactionsCalled == nil { ith.intermediateTransactions = append(ith.intermediateTransactions, txs...) return nil } - return ith.AddIntermediateTransactionsCalled(txs) + return ith.AddIntermediateTransactionsCalled(txs, key) } // GetIntermediateTransactions - diff --git a/integrationTests/mock/processComponentsStub.go b/integrationTests/mock/processComponentsStub.go index 11d4f4ce69d..04dad00a52c 100644 --- a/integrationTests/mock/processComponentsStub.go +++ b/integrationTests/mock/processComponentsStub.go @@ -61,6 +61,7 @@ type ProcessComponentsStub struct { ESDTDataStorageHandlerForAPIInternal vmcommon.ESDTNFTStorageHandler SentSignaturesTrackerInternal process.SentSignaturesTracker EpochSystemSCProcessorInternal process.EpochStartSystemSCProcessor + RelayedTxV3ProcessorField process.RelayedTxV3Processor } // Create - @@ -302,6 +303,11 @@ func (pcs *ProcessComponentsStub) EpochSystemSCProcessor() process.EpochStartSys return pcs.EpochSystemSCProcessorInternal } +// RelayedTxV3Processor - +func (pcs *ProcessComponentsStub) RelayedTxV3Processor() process.RelayedTxV3Processor { + return pcs.RelayedTxV3ProcessorField +} + // IsInterfaceNil - func (pcs *ProcessComponentsStub) IsInterfaceNil() bool { return pcs == nil diff --git a/integrationTests/mock/transactionCoordinatorMock.go b/integrationTests/mock/transactionCoordinatorMock.go index d3671b1d77b..c002c52cc0f 100644 --- a/integrationTests/mock/transactionCoordinatorMock.go +++ b/integrationTests/mock/transactionCoordinatorMock.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" + "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/processedMb" ) @@ -29,7 +30,7 @@ type TransactionCoordinatorMock struct { VerifyCreatedBlockTransactionsCalled func(hdr data.HeaderHandler, body *block.Body) error CreatePostProcessMiniBlocksCalled func() block.MiniBlockSlice VerifyCreatedMiniBlocksCalled func(hdr data.HeaderHandler, body *block.Body) error - AddIntermediateTransactionsCalled func(mapSCRs map[block.Type][]data.TransactionHandler) error + AddIntermediateTransactionsCalled func(mapSCRs map[block.Type][]data.TransactionHandler, key []byte) error GetAllIntermediateTxsCalled func() map[block.Type]map[string]data.TransactionHandler AddTxsFromMiniBlocksCalled func(miniBlocks block.MiniBlockSlice) AddTransactionsCalled func(txHandlers []data.TransactionHandler, blockType block.Type) @@ -213,12 +214,12 @@ func (tcm *TransactionCoordinatorMock) VerifyCreatedMiniBlocks(hdr data.HeaderHa } // AddIntermediateTransactions - -func (tcm *TransactionCoordinatorMock) AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler) error { +func (tcm *TransactionCoordinatorMock) AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler, key []byte) error { if tcm.AddIntermediateTransactionsCalled == nil { return nil } - return tcm.AddIntermediateTransactionsCalled(mapSCRs) + return tcm.AddIntermediateTransactionsCalled(mapSCRs, key) } // GetAllIntermediateTxs - diff --git a/integrationTests/multiShard/relayedTx/common.go b/integrationTests/multiShard/relayedTx/common.go index 33a5cedcc53..c2bc8e5995c 100644 --- a/integrationTests/multiShard/relayedTx/common.go +++ b/integrationTests/multiShard/relayedTx/common.go @@ -8,21 +8,37 @@ 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/transaction" + "github.com/multiversx/mx-chain-go/config" "github.com/multiversx/mx-chain-go/integrationTests" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/state" ) // CreateGeneralSetupForRelayTxTest will create the general setup for relayed transactions -func CreateGeneralSetupForRelayTxTest() ([]*integrationTests.TestProcessorNode, []int, []*integrationTests.TestWalletAccount, *integrationTests.TestWalletAccount) { +func CreateGeneralSetupForRelayTxTest(relayedV3Test bool) ([]*integrationTests.TestProcessorNode, []int, []*integrationTests.TestWalletAccount, *integrationTests.TestWalletAccount) { + initialVal := big.NewInt(10000000000) + epochsConfig := integrationTests.GetDefaultEnableEpochsConfig() + if !relayedV3Test { + epochsConfig.RelayedTransactionsV3EnableEpoch = integrationTests.UnreachableEpoch + epochsConfig.FixRelayedBaseCostEnableEpoch = integrationTests.UnreachableEpoch + } + nodes, idxProposers := createAndMintNodes(initialVal, epochsConfig) + + players, relayerAccount := createAndMintPlayers(relayedV3Test, nodes, initialVal) + + return nodes, idxProposers, players, relayerAccount +} + +func createAndMintNodes(initialVal *big.Int, enableEpochsConfig *config.EnableEpochs) ([]*integrationTests.TestProcessorNode, []int) { numOfShards := 2 nodesPerShard := 2 numMetachainNodes := 1 - nodes := integrationTests.CreateNodes( + nodes := integrationTests.CreateNodesWithEnableEpochsConfig( numOfShards, nodesPerShard, numMetachainNodes, + enableEpochsConfig, ) idxProposers := make([]int, numOfShards+1) @@ -33,21 +49,32 @@ func CreateGeneralSetupForRelayTxTest() ([]*integrationTests.TestProcessorNode, integrationTests.DisplayAndStartNodes(nodes) - initialVal := big.NewInt(10000000000) integrationTests.MintAllNodes(nodes, initialVal) + return nodes, idxProposers +} + +func createAndMintPlayers( + intraShard bool, + nodes []*integrationTests.TestProcessorNode, + initialVal *big.Int, +) ([]*integrationTests.TestWalletAccount, *integrationTests.TestWalletAccount) { + relayerShard := uint32(0) numPlayers := 5 numShards := nodes[0].ShardCoordinator.NumberOfShards() players := make([]*integrationTests.TestWalletAccount, numPlayers) for i := 0; i < numPlayers; i++ { shardId := uint32(i) % numShards + if intraShard { + shardId = relayerShard + } players[i] = integrationTests.CreateTestWalletAccount(nodes[0].ShardCoordinator, shardId) } - relayerAccount := integrationTests.CreateTestWalletAccount(nodes[0].ShardCoordinator, 0) + relayerAccount := integrationTests.CreateTestWalletAccount(nodes[0].ShardCoordinator, relayerShard) integrationTests.MintAllPlayers(nodes, []*integrationTests.TestWalletAccount{relayerAccount}, initialVal) - return nodes, idxProposers, players, relayerAccount + return players, relayerAccount } // CreateAndSendRelayedAndUserTx will create and send a relayed user transaction @@ -59,10 +86,10 @@ func CreateAndSendRelayedAndUserTx( value *big.Int, gasLimit uint64, txData []byte, -) *transaction.Transaction { +) (*transaction.Transaction, *transaction.Transaction) { txDispatcherNode := getNodeWithinSameShardAsPlayer(nodes, relayer.Address) - userTx := createUserTx(player, rcvAddr, value, gasLimit, txData) + userTx := createUserTx(player, rcvAddr, value, gasLimit, txData, nil) relayedTx := createRelayedTx(txDispatcherNode.EconomicsData, relayer, userTx) _, err := txDispatcherNode.SendTransaction(relayedTx) @@ -70,7 +97,7 @@ func CreateAndSendRelayedAndUserTx( fmt.Println(err.Error()) } - return relayedTx + return relayedTx, userTx } // CreateAndSendRelayedAndUserTxV2 will create and send a relayed user transaction for relayed v2 @@ -82,10 +109,10 @@ func CreateAndSendRelayedAndUserTxV2( value *big.Int, gasLimit uint64, txData []byte, -) *transaction.Transaction { +) (*transaction.Transaction, *transaction.Transaction) { txDispatcherNode := getNodeWithinSameShardAsPlayer(nodes, relayer.Address) - userTx := createUserTx(player, rcvAddr, value, 0, txData) + userTx := createUserTx(player, rcvAddr, value, 0, txData, nil) relayedTx := createRelayedTxV2(txDispatcherNode.EconomicsData, relayer, userTx, gasLimit) _, err := txDispatcherNode.SendTransaction(relayedTx) @@ -93,7 +120,30 @@ func CreateAndSendRelayedAndUserTxV2( fmt.Println(err.Error()) } - return relayedTx + return relayedTx, userTx +} + +// CreateAndSendRelayedAndUserTxV3 will create and send a relayed user transaction for relayed 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) + + userTx := createUserTx(player, rcvAddr, value, gasLimit, txData, relayer.Address) + relayedTx := createRelayedTxV3(txDispatcherNode.EconomicsData, relayer, userTx) + + _, err := txDispatcherNode.SendTransaction(relayedTx) + if err != nil { + fmt.Println(err.Error()) + } + + return relayedTx, userTx } func createUserTx( @@ -102,21 +152,24 @@ func createUserTx( value *big.Int, gasLimit uint64, txData []byte, + relayerAddress []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, - Data: txData, - ChainID: integrationTests.ChainID, - Version: integrationTests.MinTransactionVersion, + Nonce: player.Nonce, + Value: big.NewInt(0).Set(value), + RcvAddr: rcvAddr, + SndAddr: player.Address, + GasPrice: integrationTests.MinTxGasPrice, + GasLimit: gasLimit, + Data: txData, + ChainID: integrationTests.ChainID, + Version: integrationTests.MinTransactionVersion, + RelayerAddr: relayerAddress, } txBuff, _ := tx.GetDataForSigning(integrationTests.TestAddressPubkeyConverter, integrationTests.TestTxSignMarshalizer, integrationTests.TestTxSignHasher) tx.Signature, _ = player.SingleSigner.Sign(player.SkTxSign, txBuff) player.Nonce++ + player.Balance.Sub(player.Balance, value) return tx } @@ -130,7 +183,7 @@ func createRelayedTx( txData := core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshaled) tx := &transaction.Transaction{ Nonce: relayer.Nonce, - Value: big.NewInt(0).Set(userTx.Value), + Value: big.NewInt(0), RcvAddr: userTx.SndAddr, SndAddr: relayer.Address, GasPrice: integrationTests.MinTxGasPrice, @@ -144,9 +197,11 @@ func createRelayedTx( txBuff, _ := tx.GetDataForSigning(integrationTests.TestAddressPubkeyConverter, integrationTests.TestTxSignMarshalizer, integrationTests.TestTxSignHasher) tx.Signature, _ = relayer.SingleSigner.Sign(relayer.SkTxSign, txBuff) relayer.Nonce++ + + relayer.Balance.Sub(relayer.Balance, tx.Value) + txFee := economicsFee.ComputeTxFee(tx) relayer.Balance.Sub(relayer.Balance, txFee) - relayer.Balance.Sub(relayer.Balance, tx.Value) return tx } @@ -173,10 +228,43 @@ func createRelayedTxV2( txBuff, _ := tx.GetDataForSigning(integrationTests.TestAddressPubkeyConverter, integrationTests.TestTxSignMarshalizer, integrationTests.TestTxSignHasher) tx.Signature, _ = relayer.SingleSigner.Sign(relayer.SkTxSign, txBuff) relayer.Nonce++ + + relayer.Balance.Sub(relayer.Balance, tx.Value) + txFee := economicsFee.ComputeTxFee(tx) relayer.Balance.Sub(relayer.Balance, txFee) + + return tx +} + +func createRelayedTxV3( + economicsFee process.FeeHandler, + relayer *integrationTests.TestWalletAccount, + userTx *transaction.Transaction, +) *transaction.Transaction { + tx := &transaction.Transaction{ + Nonce: relayer.Nonce, + Value: big.NewInt(0), + RcvAddr: relayer.Address, + SndAddr: relayer.Address, + GasPrice: integrationTests.MinTxGasPrice, + Data: []byte(""), + ChainID: userTx.ChainID, + Version: userTx.Version, + InnerTransactions: []*transaction.Transaction{userTx}, + } + gasLimit := economicsFee.ComputeGasLimit(tx) + tx.GasLimit = userTx.GasLimit + gasLimit + + txBuff, _ := tx.GetDataForSigning(integrationTests.TestAddressPubkeyConverter, integrationTests.TestTxSignMarshalizer, integrationTests.TestTxSignHasher) + tx.Signature, _ = relayer.SingleSigner.Sign(relayer.SkTxSign, txBuff) + relayer.Nonce++ + relayer.Balance.Sub(relayer.Balance, tx.Value) + txFee := economicsFee.ComputeTxFee(tx) + relayer.Balance.Sub(relayer.Balance, txFee) + return tx } @@ -190,7 +278,7 @@ func createAndSendSimpleTransaction( ) { txDispatcherNode := getNodeWithinSameShardAsPlayer(nodes, player.Address) - userTx := createUserTx(player, rcvAddr, value, gasLimit, txData) + userTx := createUserTx(player, rcvAddr, value, gasLimit, txData, nil) _, err := txDispatcherNode.SendTransaction(userTx) if err != nil { fmt.Println(err.Error()) diff --git a/integrationTests/multiShard/relayedTx/edgecases/edgecases_test.go b/integrationTests/multiShard/relayedTx/edgecases/edgecases_test.go index 246a81fbe15..72e7bafda2e 100644 --- a/integrationTests/multiShard/relayedTx/edgecases/edgecases_test.go +++ b/integrationTests/multiShard/relayedTx/edgecases/edgecases_test.go @@ -16,7 +16,7 @@ func TestRelayedTransactionInMultiShardEnvironmentWithNormalTxButWrongNonceShoul t.Skip("this is not a short test") } - nodes, idxProposers, players, relayer := relayedTx.CreateGeneralSetupForRelayTxTest() + nodes, idxProposers, players, relayer := relayedTx.CreateGeneralSetupForRelayTxTest(false) defer func() { for _, n := range nodes { n.Close() @@ -32,18 +32,12 @@ func TestRelayedTransactionInMultiShardEnvironmentWithNormalTxButWrongNonceShoul receiverAddress1 := []byte("12345678901234567890123456789012") receiverAddress2 := []byte("12345678901234567890123456789011") - totalFees := big.NewInt(0) - relayerInitialValue := big.NewInt(0).Set(relayer.Balance) nrRoundsToTest := int64(5) for i := int64(0); i < nrRoundsToTest; i++ { for _, player := range players { player.Nonce += 1 - relayerTx := relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress1, sendValue, integrationTests.MinTxGasLimit, []byte("")) - totalFee := nodes[0].EconomicsData.ComputeTxFee(relayerTx) - totalFees.Add(totalFees, totalFee) - relayerTx = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress2, sendValue, integrationTests.MinTxGasLimit, []byte("")) - totalFee = nodes[0].EconomicsData.ComputeTxFee(relayerTx) - totalFees.Add(totalFees, totalFee) + _, _ = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress1, sendValue, integrationTests.MinTxGasLimit, []byte("")) + _, _ = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress2, sendValue, integrationTests.MinTxGasLimit, []byte("")) } round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) @@ -71,9 +65,8 @@ func TestRelayedTransactionInMultiShardEnvironmentWithNormalTxButWrongNonceShoul assert.Equal(t, uint64(0), account.GetNonce()) } - expectedBalance := big.NewInt(0).Sub(relayerInitialValue, totalFees) relayerAccount := relayedTx.GetUserAccount(nodes, relayer.Address) - assert.True(t, relayerAccount.GetBalance().Cmp(expectedBalance) == 0) + assert.True(t, relayerAccount.GetBalance().Cmp(relayer.Balance) == 0) } func TestRelayedTransactionInMultiShardEnvironmentWithNormalTxButWithTooMuchGas(t *testing.T) { @@ -81,7 +74,7 @@ func TestRelayedTransactionInMultiShardEnvironmentWithNormalTxButWithTooMuchGas( t.Skip("this is not a short test") } - nodes, idxProposers, players, relayer := relayedTx.CreateGeneralSetupForRelayTxTest() + nodes, idxProposers, players, relayer := relayedTx.CreateGeneralSetupForRelayTxTest(false) defer func() { for _, n := range nodes { n.Close() @@ -100,10 +93,16 @@ func TestRelayedTransactionInMultiShardEnvironmentWithNormalTxButWithTooMuchGas( additionalGasLimit := uint64(100000) tooMuchGasLimit := integrationTests.MinTxGasLimit + additionalGasLimit nrRoundsToTest := int64(5) + + txsSentEachRound := big.NewInt(2) // 2 relayed txs each round + txsSentPerPlayer := big.NewInt(0).Mul(txsSentEachRound, big.NewInt(nrRoundsToTest)) + initialPlayerFunds := big.NewInt(0).Mul(sendValue, txsSentPerPlayer) + integrationTests.MintAllPlayers(nodes, players, initialPlayerFunds) + for i := int64(0); i < nrRoundsToTest; i++ { for _, player := range players { - _ = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress1, sendValue, tooMuchGasLimit, []byte("")) - _ = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress2, sendValue, tooMuchGasLimit, []byte("")) + _, _ = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress1, sendValue, tooMuchGasLimit, []byte("")) + _, _ = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress2, sendValue, tooMuchGasLimit, []byte("")) } round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) @@ -124,8 +123,8 @@ func TestRelayedTransactionInMultiShardEnvironmentWithNormalTxButWithTooMuchGas( finalBalance := big.NewInt(0).Mul(big.NewInt(int64(len(players))), big.NewInt(nrRoundsToTest)) finalBalance.Mul(finalBalance, sendValue) - assert.Equal(t, receiver1.GetBalance().Cmp(finalBalance), 0) - assert.Equal(t, receiver2.GetBalance().Cmp(finalBalance), 0) + assert.Equal(t, 0, receiver1.GetBalance().Cmp(finalBalance)) + assert.Equal(t, 0, receiver2.GetBalance().Cmp(finalBalance)) players = append(players, relayer) checkPlayerBalancesWithPenalization(t, nodes, players) @@ -139,7 +138,7 @@ func checkPlayerBalancesWithPenalization( for i := 0; i < len(players); i++ { userAcc := relayedTx.GetUserAccount(nodes, players[i].Address) - assert.Equal(t, userAcc.GetBalance().Cmp(players[i].Balance), 0) + assert.Equal(t, 0, userAcc.GetBalance().Cmp(players[i].Balance)) assert.Equal(t, userAcc.GetNonce(), players[i].Nonce) } } diff --git a/integrationTests/multiShard/relayedTx/relayedTxV2_test.go b/integrationTests/multiShard/relayedTx/relayedTxV2_test.go deleted file mode 100644 index 2795646c359..00000000000 --- a/integrationTests/multiShard/relayedTx/relayedTxV2_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package relayedTx - -import ( - "encoding/hex" - "math/big" - "testing" - "time" - - "github.com/multiversx/mx-chain-core-go/data/transaction" - "github.com/multiversx/mx-chain-go/integrationTests" - "github.com/multiversx/mx-chain-go/integrationTests/vm/wasm" - vmFactory "github.com/multiversx/mx-chain-go/process/factory" - "github.com/stretchr/testify/assert" -) - -func TestRelayedTransactionV2InMultiShardEnvironmentWithSmartContractTX(t *testing.T) { - if testing.Short() { - t.Skip("this is not a short test") - } - - nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest() - defer func() { - for _, n := range nodes { - n.Close() - } - }() - - sendValue := big.NewInt(5) - round := uint64(0) - nonce := uint64(0) - round = integrationTests.IncrementAndPrintRound(round) - nonce++ - - receiverAddress1 := []byte("12345678901234567890123456789012") - receiverAddress2 := []byte("12345678901234567890123456789011") - - ownerNode := nodes[0] - initialSupply := "00" + hex.EncodeToString(big.NewInt(100000000000).Bytes()) - scCode := wasm.GetSCCode("../../vm/wasm/testdata/erc20-c-03/wrc20_wasm.wasm") - scAddress, _ := ownerNode.BlockchainHook.NewAddress(ownerNode.OwnAccount.Address, ownerNode.OwnAccount.Nonce, vmFactory.WasmVirtualMachine) - - integrationTests.CreateAndSendTransactionWithGasLimit( - nodes[0], - big.NewInt(0), - 2000000, - make([]byte, 32), - []byte(wasm.CreateDeployTxData(scCode)+"@"+initialSupply), - integrationTests.ChainID, - integrationTests.MinTransactionVersion, - ) - - transferTokenVMGas := uint64(720000) - transferTokenBaseGas := ownerNode.EconomicsData.ComputeGasLimit(&transaction.Transaction{Data: []byte("transferToken@" + hex.EncodeToString(receiverAddress1) + "@00" + hex.EncodeToString(sendValue.Bytes()))}) - transferTokenFullGas := transferTokenBaseGas + transferTokenVMGas - - initialTokenSupply := big.NewInt(1000000000) - initialPlusForGas := uint64(100000) - for _, player := range players { - integrationTests.CreateAndSendTransactionWithGasLimit( - ownerNode, - big.NewInt(0), - transferTokenFullGas+initialPlusForGas, - scAddress, - []byte("transferToken@"+hex.EncodeToString(player.Address)+"@00"+hex.EncodeToString(initialTokenSupply.Bytes())), - integrationTests.ChainID, - integrationTests.MinTransactionVersion, - ) - } - - roundToPropagateMultiShard := int64(20) - for i := int64(0); i <= roundToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - } - - nrRoundsToTest := int64(5) - for i := int64(0); i < nrRoundsToTest; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - - for _, player := range players { - _ = CreateAndSendRelayedAndUserTxV2(nodes, relayer, player, scAddress, big.NewInt(0), - transferTokenFullGas, []byte("transferToken@"+hex.EncodeToString(receiverAddress1)+"@00"+hex.EncodeToString(sendValue.Bytes()))) - _ = CreateAndSendRelayedAndUserTxV2(nodes, relayer, player, scAddress, big.NewInt(0), - transferTokenFullGas, []byte("transferToken@"+hex.EncodeToString(receiverAddress2)+"@00"+hex.EncodeToString(sendValue.Bytes()))) - } - - time.Sleep(integrationTests.StepDelay) - } - - for i := int64(0); i <= roundToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - } - - time.Sleep(time.Second) - - finalBalance := big.NewInt(0).Mul(big.NewInt(int64(len(players))), big.NewInt(nrRoundsToTest)) - finalBalance.Mul(finalBalance, sendValue) - - checkSCBalance(t, ownerNode, scAddress, receiverAddress1, finalBalance) - checkSCBalance(t, ownerNode, scAddress, receiverAddress1, finalBalance) - - checkPlayerBalances(t, nodes, players) - - userAcc := GetUserAccount(nodes, relayer.Address) - assert.Equal(t, 1, userAcc.GetBalance().Cmp(relayer.Balance)) -} diff --git a/integrationTests/multiShard/relayedTx/relayedTx_test.go b/integrationTests/multiShard/relayedTx/relayedTx_test.go index 43f713d5d09..d9ea772d7ba 100644 --- a/integrationTests/multiShard/relayedTx/relayedTx_test.go +++ b/integrationTests/multiShard/relayedTx/relayedTx_test.go @@ -21,332 +21,395 @@ import ( "github.com/stretchr/testify/require" ) +type createAndSendRelayedAndUserTxFuncType = func( + nodes []*integrationTests.TestProcessorNode, + relayer *integrationTests.TestWalletAccount, + player *integrationTests.TestWalletAccount, + rcvAddr []byte, + value *big.Int, + gasLimit uint64, + txData []byte, +) (*transaction.Transaction, *transaction.Transaction) + func TestRelayedTransactionInMultiShardEnvironmentWithNormalTx(t *testing.T) { - if testing.Short() { - t.Skip("this is not a short test") - } + t.Run("relayed v1", testRelayedTransactionInMultiShardEnvironmentWithNormalTx(CreateAndSendRelayedAndUserTx, false)) + t.Run("relayed v3", testRelayedTransactionInMultiShardEnvironmentWithNormalTx(CreateAndSendRelayedAndUserTxV3, true)) +} - nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest() - defer func() { - for _, n := range nodes { - n.Close() - } - }() +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)) +} - sendValue := big.NewInt(5) - round := uint64(0) - nonce := uint64(0) - round = integrationTests.IncrementAndPrintRound(round) - nonce++ +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)) +} - receiverAddress1 := []byte("12345678901234567890123456789012") - receiverAddress2 := []byte("12345678901234567890123456789011") +func TestRelayedTransactionInMultiShardEnvironmentWithAttestationContract(t *testing.T) { + t.Run("relayed v1", testRelayedTransactionInMultiShardEnvironmentWithAttestationContract(CreateAndSendRelayedAndUserTx, false)) + t.Run("relayed v3", testRelayedTransactionInMultiShardEnvironmentWithAttestationContract(CreateAndSendRelayedAndUserTxV3, true)) +} - nrRoundsToTest := int64(5) - for i := int64(0); i < nrRoundsToTest; i++ { - for _, player := range players { - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress1, sendValue, integrationTests.MinTxGasLimit, []byte("")) - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress2, sendValue, integrationTests.MinTxGasLimit, []byte("")) +func testRelayedTransactionInMultiShardEnvironmentWithNormalTx( + createAndSendRelayedAndUserTxFunc createAndSendRelayedAndUserTxFuncType, + relayedV3Test bool, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") } - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest(relayedV3Test) + defer func() { + for _, n := range nodes { + n.Close() + } + }() - time.Sleep(integrationTests.StepDelay) - } + sendValue := big.NewInt(5) + round := uint64(0) + nonce := uint64(0) + round = integrationTests.IncrementAndPrintRound(round) + nonce++ - roundToPropagateMultiShard := int64(20) - for i := int64(0); i <= roundToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - } + receiverAddress1 := []byte("12345678901234567890123456789012") + receiverAddress2 := []byte("12345678901234567890123456789011") - time.Sleep(time.Second) - receiver1 := GetUserAccount(nodes, receiverAddress1) - receiver2 := GetUserAccount(nodes, receiverAddress2) + nrRoundsToTest := int64(5) - finalBalance := big.NewInt(0).Mul(big.NewInt(int64(len(players))), big.NewInt(nrRoundsToTest)) - finalBalance.Mul(finalBalance, sendValue) - assert.Equal(t, receiver1.GetBalance().Cmp(finalBalance), 0) - assert.Equal(t, receiver2.GetBalance().Cmp(finalBalance), 0) + txsSentEachRound := big.NewInt(2) // 2 relayed txs each round + txsSentPerPlayer := big.NewInt(0).Mul(txsSentEachRound, big.NewInt(nrRoundsToTest)) + initialPlayerFunds := big.NewInt(0).Mul(sendValue, txsSentPerPlayer) + integrationTests.MintAllPlayers(nodes, players, initialPlayerFunds) - players = append(players, relayer) - checkPlayerBalances(t, nodes, players) -} + for i := int64(0); i < nrRoundsToTest; i++ { + for _, player := range players { + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, receiverAddress1, sendValue, integrationTests.MinTxGasLimit, []byte("")) + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, receiverAddress2, sendValue, integrationTests.MinTxGasLimit, []byte("")) + } -func TestRelayedTransactionInMultiShardEnvironmentWithSmartContractTX(t *testing.T) { - if testing.Short() { - t.Skip("this is not a short test") + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + + time.Sleep(integrationTests.StepDelay) + } + + roundToPropagateMultiShard := int64(20) + for i := int64(0); i <= roundToPropagateMultiShard; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + } + + time.Sleep(time.Second) + receiver1 := GetUserAccount(nodes, receiverAddress1) + receiver2 := GetUserAccount(nodes, receiverAddress2) + + finalBalance := big.NewInt(0).Mul(big.NewInt(int64(len(players))), big.NewInt(nrRoundsToTest)) + finalBalance.Mul(finalBalance, sendValue) + assert.Equal(t, receiver1.GetBalance().Cmp(finalBalance), 0) + assert.Equal(t, receiver2.GetBalance().Cmp(finalBalance), 0) + + players = append(players, relayer) + checkPlayerBalances(t, nodes, players) } +} - nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest() - defer func() { - for _, n := range nodes { - n.Close() +func testRelayedTransactionInMultiShardEnvironmentWithSmartContractTX( + createAndSendRelayedAndUserTxFunc createAndSendRelayedAndUserTxFuncType, + relayedV3Test bool, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") } - }() - - sendValue := big.NewInt(5) - round := uint64(0) - nonce := uint64(0) - round = integrationTests.IncrementAndPrintRound(round) - nonce++ - - receiverAddress1 := []byte("12345678901234567890123456789012") - receiverAddress2 := []byte("12345678901234567890123456789011") - - ownerNode := nodes[0] - initialSupply := "00" + hex.EncodeToString(big.NewInt(100000000000).Bytes()) - scCode := wasm.GetSCCode("../../vm/wasm/testdata/erc20-c-03/wrc20_wasm.wasm") - scAddress, _ := ownerNode.BlockchainHook.NewAddress(ownerNode.OwnAccount.Address, ownerNode.OwnAccount.Nonce, vmFactory.WasmVirtualMachine) - - integrationTests.CreateAndSendTransactionWithGasLimit( - nodes[0], - big.NewInt(0), - 200000, - make([]byte, 32), - []byte(wasm.CreateDeployTxData(scCode)+"@"+initialSupply), - integrationTests.ChainID, - integrationTests.MinTransactionVersion, - ) - - transferTokenVMGas := uint64(720000) - transferTokenBaseGas := ownerNode.EconomicsData.ComputeGasLimit(&transaction.Transaction{Data: []byte("transferToken@" + hex.EncodeToString(receiverAddress1) + "@00" + hex.EncodeToString(sendValue.Bytes()))}) - transferTokenFullGas := transferTokenBaseGas + transferTokenVMGas - - initialTokenSupply := big.NewInt(1000000000) - initialPlusForGas := uint64(100000) - for _, player := range players { + + nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest(relayedV3Test) + defer func() { + for _, n := range nodes { + n.Close() + } + }() + + sendValue := big.NewInt(5) + round := uint64(0) + nonce := uint64(0) + round = integrationTests.IncrementAndPrintRound(round) + nonce++ + + receiverAddress1 := []byte("12345678901234567890123456789012") + receiverAddress2 := []byte("12345678901234567890123456789011") + + ownerNode := nodes[0] + initialSupply := "00" + hex.EncodeToString(big.NewInt(100000000000).Bytes()) + scCode := wasm.GetSCCode("../../vm/wasm/testdata/erc20-c-03/wrc20_wasm.wasm") + scAddress, _ := ownerNode.BlockchainHook.NewAddress(ownerNode.OwnAccount.Address, ownerNode.OwnAccount.Nonce, vmFactory.WasmVirtualMachine) + integrationTests.CreateAndSendTransactionWithGasLimit( - ownerNode, + nodes[0], big.NewInt(0), - transferTokenFullGas+initialPlusForGas, - scAddress, - []byte("transferToken@"+hex.EncodeToString(player.Address)+"@00"+hex.EncodeToString(initialTokenSupply.Bytes())), + 200000, + make([]byte, 32), + []byte(wasm.CreateDeployTxData(scCode)+"@"+initialSupply), integrationTests.ChainID, integrationTests.MinTransactionVersion, ) - } - time.Sleep(time.Second) - nrRoundsToTest := int64(5) - for i := int64(0); i < nrRoundsToTest; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + transferTokenVMGas := uint64(720000) + transferTokenBaseGas := ownerNode.EconomicsData.ComputeGasLimit(&transaction.Transaction{Data: []byte("transferToken@" + hex.EncodeToString(receiverAddress1) + "@00" + hex.EncodeToString(sendValue.Bytes()))}) + transferTokenFullGas := transferTokenBaseGas + transferTokenVMGas + initialTokenSupply := big.NewInt(1000000000) + initialPlusForGas := uint64(100000) for _, player := range players { - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, scAddress, big.NewInt(0), - transferTokenFullGas, []byte("transferToken@"+hex.EncodeToString(receiverAddress1)+"@00"+hex.EncodeToString(sendValue.Bytes()))) - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, scAddress, big.NewInt(0), - transferTokenFullGas, []byte("transferToken@"+hex.EncodeToString(receiverAddress2)+"@00"+hex.EncodeToString(sendValue.Bytes()))) + integrationTests.CreateAndSendTransactionWithGasLimit( + ownerNode, + big.NewInt(0), + transferTokenFullGas+initialPlusForGas, + scAddress, + []byte("transferToken@"+hex.EncodeToString(player.Address)+"@00"+hex.EncodeToString(initialTokenSupply.Bytes())), + integrationTests.ChainID, + integrationTests.MinTransactionVersion, + ) } + time.Sleep(time.Second) - time.Sleep(integrationTests.StepDelay) - } - time.Sleep(time.Second) + nrRoundsToTest := int64(5) + for i := int64(0); i < nrRoundsToTest; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - roundToPropagateMultiShard := int64(25) - for i := int64(0); i <= roundToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - } + for _, player := range players { + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, scAddress, big.NewInt(0), + transferTokenFullGas, []byte("transferToken@"+hex.EncodeToString(receiverAddress1)+"@00"+hex.EncodeToString(sendValue.Bytes()))) + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, scAddress, big.NewInt(0), + transferTokenFullGas, []byte("transferToken@"+hex.EncodeToString(receiverAddress2)+"@00"+hex.EncodeToString(sendValue.Bytes()))) + } + + time.Sleep(integrationTests.StepDelay) + } + time.Sleep(time.Second) - time.Sleep(time.Second) + roundToPropagateMultiShard := int64(25) + for i := int64(0); i <= roundToPropagateMultiShard; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + } - finalBalance := big.NewInt(0).Mul(big.NewInt(int64(len(players))), big.NewInt(nrRoundsToTest)) - finalBalance.Mul(finalBalance, sendValue) + time.Sleep(time.Second) - checkSCBalance(t, ownerNode, scAddress, receiverAddress1, finalBalance) - checkSCBalance(t, ownerNode, scAddress, receiverAddress1, finalBalance) + finalBalance := big.NewInt(0).Mul(big.NewInt(int64(len(players))), big.NewInt(nrRoundsToTest)) + finalBalance.Mul(finalBalance, sendValue) - checkPlayerBalances(t, nodes, players) + checkSCBalance(t, ownerNode, scAddress, receiverAddress1, finalBalance) + checkSCBalance(t, ownerNode, scAddress, receiverAddress1, finalBalance) - userAcc := GetUserAccount(nodes, relayer.Address) - assert.Equal(t, userAcc.GetBalance().Cmp(relayer.Balance), 1) -} + checkPlayerBalances(t, nodes, players) -func TestRelayedTransactionInMultiShardEnvironmentWithESDTTX(t *testing.T) { - if testing.Short() { - t.Skip("this is not a short test") + userAcc := GetUserAccount(nodes, relayer.Address) + assert.Equal(t, 1, userAcc.GetBalance().Cmp(relayer.Balance)) } +} - nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest() - defer func() { - for _, n := range nodes { - n.Close() +func testRelayedTransactionInMultiShardEnvironmentWithESDTTX( + createAndSendRelayedAndUserTxFunc createAndSendRelayedAndUserTxFuncType, + relayedV3Test bool, +) func(t *testing.T) { + return func(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") } - }() - - sendValue := big.NewInt(5) - round := uint64(0) - nonce := uint64(0) - round = integrationTests.IncrementAndPrintRound(round) - nonce++ - - receiverAddress1 := []byte("12345678901234567890123456789012") - receiverAddress2 := []byte("12345678901234567890123456789011") - - // ------- send token issue - issuePrice := big.NewInt(1000) - initalSupply := big.NewInt(10000000000) - tokenIssuer := nodes[0] - txData := "issue" + - "@" + hex.EncodeToString([]byte("robertWhyNot")) + - "@" + hex.EncodeToString([]byte("RBT")) + - "@" + hex.EncodeToString(initalSupply.Bytes()) + - "@" + hex.EncodeToString([]byte{6}) - integrationTests.CreateAndSendTransaction(tokenIssuer, nodes, issuePrice, vm.ESDTSCAddress, txData, core.MinMetaTxExtraGasCost) - - time.Sleep(time.Second) - nrRoundsToPropagateMultiShard := int64(10) - for i := int64(0); i < nrRoundsToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - time.Sleep(integrationTests.StepDelay) - } - time.Sleep(time.Second) - tokenIdenfitifer := string(integrationTests.GetTokenIdentifier(nodes, []byte("RBT"))) - CheckAddressHasTokens(t, tokenIssuer.OwnAccount.Address, nodes, tokenIdenfitifer, initalSupply) + nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest(relayedV3Test) + defer func() { + for _, n := range nodes { + n.Close() + } + }() + + sendValue := big.NewInt(5) + round := uint64(0) + nonce := uint64(0) + round = integrationTests.IncrementAndPrintRound(round) + nonce++ + + receiverAddress1 := []byte("12345678901234567890123456789012") + receiverAddress2 := []byte("12345678901234567890123456789011") + + // ------- send token issue + issuePrice := big.NewInt(1000) + initalSupply := big.NewInt(10000000000) + tokenIssuer := nodes[0] + txData := "issue" + + "@" + hex.EncodeToString([]byte("robertWhyNot")) + + "@" + hex.EncodeToString([]byte("RBT")) + + "@" + hex.EncodeToString(initalSupply.Bytes()) + + "@" + hex.EncodeToString([]byte{6}) + integrationTests.CreateAndSendTransaction(tokenIssuer, nodes, issuePrice, vm.ESDTSCAddress, txData, core.MinMetaTxExtraGasCost) + + time.Sleep(time.Second) + nrRoundsToPropagateMultiShard := int64(10) + for i := int64(0); i < nrRoundsToPropagateMultiShard; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + time.Sleep(integrationTests.StepDelay) + } + time.Sleep(time.Second) - // ------ send tx to players - valueToTopUp := big.NewInt(100000000) - txData = core.BuiltInFunctionESDTTransfer + "@" + hex.EncodeToString([]byte(tokenIdenfitifer)) + "@" + hex.EncodeToString(valueToTopUp.Bytes()) - for _, player := range players { - integrationTests.CreateAndSendTransaction(tokenIssuer, nodes, big.NewInt(0), player.Address, txData, integrationTests.AdditionalGasLimit) - } + tokenIdenfitifer := string(integrationTests.GetTokenIdentifier(nodes, []byte("RBT"))) + CheckAddressHasTokens(t, tokenIssuer.OwnAccount.Address, nodes, tokenIdenfitifer, initalSupply) - time.Sleep(time.Second) - for i := int64(0); i < nrRoundsToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - time.Sleep(integrationTests.StepDelay) - } - time.Sleep(time.Second) - - txData = core.BuiltInFunctionESDTTransfer + "@" + hex.EncodeToString([]byte(tokenIdenfitifer)) + "@" + hex.EncodeToString(sendValue.Bytes()) - transferTokenESDTGas := uint64(1) - transferTokenBaseGas := tokenIssuer.EconomicsData.ComputeGasLimit(&transaction.Transaction{Data: []byte(txData)}) - transferTokenFullGas := transferTokenBaseGas + transferTokenESDTGas + uint64(100) // use more gas to simulate gas refund - nrRoundsToTest := int64(5) - for i := int64(0); i < nrRoundsToTest; i++ { + // ------ send tx to players + valueToTopUp := big.NewInt(100000000) + txData = core.BuiltInFunctionESDTTransfer + "@" + hex.EncodeToString([]byte(tokenIdenfitifer)) + "@" + hex.EncodeToString(valueToTopUp.Bytes()) for _, player := range players { - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress1, big.NewInt(0), transferTokenFullGas, []byte(txData)) - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, receiverAddress2, big.NewInt(0), transferTokenFullGas, []byte(txData)) + integrationTests.CreateAndSendTransaction(tokenIssuer, nodes, big.NewInt(0), player.Address, txData, integrationTests.AdditionalGasLimit) } - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + time.Sleep(time.Second) + for i := int64(0); i < nrRoundsToPropagateMultiShard; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + time.Sleep(integrationTests.StepDelay) + } + time.Sleep(time.Second) + + txData = core.BuiltInFunctionESDTTransfer + "@" + hex.EncodeToString([]byte(tokenIdenfitifer)) + "@" + hex.EncodeToString(sendValue.Bytes()) + transferTokenESDTGas := uint64(1) + transferTokenBaseGas := tokenIssuer.EconomicsData.ComputeGasLimit(&transaction.Transaction{Data: []byte(txData)}) + transferTokenFullGas := transferTokenBaseGas + transferTokenESDTGas + uint64(100) // use more gas to simulate gas refund + nrRoundsToTest := int64(5) + for i := int64(0); i < nrRoundsToTest; i++ { + for _, player := range players { + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, receiverAddress1, big.NewInt(0), transferTokenFullGas, []byte(txData)) + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, receiverAddress2, big.NewInt(0), transferTokenFullGas, []byte(txData)) + } + + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + + time.Sleep(integrationTests.StepDelay) + } - time.Sleep(integrationTests.StepDelay) - } + nrRoundsToPropagateMultiShard = int64(20) + for i := int64(0); i <= nrRoundsToPropagateMultiShard; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + } - nrRoundsToPropagateMultiShard = int64(20) - for i := int64(0); i <= nrRoundsToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + time.Sleep(time.Second) + finalBalance := big.NewInt(0).Mul(big.NewInt(int64(len(players))), big.NewInt(nrRoundsToTest)) + finalBalance.Mul(finalBalance, sendValue) + CheckAddressHasTokens(t, receiverAddress1, nodes, tokenIdenfitifer, finalBalance) + CheckAddressHasTokens(t, receiverAddress2, nodes, tokenIdenfitifer, finalBalance) + + players = append(players, relayer) + checkPlayerBalances(t, nodes, players) } +} - time.Sleep(time.Second) - finalBalance := big.NewInt(0).Mul(big.NewInt(int64(len(players))), big.NewInt(nrRoundsToTest)) - finalBalance.Mul(finalBalance, sendValue) - CheckAddressHasTokens(t, receiverAddress1, nodes, tokenIdenfitifer, finalBalance) - CheckAddressHasTokens(t, receiverAddress2, nodes, tokenIdenfitifer, finalBalance) +func testRelayedTransactionInMultiShardEnvironmentWithAttestationContract( + createAndSendRelayedAndUserTxFunc createAndSendRelayedAndUserTxFuncType, + relayedV3Test bool, +) func(t *testing.T) { + return func(t *testing.T) { - players = append(players, relayer) - checkPlayerBalances(t, nodes, players) -} + if testing.Short() { + t.Skip("this is not a short test") + } -func TestRelayedTransactionInMultiShardEnvironmentWithAttestationContract(t *testing.T) { - if testing.Short() { - t.Skip("this is not a short test") - } + nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest(relayedV3Test) + defer func() { + for _, n := range nodes { + n.Close() + } + }() - nodes, idxProposers, players, relayer := CreateGeneralSetupForRelayTxTest() - defer func() { - for _, n := range nodes { - n.Close() + for _, node := range nodes { + node.EconomicsData.SetMaxGasLimitPerBlock(1500000000, 0) } - }() - for _, node := range nodes { - node.EconomicsData.SetMaxGasLimitPerBlock(1500000000, 0) - } + round := uint64(0) + nonce := uint64(0) + round = integrationTests.IncrementAndPrintRound(round) + nonce++ - round := uint64(0) - nonce := uint64(0) - round = integrationTests.IncrementAndPrintRound(round) - nonce++ - - ownerNode := nodes[0] - scCode := wasm.GetSCCode("attestation.wasm") - scAddress, _ := ownerNode.BlockchainHook.NewAddress(ownerNode.OwnAccount.Address, ownerNode.OwnAccount.Nonce, vmFactory.WasmVirtualMachine) - - registerValue := big.NewInt(100) - integrationTests.CreateAndSendTransactionWithGasLimit( - nodes[0], - big.NewInt(0), - 2000000, - make([]byte, 32), - []byte(wasm.CreateDeployTxData(scCode)+"@"+hex.EncodeToString(registerValue.Bytes())+"@"+hex.EncodeToString(relayer.Address)+"@"+"ababab"), - integrationTests.ChainID, - integrationTests.MinTransactionVersion, - ) - time.Sleep(time.Second) - - registerVMGas := uint64(10000000) - savePublicInfoVMGas := uint64(10000000) - attestVMGas := uint64(10000000) - - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - - uniqueIDs := make([]string, len(players)) - for i, player := range players { - uniqueIDs[i] = core.UniqueIdentifier() - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, scAddress, registerValue, - registerVMGas, []byte("register@"+hex.EncodeToString([]byte(uniqueIDs[i])))) - } - time.Sleep(time.Second) + ownerNode := nodes[0] + scCode := wasm.GetSCCode("attestation.wasm") + scAddress, _ := ownerNode.BlockchainHook.NewAddress(ownerNode.OwnAccount.Address, ownerNode.OwnAccount.Nonce, vmFactory.WasmVirtualMachine) - nrRoundsToPropagateMultiShard := int64(10) - for i := int64(0); i <= nrRoundsToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - } + registerValue := big.NewInt(100) + integrationTests.CreateAndSendTransactionWithGasLimit( + nodes[0], + big.NewInt(0), + 2000000, + make([]byte, 32), + []byte(wasm.CreateDeployTxData(scCode)+"@"+hex.EncodeToString(registerValue.Bytes())+"@"+hex.EncodeToString(relayer.Address)+"@"+"ababab"), + integrationTests.ChainID, + integrationTests.MinTransactionVersion, + ) + time.Sleep(time.Second) - cryptoHook := hooks.NewVMCryptoHook() - privateInfos := make([]string, len(players)) - for i := range players { - privateInfos[i] = core.UniqueIdentifier() - publicInfo, _ := cryptoHook.Keccak256([]byte(privateInfos[i])) - createAndSendSimpleTransaction(nodes, relayer, scAddress, big.NewInt(0), savePublicInfoVMGas, - []byte("savePublicInfo@"+hex.EncodeToString([]byte(uniqueIDs[i]))+"@"+hex.EncodeToString(publicInfo))) - } - time.Sleep(time.Second) + registerVMGas := uint64(10000000) + savePublicInfoVMGas := uint64(10000000) + attestVMGas := uint64(10000000) - nrRoundsToPropagate := int64(5) - for i := int64(0); i <= nrRoundsToPropagate; i++ { round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - } - for i, player := range players { - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, scAddress, big.NewInt(0), attestVMGas, - []byte("attest@"+hex.EncodeToString([]byte(uniqueIDs[i]))+"@"+hex.EncodeToString([]byte(privateInfos[i])))) - _ = CreateAndSendRelayedAndUserTx(nodes, relayer, player, scAddress, registerValue, - registerVMGas, []byte("register@"+hex.EncodeToString([]byte(uniqueIDs[i])))) - } - time.Sleep(time.Second) + integrationTests.MintAllPlayers(nodes, players, registerValue) - nrRoundsToPropagateMultiShard = int64(20) - for i := int64(0); i <= nrRoundsToPropagateMultiShard; i++ { - round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) - integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) - } + uniqueIDs := make([]string, len(players)) + for i, player := range players { + uniqueIDs[i] = core.UniqueIdentifier() + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, scAddress, registerValue, + registerVMGas, []byte("register@"+hex.EncodeToString([]byte(uniqueIDs[i])))) + } + time.Sleep(time.Second) - for i, player := range players { - checkAttestedPublicKeys(t, ownerNode, scAddress, []byte(uniqueIDs[i]), player.Address) + nrRoundsToPropagateMultiShard := int64(10) + for i := int64(0); i <= nrRoundsToPropagateMultiShard; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + } + + cryptoHook := hooks.NewVMCryptoHook() + privateInfos := make([]string, len(players)) + for i := range players { + privateInfos[i] = core.UniqueIdentifier() + publicInfo, _ := cryptoHook.Keccak256([]byte(privateInfos[i])) + createAndSendSimpleTransaction(nodes, relayer, scAddress, big.NewInt(0), savePublicInfoVMGas, + []byte("savePublicInfo@"+hex.EncodeToString([]byte(uniqueIDs[i]))+"@"+hex.EncodeToString(publicInfo))) + } + time.Sleep(time.Second) + + nrRoundsToPropagate := int64(5) + for i := int64(0); i <= nrRoundsToPropagate; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + } + + integrationTests.MintAllPlayers(nodes, players, registerValue) + + for i, player := range players { + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, scAddress, big.NewInt(0), attestVMGas, + []byte("attest@"+hex.EncodeToString([]byte(uniqueIDs[i]))+"@"+hex.EncodeToString([]byte(privateInfos[i])))) + _, _ = createAndSendRelayedAndUserTxFunc(nodes, relayer, player, scAddress, registerValue, + registerVMGas, []byte("register@"+hex.EncodeToString([]byte(uniqueIDs[i])))) + } + time.Sleep(time.Second) + + nrRoundsToPropagateMultiShard = int64(20) + for i := int64(0); i <= nrRoundsToPropagateMultiShard; i++ { + round, nonce = integrationTests.ProposeAndSyncOneBlock(t, nodes, idxProposers, round, nonce) + integrationTests.AddSelfNotarizedHeaderByMetachain(nodes) + } + + for i, player := range players { + checkAttestedPublicKeys(t, ownerNode, scAddress, []byte(uniqueIDs[i]), player.Address) + } } } @@ -386,7 +449,7 @@ func checkPlayerBalances( players []*integrationTests.TestWalletAccount) { for _, player := range players { userAcc := GetUserAccount(nodes, player.Address) - assert.Equal(t, userAcc.GetBalance().Cmp(player.Balance), 0) + assert.Equal(t, 0, userAcc.GetBalance().Cmp(player.Balance)) assert.Equal(t, userAcc.GetNonce(), player.Nonce) } } diff --git a/integrationTests/multiShard/smartContract/dns/dns_test.go b/integrationTests/multiShard/smartContract/dns/dns_test.go index 20135a2bda4..1f983617cb1 100644 --- a/integrationTests/multiShard/smartContract/dns/dns_test.go +++ b/integrationTests/multiShard/smartContract/dns/dns_test.go @@ -202,7 +202,7 @@ func sendRegisterUserNameAsRelayedTx( for i, player := range players { userName := generateNewUserName() scAddress := selectDNSAddressFromUserName(sortedDNSAddresses, userName) - _ = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, []byte(scAddress), dnsRegisterValue, + _, _ = relayedTx.CreateAndSendRelayedAndUserTx(nodes, relayer, player, []byte(scAddress), dnsRegisterValue, gasLimit, []byte("register@"+hex.EncodeToString([]byte(userName)))) userNames[i] = userName } diff --git a/integrationTests/testHeartbeatNode.go b/integrationTests/testHeartbeatNode.go index 1ba488b9e12..43b2ac576a0 100644 --- a/integrationTests/testHeartbeatNode.go +++ b/integrationTests/testHeartbeatNode.go @@ -54,6 +54,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/genesisMocks" "github.com/multiversx/mx-chain-go/testscommon/nodeTypeProviderMock" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" trieMock "github.com/multiversx/mx-chain-go/testscommon/trie" vic "github.com/multiversx/mx-chain-go/testscommon/validatorInfoCacher" @@ -626,6 +627,7 @@ func (thn *TestHeartbeatNode) initInterceptors() { SignaturesHandler: &processMock.SignaturesHandlerStub{}, HeartbeatExpiryTimespanInSec: thn.heartbeatExpiryTimespanInSec, PeerID: thn.MainMessenger.ID(), + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, } thn.createPeerAuthInterceptor(argsFactory) diff --git a/integrationTests/testInitializer.go b/integrationTests/testInitializer.go index a7c6cdac3c3..06dc1a24866 100644 --- a/integrationTests/testInitializer.go +++ b/integrationTests/testInitializer.go @@ -69,6 +69,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/guardianMocks" "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/stakingcommon" testStorage "github.com/multiversx/mx-chain-go/testscommon/state" statusHandlerMock "github.com/multiversx/mx-chain-go/testscommon/statusHandler" @@ -1055,15 +1056,17 @@ func CreateSimpleTxProcessor(accnts state.AccountsAdapter) process.TransactionPr return fee }, }, - ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, - BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, - ArgsParser: smartContract.NewArgumentParser(), - ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, - EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, - EnableEpochsHandler: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, - TxVersionChecker: &testscommon.TxVersionCheckerStub{}, - GuardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, - TxLogsProcessor: &mock.TxLogsProcessorStub{}, + ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, + BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, + ArgsParser: smartContract.NewArgumentParser(), + ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, + EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, + EnableEpochsHandler: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + TxVersionChecker: &testscommon.TxVersionCheckerStub{}, + GuardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, + TxLogsProcessor: &mock.TxLogsProcessorStub{}, + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } txProcessor, _ := txProc.NewTxProcessor(argsNewTxProcessor) diff --git a/integrationTests/testProcessorNode.go b/integrationTests/testProcessorNode.go index a7468de8485..ef55c21f54a 100644 --- a/integrationTests/testProcessorNode.go +++ b/integrationTests/testProcessorNode.go @@ -114,6 +114,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/mainFactoryMocks" "github.com/multiversx/mx-chain-go/testscommon/outport" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" "github.com/multiversx/mx-chain-go/testscommon/stakingcommon" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" @@ -1287,6 +1288,12 @@ func (tpn *TestProcessorNode) initInterceptors(heartbeatPk string) { cryptoComponents.BlKeyGen = tpn.OwnAccount.KeygenBlockSign cryptoComponents.TxKeyGen = tpn.OwnAccount.KeygenTxSign + relayedV3TxProcessor, _ := transaction.NewRelayedTxV3Processor(transaction.ArgRelayedTxV3Processor{ + EconomicsFee: tpn.EconomicsData, + ShardCoordinator: tpn.ShardCoordinator, + MaxTransactionsAllowed: 10, + }) + if tpn.ShardCoordinator.SelfId() == core.MetachainShardId { argsEpochStart := &metachain.ArgsNewMetaEpochStartTrigger{ GenesisTime: tpn.RoundHandler.TimeStamp(), @@ -1339,6 +1346,7 @@ func (tpn *TestProcessorNode) initInterceptors(heartbeatPk string) { FullArchivePeerShardMapper: tpn.FullArchivePeerShardMapper, HardforkTrigger: tpn.HardforkTrigger, NodeOperationMode: tpn.NodeOperationMode, + RelayedTxV3Processor: relayedV3TxProcessor, } interceptorContainerFactory, _ := interceptorscontainer.NewMetaInterceptorsContainerFactory(metaInterceptorContainerFactoryArgs) @@ -1407,6 +1415,7 @@ func (tpn *TestProcessorNode) initInterceptors(heartbeatPk string) { FullArchivePeerShardMapper: tpn.FullArchivePeerShardMapper, HardforkTrigger: tpn.HardforkTrigger, NodeOperationMode: tpn.NodeOperationMode, + RelayedTxV3Processor: relayedV3TxProcessor, } interceptorContainerFactory, _ := interceptorscontainer.NewShardInterceptorsContainerFactory(shardIntereptorContainerFactoryArgs) @@ -1687,56 +1696,66 @@ func (tpn *TestProcessorNode) initInnerProcessors(gasMap map[string]map[string]u EnableEpochsHandler: tpn.EnableEpochsHandler, } txTypeHandler, _ := coordinator.NewTxTypeHandler(argsTxTypeHandler) + _ = tpn.EconomicsData.SetTxTypeHandler(txTypeHandler) tpn.GasHandler, _ = preprocess.NewGasComputation(tpn.EconomicsData, txTypeHandler, tpn.EnableEpochsHandler) badBlocksHandler, _ := tpn.InterimProcContainer.Get(dataBlock.InvalidBlock) argsNewScProcessor := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: tpn.VMContainer, - ArgsParser: tpn.ArgsParser, - Hasher: TestHasher, - Marshalizer: TestMarshalizer, - AccountsDB: tpn.AccntState, - BlockChainHook: vmFactory.BlockChainHookImpl(), - BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), - PubkeyConv: TestAddressPubkeyConverter, - ShardCoordinator: tpn.ShardCoordinator, - ScrForwarder: tpn.ScrForwarder, - TxFeeHandler: tpn.FeeAccumulator, - EconomicsFee: tpn.EconomicsData, - TxTypeHandler: txTypeHandler, - GasHandler: tpn.GasHandler, - GasSchedule: gasSchedule, - TxLogsProcessor: tpn.TransactionLogProcessor, - BadTxForwarder: badBlocksHandler, - EnableRoundsHandler: tpn.EnableRoundsHandler, - EnableEpochsHandler: tpn.EnableEpochsHandler, - VMOutputCacher: txcache.NewDisabledCache(), - WasmVMChangeLocker: tpn.WasmVMChangeLocker, + VmContainer: tpn.VMContainer, + ArgsParser: tpn.ArgsParser, + Hasher: TestHasher, + Marshalizer: TestMarshalizer, + AccountsDB: tpn.AccntState, + BlockChainHook: vmFactory.BlockChainHookImpl(), + BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), + PubkeyConv: TestAddressPubkeyConverter, + ShardCoordinator: tpn.ShardCoordinator, + ScrForwarder: tpn.ScrForwarder, + TxFeeHandler: tpn.FeeAccumulator, + EconomicsFee: tpn.EconomicsData, + TxTypeHandler: txTypeHandler, + GasHandler: tpn.GasHandler, + GasSchedule: gasSchedule, + TxLogsProcessor: tpn.TransactionLogProcessor, + BadTxForwarder: badBlocksHandler, + EnableRoundsHandler: tpn.EnableRoundsHandler, + EnableEpochsHandler: tpn.EnableEpochsHandler, + VMOutputCacher: txcache.NewDisabledCache(), + WasmVMChangeLocker: tpn.WasmVMChangeLocker, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } tpn.ScProcessor, _ = processProxy.NewTestSmartContractProcessorProxy(argsNewScProcessor, tpn.EpochNotifier) + relayedV3TxProcessor, _ := transaction.NewRelayedTxV3Processor(transaction.ArgRelayedTxV3Processor{ + EconomicsFee: tpn.EconomicsData, + ShardCoordinator: tpn.ShardCoordinator, + MaxTransactionsAllowed: 10, + }) + receiptsHandler, _ := tpn.InterimProcContainer.Get(dataBlock.ReceiptBlock) argsNewTxProcessor := transaction.ArgsNewTxProcessor{ - Accounts: tpn.AccntState, - Hasher: TestHasher, - PubkeyConv: TestAddressPubkeyConverter, - Marshalizer: TestMarshalizer, - SignMarshalizer: TestTxSignMarshalizer, - ShardCoordinator: tpn.ShardCoordinator, - ScProcessor: tpn.ScProcessor, - TxFeeHandler: tpn.FeeAccumulator, - TxTypeHandler: txTypeHandler, - EconomicsFee: tpn.EconomicsData, - ReceiptForwarder: receiptsHandler, - BadTxForwarder: badBlocksHandler, - ArgsParser: tpn.ArgsParser, - ScrForwarder: tpn.ScrForwarder, - EnableRoundsHandler: tpn.EnableRoundsHandler, - EnableEpochsHandler: tpn.EnableEpochsHandler, - GuardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, - TxVersionChecker: &testscommon.TxVersionCheckerStub{}, - TxLogsProcessor: tpn.TransactionLogProcessor, + Accounts: tpn.AccntState, + Hasher: TestHasher, + PubkeyConv: TestAddressPubkeyConverter, + Marshalizer: TestMarshalizer, + SignMarshalizer: TestTxSignMarshalizer, + ShardCoordinator: tpn.ShardCoordinator, + ScProcessor: tpn.ScProcessor, + TxFeeHandler: tpn.FeeAccumulator, + TxTypeHandler: txTypeHandler, + EconomicsFee: tpn.EconomicsData, + ReceiptForwarder: receiptsHandler, + BadTxForwarder: badBlocksHandler, + ArgsParser: tpn.ArgsParser, + ScrForwarder: tpn.ScrForwarder, + EnableRoundsHandler: tpn.EnableRoundsHandler, + EnableEpochsHandler: tpn.EnableEpochsHandler, + GuardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, + TxVersionChecker: &testscommon.TxVersionCheckerStub{}, + TxLogsProcessor: tpn.TransactionLogProcessor, + RelayedTxV3Processor: relayedV3TxProcessor, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } tpn.TxProcessor, _ = transaction.NewTxProcessor(argsNewTxProcessor) scheduledSCRsStorer, _ := tpn.Storage.GetStorer(dataRetriever.ScheduledSCRsUnit) @@ -1967,30 +1986,32 @@ func (tpn *TestProcessorNode) initMetaInnerProcessors(gasMap map[string]map[stri EnableEpochsHandler: tpn.EnableEpochsHandler, } txTypeHandler, _ := coordinator.NewTxTypeHandler(argsTxTypeHandler) + _ = tpn.EconomicsData.SetTxTypeHandler(txTypeHandler) tpn.GasHandler, _ = preprocess.NewGasComputation(tpn.EconomicsData, txTypeHandler, tpn.EnableEpochsHandler) badBlocksHandler, _ := tpn.InterimProcContainer.Get(dataBlock.InvalidBlock) argsNewScProcessor := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: tpn.VMContainer, - ArgsParser: tpn.ArgsParser, - Hasher: TestHasher, - Marshalizer: TestMarshalizer, - AccountsDB: tpn.AccntState, - BlockChainHook: vmFactory.BlockChainHookImpl(), - BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), - PubkeyConv: TestAddressPubkeyConverter, - ShardCoordinator: tpn.ShardCoordinator, - ScrForwarder: tpn.ScrForwarder, - TxFeeHandler: tpn.FeeAccumulator, - EconomicsFee: tpn.EconomicsData, - TxTypeHandler: txTypeHandler, - GasHandler: tpn.GasHandler, - GasSchedule: gasSchedule, - TxLogsProcessor: tpn.TransactionLogProcessor, - BadTxForwarder: badBlocksHandler, - EnableRoundsHandler: tpn.EnableRoundsHandler, - EnableEpochsHandler: tpn.EnableEpochsHandler, - VMOutputCacher: txcache.NewDisabledCache(), - WasmVMChangeLocker: tpn.WasmVMChangeLocker, + VmContainer: tpn.VMContainer, + ArgsParser: tpn.ArgsParser, + Hasher: TestHasher, + Marshalizer: TestMarshalizer, + AccountsDB: tpn.AccntState, + BlockChainHook: vmFactory.BlockChainHookImpl(), + BuiltInFunctions: builtInFuncFactory.BuiltInFunctionContainer(), + PubkeyConv: TestAddressPubkeyConverter, + ShardCoordinator: tpn.ShardCoordinator, + ScrForwarder: tpn.ScrForwarder, + TxFeeHandler: tpn.FeeAccumulator, + EconomicsFee: tpn.EconomicsData, + TxTypeHandler: txTypeHandler, + GasHandler: tpn.GasHandler, + GasSchedule: gasSchedule, + TxLogsProcessor: tpn.TransactionLogProcessor, + BadTxForwarder: badBlocksHandler, + EnableRoundsHandler: tpn.EnableRoundsHandler, + EnableEpochsHandler: tpn.EnableEpochsHandler, + VMOutputCacher: txcache.NewDisabledCache(), + WasmVMChangeLocker: tpn.WasmVMChangeLocker, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } tpn.ScProcessor, _ = processProxy.NewTestSmartContractProcessorProxy(argsNewScProcessor, tpn.EpochNotifier) @@ -2593,21 +2614,22 @@ func (tpn *TestProcessorNode) SendTransaction(tx *dataTransaction.Transaction) ( guardianAddress = TestAddressPubkeyConverter.SilentEncode(tx.GuardianAddr, 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), + InnerTransactions: tx.InnerTransactions, } tx, txHash, err := tpn.Node.CreateTransaction(createTxArgs) if err != nil { @@ -3253,6 +3275,8 @@ func CreateEnableEpochsConfig() config.EnableEpochs { MiniBlockPartialExecutionEnableEpoch: UnreachableEpoch, RefactorPeersMiniBlocksEnableEpoch: UnreachableEpoch, SCProcessorV2EnableEpoch: UnreachableEpoch, + RelayedTransactionsV3EnableEpoch: UnreachableEpoch, + FixRelayedBaseCostEnableEpoch: UnreachableEpoch, } } @@ -3338,6 +3362,11 @@ func GetDefaultProcessComponents() *mock.ProcessComponentsStub { CurrentEpochProviderInternal: &testscommon.CurrentEpochProviderStub{}, HistoryRepositoryInternal: &dblookupextMock.HistoryRepositoryStub{}, HardforkTriggerField: &testscommon.HardforkTriggerStub{}, + RelayedTxV3ProcessorField: &processMocks.RelayedTxV3ProcessorMock{ + CheckRelayedTxCalled: func(tx *dataTransaction.Transaction) error { + return nil + }, + }, } } @@ -3558,6 +3587,5 @@ func GetDefaultEnableEpochsConfig() *config.EnableEpochs { DynamicGasCostForDataTrieStorageLoadEnableEpoch: UnreachableEpoch, StakingV4Step1EnableEpoch: UnreachableEpoch, StakingV4Step2EnableEpoch: UnreachableEpoch, - StakingV4Step3EnableEpoch: UnreachableEpoch, } } diff --git a/integrationTests/testProcessorNodeWithTestWebServer.go b/integrationTests/testProcessorNodeWithTestWebServer.go index 592d7d1bdba..b380a643660 100644 --- a/integrationTests/testProcessorNodeWithTestWebServer.go +++ b/integrationTests/testProcessorNodeWithTestWebServer.go @@ -162,6 +162,7 @@ func createFacadeComponents(tpn *TestProcessorNode) nodeFacade.ApiResolver { } txTypeHandler, err := coordinator.NewTxTypeHandler(argsTxTypeHandler) log.LogIfError(err) + _ = tpn.EconomicsData.SetTxTypeHandler(txTypeHandler) argsDataFieldParser := &datafield.ArgsOperationDataFieldParser{ AddressLength: TestAddressPubkeyConverter.Len(), diff --git a/integrationTests/vm/testInitializer.go b/integrationTests/vm/testInitializer.go index 4ffd57197ca..fc129e36d90 100644 --- a/integrationTests/vm/testInitializer.go +++ b/integrationTests/vm/testInitializer.go @@ -62,6 +62,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/epochNotifier" "github.com/multiversx/mx-chain-go/testscommon/genesisMocks" "github.com/multiversx/mx-chain-go/testscommon/integrationtests" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" storageStubs "github.com/multiversx/mx-chain-go/testscommon/storage" "github.com/multiversx/mx-chain-go/testscommon/txDataBuilder" @@ -140,8 +141,9 @@ type VMTestContext struct { ContractOwner VMTestAccount Contract VMTestAccount - TxCostHandler external.TransactionEvaluator - TxsLogsProcessor process.TransactionLogProcessor + TxCostHandler external.TransactionEvaluator + TxsLogsProcessor process.TransactionLogProcessor + FailedTxLogsAccumulator process.FailedTxLogsAccumulator } // Close - @@ -317,7 +319,7 @@ func CreateAccount(accnts state.AccountsAdapter, pubKey []byte, nonce uint64, ba return hashCreated, nil } -func createEconomicsData(enableEpochsConfig config.EnableEpochs) (process.EconomicsDataHandler, error) { +func createEconomicsData(enableEpochsConfig config.EnableEpochs, gasPriceModifier float64) (process.EconomicsDataHandler, error) { maxGasLimitPerBlock := strconv.FormatUint(math.MaxUint64, 10) minGasPrice := strconv.FormatUint(1, 10) minGasLimit := strconv.FormatUint(1, 10) @@ -363,7 +365,7 @@ func createEconomicsData(enableEpochsConfig config.EnableEpochs) (process.Econom }, MinGasPrice: minGasPrice, GasPerDataByte: "1", - GasPriceModifier: 1.0, + GasPriceModifier: gasPriceModifier, MaxGasPriceSetGuardian: "2000000000", }, }, @@ -437,10 +439,11 @@ func CreateTxProcessorWithOneSCExecutorMockVM( } txTypeHandler, _ := coordinator.NewTxTypeHandler(argsTxTypeHandler) - economicsData, err := createEconomicsData(enableEpochsConfig) + economicsData, err := createEconomicsData(enableEpochsConfig, 1) if err != nil { return nil, err } + _ = economicsData.SetTxTypeHandler(txTypeHandler) argsNewSCProcessor := scrCommon.ArgsNewSmartContractProcessor{ VmContainer: vmContainer, @@ -460,12 +463,13 @@ func CreateTxProcessorWithOneSCExecutorMockVM( GasHandler: &testscommon.GasHandlerStub{ SetGasRefundedCalled: func(gasRefunded uint64, hash []byte) {}, }, - GasSchedule: gasScheduleNotifier, - TxLogsProcessor: &mock.TxLogsProcessorStub{}, - EnableEpochsHandler: enableEpochsHandler, - EnableRoundsHandler: enableRoundsHandler, - VMOutputCacher: txcache.NewDisabledCache(), - WasmVMChangeLocker: wasmVMChangeLocker, + GasSchedule: gasScheduleNotifier, + TxLogsProcessor: &mock.TxLogsProcessorStub{}, + EnableEpochsHandler: enableEpochsHandler, + EnableRoundsHandler: enableRoundsHandler, + VMOutputCacher: txcache.NewDisabledCache(), + WasmVMChangeLocker: wasmVMChangeLocker, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } scProcessor, _ := processProxy.NewTestSmartContractProcessorProxy(argsNewSCProcessor, genericEpochNotifier) @@ -476,25 +480,27 @@ func CreateTxProcessorWithOneSCExecutorMockVM( } argsNewTxProcessor := transaction.ArgsNewTxProcessor{ - Accounts: accnts, - Hasher: integrationtests.TestHasher, - PubkeyConv: pubkeyConv, - Marshalizer: integrationtests.TestMarshalizer, - SignMarshalizer: integrationtests.TestMarshalizer, - ShardCoordinator: mock.NewMultiShardsCoordinatorMock(2), - ScProcessor: scProcessor, - TxFeeHandler: &testscommon.UnsignedTxHandlerStub{}, - TxTypeHandler: txTypeHandler, - EconomicsFee: economicsData, - ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, - BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, - ArgsParser: smartContract.NewArgumentParser(), - ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, - EnableRoundsHandler: enableRoundsHandler, - EnableEpochsHandler: enableEpochsHandler, - TxVersionChecker: versioning.NewTxVersionChecker(minTransactionVersion), - GuardianChecker: guardedAccountHandler, - TxLogsProcessor: &mock.TxLogsProcessorStub{}, + Accounts: accnts, + Hasher: integrationtests.TestHasher, + PubkeyConv: pubkeyConv, + Marshalizer: integrationtests.TestMarshalizer, + SignMarshalizer: integrationtests.TestMarshalizer, + ShardCoordinator: mock.NewMultiShardsCoordinatorMock(2), + ScProcessor: scProcessor, + TxFeeHandler: &testscommon.UnsignedTxHandlerStub{}, + TxTypeHandler: txTypeHandler, + EconomicsFee: economicsData, + ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, + BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, + ArgsParser: smartContract.NewArgumentParser(), + ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, + EnableRoundsHandler: enableRoundsHandler, + EnableEpochsHandler: enableEpochsHandler, + TxVersionChecker: versioning.NewTxVersionChecker(minTransactionVersion), + GuardianChecker: guardedAccountHandler, + TxLogsProcessor: &mock.TxLogsProcessorStub{}, + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } return transaction.NewTxProcessor(argsNewTxProcessor) @@ -686,7 +692,7 @@ func CreateVMAndBlockchainHookMeta( MissingTrieNodesNotifier: &testscommon.MissingTrieNodesNotifierStub{}, } - economicsData, err := createEconomicsData(config.EnableEpochs{}) + economicsData, err := createEconomicsData(config.EnableEpochs{}, 1) if err != nil { log.LogIfError(err) } @@ -803,12 +809,13 @@ func CreateVMConfigWithVersion(version string) *config.VirtualMachineConfig { // ResultsCreateTxProcessor is the struct that will hold all needed processor instances type ResultsCreateTxProcessor struct { - TxProc process.TransactionProcessor - SCProc scrCommon.TestSmartContractProcessor - IntermediateTxProc process.IntermediateTransactionHandler - EconomicsHandler process.EconomicsDataHandler - CostHandler external.TransactionEvaluator - TxLogProc process.TransactionLogProcessor + TxProc process.TransactionProcessor + SCProc scrCommon.TestSmartContractProcessor + IntermediateTxProc process.IntermediateTransactionHandler + EconomicsHandler process.EconomicsDataHandler + CostHandler external.TransactionEvaluator + TxLogProc process.TransactionLogProcessor + FailedTxLogsAccumulator process.FailedTxLogsAccumulator } // CreateTxProcessorWithOneSCExecutorWithVMs - @@ -826,6 +833,7 @@ func CreateTxProcessorWithOneSCExecutorWithVMs( guardianChecker process.GuardianChecker, roundNotifierInstance process.RoundNotifier, chainHandler data.ChainHandler, + gasPriceModifier float64, ) (*ResultsCreateTxProcessor, error) { if check.IfNil(poolsHolder) { poolsHolder = dataRetrieverMock.NewPoolsHolderMock() @@ -848,10 +856,11 @@ func CreateTxProcessorWithOneSCExecutorWithVMs( gasSchedule := make(map[string]map[string]uint64) defaults.FillGasMapInternal(gasSchedule, 1) - economicsData, err := createEconomicsData(enableEpochsConfig) + economicsData, err := createEconomicsData(enableEpochsConfig, gasPriceModifier) if err != nil { return nil, err } + _ = economicsData.SetTxTypeHandler(txTypeHandler) gasComp, err := preprocess.NewGasComputation(economicsData, txTypeHandler, enableEpochsHandler) if err != nil { @@ -863,53 +872,58 @@ func CreateTxProcessorWithOneSCExecutorWithVMs( Marshalizer: integrationtests.TestMarshalizer, }) + failedLogsAcc := transactionLog.NewFailedTxLogsAccumulator() + intermediateTxHandler := &mock.IntermediateTransactionHandlerMock{} argsNewSCProcessor := scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: vmContainer, - ArgsParser: smartContract.NewArgumentParser(), - Hasher: integrationtests.TestHasher, - Marshalizer: integrationtests.TestMarshalizer, - AccountsDB: accnts, - BlockChainHook: blockChainHook, - BuiltInFunctions: blockChainHook.GetBuiltinFunctionsContainer(), - PubkeyConv: pubkeyConv, - ShardCoordinator: shardCoordinator, - ScrForwarder: intermediateTxHandler, - BadTxForwarder: intermediateTxHandler, - TxFeeHandler: feeAccumulator, - EconomicsFee: economicsData, - TxTypeHandler: txTypeHandler, - GasHandler: gasComp, - GasSchedule: mock.NewGasScheduleNotifierMock(gasSchedule), - TxLogsProcessor: logProc, - EnableRoundsHandler: enableRoundsHandler, - EnableEpochsHandler: enableEpochsHandler, - WasmVMChangeLocker: wasmVMChangeLocker, - VMOutputCacher: txcache.NewDisabledCache(), + VmContainer: vmContainer, + ArgsParser: smartContract.NewArgumentParser(), + Hasher: integrationtests.TestHasher, + Marshalizer: integrationtests.TestMarshalizer, + AccountsDB: accnts, + BlockChainHook: blockChainHook, + BuiltInFunctions: blockChainHook.GetBuiltinFunctionsContainer(), + PubkeyConv: pubkeyConv, + ShardCoordinator: shardCoordinator, + ScrForwarder: intermediateTxHandler, + BadTxForwarder: intermediateTxHandler, + TxFeeHandler: feeAccumulator, + EconomicsFee: economicsData, + TxTypeHandler: txTypeHandler, + GasHandler: gasComp, + GasSchedule: mock.NewGasScheduleNotifierMock(gasSchedule), + TxLogsProcessor: logProc, + EnableRoundsHandler: enableRoundsHandler, + EnableEpochsHandler: enableEpochsHandler, + WasmVMChangeLocker: wasmVMChangeLocker, + VMOutputCacher: txcache.NewDisabledCache(), + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } scProcessorProxy, _ := processProxy.NewTestSmartContractProcessorProxy(argsNewSCProcessor, epochNotifierInstance) argsNewTxProcessor := transaction.ArgsNewTxProcessor{ - Accounts: accnts, - Hasher: integrationtests.TestHasher, - PubkeyConv: pubkeyConv, - Marshalizer: integrationtests.TestMarshalizer, - SignMarshalizer: integrationtests.TestMarshalizer, - ShardCoordinator: shardCoordinator, - ScProcessor: scProcessorProxy, - TxFeeHandler: feeAccumulator, - TxTypeHandler: txTypeHandler, - EconomicsFee: economicsData, - ReceiptForwarder: intermediateTxHandler, - BadTxForwarder: intermediateTxHandler, - ArgsParser: smartContract.NewArgumentParser(), - ScrForwarder: intermediateTxHandler, - EnableRoundsHandler: enableRoundsHandler, - EnableEpochsHandler: enableEpochsHandler, - TxVersionChecker: versioning.NewTxVersionChecker(minTransactionVersion), - GuardianChecker: guardianChecker, - TxLogsProcessor: logProc, + Accounts: accnts, + Hasher: integrationtests.TestHasher, + PubkeyConv: pubkeyConv, + Marshalizer: integrationtests.TestMarshalizer, + SignMarshalizer: integrationtests.TestMarshalizer, + ShardCoordinator: shardCoordinator, + ScProcessor: scProcessorProxy, + TxFeeHandler: feeAccumulator, + TxTypeHandler: txTypeHandler, + EconomicsFee: economicsData, + ReceiptForwarder: intermediateTxHandler, + BadTxForwarder: intermediateTxHandler, + ArgsParser: smartContract.NewArgumentParser(), + ScrForwarder: intermediateTxHandler, + EnableRoundsHandler: enableRoundsHandler, + EnableEpochsHandler: enableEpochsHandler, + TxVersionChecker: versioning.NewTxVersionChecker(minTransactionVersion), + GuardianChecker: guardianChecker, + TxLogsProcessor: logProc, + FailedTxLogsAccumulator: failedLogsAcc, + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, } txProcessor, err := transaction.NewTxProcessor(argsNewTxProcessor) if err != nil { @@ -1139,6 +1153,7 @@ func CreatePreparedTxProcessorAndAccountsWithVMsWithRoundsConfig( guardedAccountHandler, roundNotifierInstance, chainHandler, + 1, ) if err != nil { return nil, err @@ -1172,36 +1187,48 @@ func createMockGasScheduleNotifierWithCustomGasSchedule(updateGasSchedule func(g } // CreatePreparedTxProcessorWithVMs - -func CreatePreparedTxProcessorWithVMs(enableEpochs config.EnableEpochs) (*VMTestContext, error) { - return CreatePreparedTxProcessorWithVMsAndCustomGasSchedule(enableEpochs, func(gasMap wasmConfig.GasScheduleMap) {}) +func CreatePreparedTxProcessorWithVMs(enableEpochs config.EnableEpochs, gasPriceModifier float64) (*VMTestContext, error) { + return CreatePreparedTxProcessorWithVMsAndCustomGasSchedule(enableEpochs, func(gasMap wasmConfig.GasScheduleMap) {}, gasPriceModifier) } // CreatePreparedTxProcessorWithVMsAndCustomGasSchedule - func CreatePreparedTxProcessorWithVMsAndCustomGasSchedule( enableEpochs config.EnableEpochs, - updateGasSchedule func(gasMap wasmConfig.GasScheduleMap)) (*VMTestContext, error) { + updateGasSchedule func(gasMap wasmConfig.GasScheduleMap), + gasPriceModifier float64) (*VMTestContext, error) { return CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGasAndRoundConfig( enableEpochs, mock.NewMultiShardsCoordinatorMock(2), integrationtests.CreateMemUnit(), createMockGasScheduleNotifierWithCustomGasSchedule(updateGasSchedule), testscommon.GetDefaultRoundsConfig(), + gasPriceModifier, ) } // CreatePreparedTxProcessorWithVMsWithShardCoordinator - -func CreatePreparedTxProcessorWithVMsWithShardCoordinator(enableEpochsConfig config.EnableEpochs, shardCoordinator sharding.Coordinator) (*VMTestContext, error) { - return CreatePreparedTxProcessorWithVMsWithShardCoordinatorAndRoundConfig(enableEpochsConfig, testscommon.GetDefaultRoundsConfig(), shardCoordinator) +func CreatePreparedTxProcessorWithVMsWithShardCoordinator( + enableEpochsConfig config.EnableEpochs, + shardCoordinator sharding.Coordinator, + gasPriceModifier float64, +) (*VMTestContext, error) { + return CreatePreparedTxProcessorWithVMsWithShardCoordinatorAndRoundConfig(enableEpochsConfig, testscommon.GetDefaultRoundsConfig(), shardCoordinator, gasPriceModifier) } // CreatePreparedTxProcessorWithVMsWithShardCoordinatorAndRoundConfig - -func CreatePreparedTxProcessorWithVMsWithShardCoordinatorAndRoundConfig(enableEpochsConfig config.EnableEpochs, roundsConfig config.RoundConfig, shardCoordinator sharding.Coordinator) (*VMTestContext, error) { +func CreatePreparedTxProcessorWithVMsWithShardCoordinatorAndRoundConfig( + enableEpochsConfig config.EnableEpochs, + roundsConfig config.RoundConfig, + shardCoordinator sharding.Coordinator, + gasPriceModifier float64, +) (*VMTestContext, error) { return CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGasAndRoundConfig( enableEpochsConfig, shardCoordinator, integrationtests.CreateMemUnit(), CreateMockGasScheduleNotifier(), roundsConfig, + gasPriceModifier, ) } @@ -1211,6 +1238,7 @@ func CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGas( shardCoordinator sharding.Coordinator, db storage.Storer, gasScheduleNotifier core.GasScheduleNotifier, + gasPriceModifier float64, ) (*VMTestContext, error) { vmConfig := createDefaultVMConfig() return CreatePreparedTxProcessorWithVMConfigWithShardCoordinatorDBAndGasAndRoundConfig( @@ -1220,6 +1248,7 @@ func CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGas( gasScheduleNotifier, testscommon.GetDefaultRoundsConfig(), vmConfig, + gasPriceModifier, ) } @@ -1230,6 +1259,7 @@ func CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGasAndRoundConfig( db storage.Storer, gasScheduleNotifier core.GasScheduleNotifier, roundsConfig config.RoundConfig, + gasPriceModifier float64, ) (*VMTestContext, error) { vmConfig := createDefaultVMConfig() return CreatePreparedTxProcessorWithVMConfigWithShardCoordinatorDBAndGasAndRoundConfig( @@ -1239,6 +1269,7 @@ func CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGasAndRoundConfig( gasScheduleNotifier, roundsConfig, vmConfig, + gasPriceModifier, ) } @@ -1250,6 +1281,7 @@ func CreatePreparedTxProcessorWithVMConfigWithShardCoordinatorDBAndGasAndRoundCo gasScheduleNotifier core.GasScheduleNotifier, roundsConfig config.RoundConfig, vmConfig *config.VirtualMachineConfig, + gasPriceModifier float64, ) (*VMTestContext, error) { feeAccumulator := postprocess.NewFeeAccumulator() epochNotifierInstance := forking.NewGenericEpochNotifier() @@ -1291,29 +1323,31 @@ func CreatePreparedTxProcessorWithVMConfigWithShardCoordinatorDBAndGasAndRoundCo guardedAccountHandler, roundNotifierInstance, chainHandler, + gasPriceModifier, ) if err != nil { return nil, err } return &VMTestContext{ - TxProcessor: res.TxProc, - ScProcessor: res.SCProc, - Accounts: accounts, - BlockchainHook: blockchainHook, - VMContainer: vmContainer, - TxFeeHandler: feeAccumulator, - ScForwarder: res.IntermediateTxProc, - ShardCoordinator: shardCoordinator, - EconomicsData: res.EconomicsHandler, - TxCostHandler: res.CostHandler, - TxsLogsProcessor: res.TxLogProc, - GasSchedule: gasScheduleNotifier, - EpochNotifier: epochNotifierInstance, - EnableEpochsHandler: enableEpochsHandler, - ChainHandler: chainHandler, - Marshalizer: integrationtests.TestMarshalizer, - GuardedAccountsHandler: guardedAccountHandler, + TxProcessor: res.TxProc, + ScProcessor: res.SCProc, + Accounts: accounts, + BlockchainHook: blockchainHook, + VMContainer: vmContainer, + TxFeeHandler: feeAccumulator, + ScForwarder: res.IntermediateTxProc, + ShardCoordinator: shardCoordinator, + EconomicsData: res.EconomicsHandler, + TxCostHandler: res.CostHandler, + TxsLogsProcessor: res.TxLogProc, + FailedTxLogsAccumulator: res.FailedTxLogsAccumulator, + GasSchedule: gasScheduleNotifier, + EpochNotifier: epochNotifierInstance, + EnableEpochsHandler: enableEpochsHandler, + ChainHandler: chainHandler, + Marshalizer: integrationtests.TestMarshalizer, + GuardedAccountsHandler: guardedAccountHandler, }, nil } @@ -1387,6 +1421,7 @@ func CreateTxProcessorArwenVMWithGasScheduleAndRoundConfig( guardedAccountHandler, roundNotifierInstance, chainHandler, + 1, ) if err != nil { return nil, err @@ -1469,6 +1504,7 @@ func CreateTxProcessorArwenWithVMConfigAndRoundConfig( guardedAccountHandler, roundNotifierInstance, chainHandler, + 1, ) if err != nil { return nil, err @@ -1836,13 +1872,13 @@ func GetNodeIndex(nodeList []*integrationTests.TestProcessorNode, node *integrat } // CreatePreparedTxProcessorWithVMsMultiShard - -func CreatePreparedTxProcessorWithVMsMultiShard(selfShardID uint32, enableEpochsConfig config.EnableEpochs) (*VMTestContext, error) { - return CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(selfShardID, enableEpochsConfig, testscommon.GetDefaultRoundsConfig()) +func CreatePreparedTxProcessorWithVMsMultiShard(selfShardID uint32, enableEpochsConfig config.EnableEpochs, gasPriceModifier float64) (*VMTestContext, error) { + return CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(selfShardID, enableEpochsConfig, testscommon.GetDefaultRoundsConfig(), gasPriceModifier) } // CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig - -func CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(selfShardID uint32, enableEpochsConfig config.EnableEpochs, roundsConfig config.RoundConfig) (*VMTestContext, error) { - return CreatePreparedTxProcessorWithVMsMultiShardRoundVMConfig(selfShardID, enableEpochsConfig, roundsConfig, createDefaultVMConfig()) +func CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(selfShardID uint32, enableEpochsConfig config.EnableEpochs, roundsConfig config.RoundConfig, gasPriceModifier float64) (*VMTestContext, error) { + return CreatePreparedTxProcessorWithVMsMultiShardRoundVMConfig(selfShardID, enableEpochsConfig, roundsConfig, createDefaultVMConfig(), gasPriceModifier) } // CreatePreparedTxProcessorWithVMsMultiShardRoundVMConfig - @@ -1851,6 +1887,7 @@ func CreatePreparedTxProcessorWithVMsMultiShardRoundVMConfig( enableEpochsConfig config.EnableEpochs, roundsConfig config.RoundConfig, vmConfig *config.VirtualMachineConfig, + gasPriceModifier float64, ) (*VMTestContext, error) { shardCoordinator, _ := sharding.NewMultiShardCoordinator(3, selfShardID) @@ -1900,27 +1937,29 @@ func CreatePreparedTxProcessorWithVMsMultiShardRoundVMConfig( guardedAccountHandler, roundNotifierInstance, chainHandler, + gasPriceModifier, ) if err != nil { return nil, err } return &VMTestContext{ - TxProcessor: res.TxProc, - ScProcessor: res.SCProc, - Accounts: accounts, - BlockchainHook: blockchainHook, - VMContainer: vmContainer, - TxFeeHandler: feeAccumulator, - ShardCoordinator: shardCoordinator, - ScForwarder: res.IntermediateTxProc, - EconomicsData: res.EconomicsHandler, - Marshalizer: integrationtests.TestMarshalizer, - TxsLogsProcessor: res.TxLogProc, - EpochNotifier: epochNotifierInstance, - EnableEpochsHandler: enableEpochsHandler, - ChainHandler: chainHandler, - GuardedAccountsHandler: guardedAccountHandler, + TxProcessor: res.TxProc, + ScProcessor: res.SCProc, + Accounts: accounts, + BlockchainHook: blockchainHook, + VMContainer: vmContainer, + TxFeeHandler: feeAccumulator, + ShardCoordinator: shardCoordinator, + ScForwarder: res.IntermediateTxProc, + EconomicsData: res.EconomicsHandler, + Marshalizer: integrationtests.TestMarshalizer, + TxsLogsProcessor: res.TxLogProc, + FailedTxLogsAccumulator: res.FailedTxLogsAccumulator, + EpochNotifier: epochNotifierInstance, + EnableEpochsHandler: enableEpochsHandler, + ChainHandler: chainHandler, + GuardedAccountsHandler: guardedAccountHandler, }, nil } diff --git a/integrationTests/vm/txsFee/apiTransactionEvaluator_test.go b/integrationTests/vm/txsFee/apiTransactionEvaluator_test.go index 56551737de5..8f3894aa319 100644 --- a/integrationTests/vm/txsFee/apiTransactionEvaluator_test.go +++ b/integrationTests/vm/txsFee/apiTransactionEvaluator_test.go @@ -30,7 +30,7 @@ func TestSCCallCostTransactionCost(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -55,7 +55,7 @@ func TestScDeployTransactionCost(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -75,7 +75,7 @@ func TestAsyncCallsTransactionCost(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -109,7 +109,7 @@ func TestBuiltInFunctionTransactionCost(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs( config.EnableEpochs{ PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -132,7 +132,7 @@ func TestESDTTransfer(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -157,7 +157,7 @@ func TestAsyncESDTTransfer(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/asyncCall_multi_test.go b/integrationTests/vm/txsFee/asyncCall_multi_test.go index 24cf1f14750..56a6dc02a26 100644 --- a/integrationTests/vm/txsFee/asyncCall_multi_test.go +++ b/integrationTests/vm/txsFee/asyncCall_multi_test.go @@ -24,7 +24,7 @@ func TestAsyncCallLegacy(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -71,7 +71,7 @@ func TestAsyncCallMulti(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -122,7 +122,7 @@ func TestAsyncCallTransferAndExecute(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -183,7 +183,7 @@ func TestAsyncCallTransferESDTAndExecute_Success(t *testing.T) { } func transferESDTAndExecute(t *testing.T, numberOfCallsFromParent int, numberOfBackTransfers int) { - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -297,15 +297,15 @@ func TestAsyncCallMulti_CrossShard(t *testing.T) { t.Skip("this is not a short test") } - testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextFirstContract.Close() - testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextSecondContract.Close() - testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}) + testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextSender.Close() @@ -387,15 +387,15 @@ func TestAsyncCallTransferAndExecute_CrossShard(t *testing.T) { t.Skip("this is not a short test") } - childShard, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + childShard, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer childShard.Close() - forwarderShard, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + forwarderShard, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer forwarderShard.Close() - testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}) + testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextSender.Close() @@ -479,15 +479,15 @@ func TestAsyncCallTransferESDTAndExecute_CrossShard_Success(t *testing.T) { } func transferESDTAndExecuteCrossShard(t *testing.T, numberOfCallsFromParent int, numberOfBackTransfers int) { - vaultShard, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + vaultShard, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer vaultShard.Close() - forwarderShard, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + forwarderShard, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer forwarderShard.Close() - testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}) + testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextSender.Close() diff --git a/integrationTests/vm/txsFee/asyncCall_test.go b/integrationTests/vm/txsFee/asyncCall_test.go index 19a966e2fa8..88057f564a7 100644 --- a/integrationTests/vm/txsFee/asyncCall_test.go +++ b/integrationTests/vm/txsFee/asyncCall_test.go @@ -33,7 +33,7 @@ func TestAsyncCallShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -94,7 +94,7 @@ func TestMinterContractWithAsyncCalls(t *testing.T) { gasMap[common.MaxPerTransaction]["MaxBuiltInCallsPerTx"] = 199 gasMap[common.MaxPerTransaction]["MaxNumberOfTransfersPerTx"] = 100000 gasMap[common.MaxPerTransaction]["MaxNumberOfTrieReadsPerTx"] = 100000 - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -202,6 +202,7 @@ func testAsyncCallsOnInitFunctionOnUpgrade( gasScheduleNotifier, testscommon.GetDefaultRoundsConfig(), vm.CreateVMConfigWithVersion("v1.4"), + 1, ) require.Nil(t, err) testContextShardMeta, err := vm.CreatePreparedTxProcessorWithVMConfigWithShardCoordinatorDBAndGasAndRoundConfig( @@ -211,6 +212,7 @@ func testAsyncCallsOnInitFunctionOnUpgrade( gasScheduleNotifier, testscommon.GetDefaultRoundsConfig(), vm.CreateVMConfigWithVersion("v1.4"), + 1, ) require.Nil(t, err) @@ -340,6 +342,7 @@ func testAsyncCallsOnInitFunctionOnDeploy(t *testing.T, gasScheduleNotifier, testscommon.GetDefaultRoundsConfig(), vm.CreateVMConfigWithVersion("v1.4"), + 1, ) require.Nil(t, err) testContextShardMeta, err := vm.CreatePreparedTxProcessorWithVMConfigWithShardCoordinatorDBAndGasAndRoundConfig( @@ -349,6 +352,7 @@ func testAsyncCallsOnInitFunctionOnDeploy(t *testing.T, gasScheduleNotifier, testscommon.GetDefaultRoundsConfig(), vm.CreateVMConfigWithVersion("v1.4"), + 1, ) require.Nil(t, err) diff --git a/integrationTests/vm/txsFee/asyncESDT_test.go b/integrationTests/vm/txsFee/asyncESDT_test.go index 4476a79511d..c7c8d088fb9 100644 --- a/integrationTests/vm/txsFee/asyncESDT_test.go +++ b/integrationTests/vm/txsFee/asyncESDT_test.go @@ -27,7 +27,7 @@ func TestAsyncESDTCallShouldWork(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -83,7 +83,7 @@ func TestAsyncESDTCallSecondScRefusesPayment(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -140,7 +140,7 @@ func TestAsyncESDTCallsOutOfGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -198,7 +198,7 @@ func TestAsyncMultiTransferOnCallback(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -295,7 +295,7 @@ func TestAsyncMultiTransferOnCallAndOnCallback(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -399,7 +399,7 @@ func TestSendNFTToContractWith0Function(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -452,7 +452,7 @@ func TestSendNFTToContractWith0FunctionNonPayable(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -506,7 +506,7 @@ func TestAsyncESDTCallForThirdContractShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/backwardsCompatibility_test.go b/integrationTests/vm/txsFee/backwardsCompatibility_test.go index 2b160d342cd..424594c6754 100644 --- a/integrationTests/vm/txsFee/backwardsCompatibility_test.go +++ b/integrationTests/vm/txsFee/backwardsCompatibility_test.go @@ -26,7 +26,7 @@ func TestMoveBalanceSelfShouldWorkAndConsumeTxFeeWhenAllFlagsAreDisabled(t *test SCDeployEnableEpoch: 100, MetaProtectionEnableEpoch: 100, RelayedTransactionsEnableEpoch: 100, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -71,7 +71,7 @@ func TestMoveBalanceAllFlagsDisabledLessBalanceThanGasLimitMulGasPrice(t *testin SCDeployEnableEpoch: integrationTests.UnreachableEpoch, MetaProtectionEnableEpoch: integrationTests.UnreachableEpoch, RelayedTransactionsEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -99,7 +99,7 @@ func TestMoveBalanceSelfShouldWorkAndConsumeTxFeeWhenSomeFlagsAreDisabled(t *tes SCDeployEnableEpoch: 100, MetaProtectionEnableEpoch: 100, RelayedTransactionsV2EnableEpoch: 100, - }) + }, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/builtInFunctions_test.go b/integrationTests/vm/txsFee/builtInFunctions_test.go index 4ac02c62661..0c7c1f7cdf3 100644 --- a/integrationTests/vm/txsFee/builtInFunctions_test.go +++ b/integrationTests/vm/txsFee/builtInFunctions_test.go @@ -32,11 +32,11 @@ func TestBuildInFunctionChangeOwnerCallShouldWorkV1(t *testing.T) { config.EnableEpochs{ PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, SCProcessorV2EnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) utils.CleanAccumulatedIntermediateTransactions(t, testContext) @@ -73,11 +73,11 @@ func TestBuildInFunctionChangeOwnerCallShouldWork(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs( config.EnableEpochs{ PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) utils.CleanAccumulatedIntermediateTransactions(t, testContext) @@ -111,11 +111,11 @@ func TestBuildInFunctionChangeOwnerCallWrongOwnerShouldConsumeGas(t *testing.T) t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, initialOwner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, initialOwner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) utils.CleanAccumulatedIntermediateTransactions(t, testContext) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) @@ -152,11 +152,11 @@ func TestBuildInFunctionChangeOwnerInvalidAddressShouldConsumeGas(t *testing.T) t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) utils.CleanAccumulatedIntermediateTransactions(t, testContext) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) @@ -190,11 +190,11 @@ func TestBuildInFunctionChangeOwnerCallInsufficientGasLimitShouldNotConsumeGas(t t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) newOwner := []byte("12345678901234567890123456789112") @@ -230,11 +230,11 @@ func TestBuildInFunctionChangeOwnerOutOfGasShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) utils.CleanAccumulatedIntermediateTransactions(t, testContext) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) @@ -275,7 +275,7 @@ func TestBuildInFunctionSaveKeyValue_WrongDestination(t *testing.T) { config.EnableEpochs{ CleanUpInformativeSCRsEnableEpoch: integrationTests.UnreachableEpoch, SCProcessorV2EnableEpoch: integrationTests.UnreachableEpoch, - }, shardCoord) + }, shardCoord, 1) require.Nil(t, err) defer testContext.Close() @@ -313,7 +313,7 @@ func TestBuildInFunctionSaveKeyValue_NotEnoughGasFor3rdSave(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinator( config.EnableEpochs{ BackwardCompSaveKeyValueEnableEpoch: 5, - }, shardCoord) + }, shardCoord, 1) require.Nil(t, err) defer testContext.Close() @@ -356,6 +356,7 @@ func TestBuildInFunctionSaveKeyValue_NotEnoughGasForTheSameKeyValue(t *testing.T gasScheduleNotifier, testscommon.GetDefaultRoundsConfig(), vm.CreateVMConfigWithVersion("v1.5"), + 1, ) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/common.go b/integrationTests/vm/txsFee/common.go index 9f6574aca1d..774af8202d2 100644 --- a/integrationTests/vm/txsFee/common.go +++ b/integrationTests/vm/txsFee/common.go @@ -15,7 +15,11 @@ import ( "github.com/stretchr/testify/require" ) -const gasPrice = uint64(10) +const ( + gasPrice = uint64(10) + minGasLimit = uint64(1) + gasPriceModifier = float64(0.1) +) // MetaData defines test meta data struct type MetaData struct { diff --git a/integrationTests/vm/txsFee/dns_test.go b/integrationTests/vm/txsFee/dns_test.go index 0ff3914d7a0..c8787d99db5 100644 --- a/integrationTests/vm/txsFee/dns_test.go +++ b/integrationTests/vm/txsFee/dns_test.go @@ -31,7 +31,7 @@ func TestDeployDNSContract_TestRegisterAndResolveAndSendTxWithSndAndRcvUserName( testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ DynamicGasCostForDataTrieStorageLoadEnableEpoch: 10, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -131,6 +131,7 @@ func TestDeployDNSContract_TestGasWhenSaveUsernameFailsCrossShardBackwardsCompat enableEpochs, testscommon.GetDefaultRoundsConfig(), vmConfig, + 1, ) require.Nil(t, err) defer testContextForDNSContract.Close() @@ -140,6 +141,7 @@ func TestDeployDNSContract_TestGasWhenSaveUsernameFailsCrossShardBackwardsCompat enableEpochs, testscommon.GetDefaultRoundsConfig(), vmConfig, + 1, ) require.Nil(t, err) defer testContextForRelayerAndUser.Close() @@ -200,11 +202,13 @@ func TestDeployDNSContract_TestGasWhenSaveUsernameAfterDNSv2IsActivated(t *testi t.Skip("this is not a short test") } - testContextForDNSContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContextForDNSContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: integrationTests.UnreachableEpoch, + }, 1) require.Nil(t, err) defer testContextForDNSContract.Close() - testContextForRelayerAndUser, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}) + testContextForRelayerAndUser, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextForRelayerAndUser.Close() scAddress, _ := utils.DoDeployDNS(t, testContextForDNSContract, "../../multiShard/smartContract/dns/dns.wasm") diff --git a/integrationTests/vm/txsFee/dynamicGasCost_test.go b/integrationTests/vm/txsFee/dynamicGasCost_test.go index e1fca367f3f..08edae2af13 100644 --- a/integrationTests/vm/txsFee/dynamicGasCost_test.go +++ b/integrationTests/vm/txsFee/dynamicGasCost_test.go @@ -29,7 +29,7 @@ func TestDynamicGasCostForDataTrieStorageLoad(t *testing.T) { shardCoordinator, _ := sharding.NewMultiShardCoordinator(3, 1) gasScheduleNotifier := vm.CreateMockGasScheduleNotifier() - testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGas(enableEpochs, shardCoordinator, integrationTests.CreateMemUnit(), gasScheduleNotifier) + testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGas(enableEpochs, shardCoordinator, integrationTests.CreateMemUnit(), gasScheduleNotifier, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/esdtLocalBurn_test.go b/integrationTests/vm/txsFee/esdtLocalBurn_test.go index 29c4fc26320..681c7e293b4 100644 --- a/integrationTests/vm/txsFee/esdtLocalBurn_test.go +++ b/integrationTests/vm/txsFee/esdtLocalBurn_test.go @@ -18,7 +18,7 @@ func TestESDTLocalBurnShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -52,7 +52,7 @@ func TestESDTLocalBurnMoreThanTotalBalanceShouldErr(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -86,7 +86,7 @@ func TestESDTLocalBurnNotAllowedShouldErr(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/esdtLocalMint_test.go b/integrationTests/vm/txsFee/esdtLocalMint_test.go index f2104f4c341..516402c80a4 100644 --- a/integrationTests/vm/txsFee/esdtLocalMint_test.go +++ b/integrationTests/vm/txsFee/esdtLocalMint_test.go @@ -18,7 +18,7 @@ func TestESDTLocalMintShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -52,7 +52,7 @@ func TestESDTLocalMintNotAllowedShouldErr(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/esdtMetaDataRecreate_test.go b/integrationTests/vm/txsFee/esdtMetaDataRecreate_test.go index d980ed816d7..8e46c5d613b 100644 --- a/integrationTests/vm/txsFee/esdtMetaDataRecreate_test.go +++ b/integrationTests/vm/txsFee/esdtMetaDataRecreate_test.go @@ -28,11 +28,11 @@ func TestESDTMetaDataRecreate(t *testing.T) { func runEsdtMetaDataRecreateTest(t *testing.T, tokenType string) { sndAddr := []byte("12345678901234567890123456789012") token := []byte("tokenId") - roles := [][]byte{[]byte(core.ESDTMetaDataRecreate), []byte(core.ESDTRoleNFTCreate)} + roles := [][]byte{[]byte(core.ESDTRoleNFTRecreate), []byte(core.ESDTRoleNFTCreate)} baseEsdtKeyPrefix := core.ProtectedKeyPrefix + core.ESDTKeyIdentifier key := append([]byte(baseEsdtKeyPrefix), token...) - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/esdtMetaDataUpdate_test.go b/integrationTests/vm/txsFee/esdtMetaDataUpdate_test.go index ea5ec910c97..53174e22a35 100644 --- a/integrationTests/vm/txsFee/esdtMetaDataUpdate_test.go +++ b/integrationTests/vm/txsFee/esdtMetaDataUpdate_test.go @@ -32,7 +32,7 @@ func runEsdtMetaDataUpdateTest(t *testing.T, tokenType string) { baseEsdtKeyPrefix := core.ProtectedKeyPrefix + core.ESDTKeyIdentifier key := append([]byte(baseEsdtKeyPrefix), token...) - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/esdtModifyCreator_test.go b/integrationTests/vm/txsFee/esdtModifyCreator_test.go index 1aa80ffd5c3..ead51c5d61d 100644 --- a/integrationTests/vm/txsFee/esdtModifyCreator_test.go +++ b/integrationTests/vm/txsFee/esdtModifyCreator_test.go @@ -36,7 +36,7 @@ func runEsdtModifyCreatorTest(t *testing.T, tokenType string) { baseEsdtKeyPrefix := core.ProtectedKeyPrefix + core.ESDTKeyIdentifier key := append([]byte(baseEsdtKeyPrefix), token...) - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/esdtModifyRoyalties_test.go b/integrationTests/vm/txsFee/esdtModifyRoyalties_test.go index fd4b9c84880..f4ef7dc9f49 100644 --- a/integrationTests/vm/txsFee/esdtModifyRoyalties_test.go +++ b/integrationTests/vm/txsFee/esdtModifyRoyalties_test.go @@ -31,7 +31,7 @@ func runEsdtModifyRoyaltiesTest(t *testing.T, tokenType string) { baseEsdtKeyPrefix := core.ProtectedKeyPrefix + core.ESDTKeyIdentifier key := append([]byte(baseEsdtKeyPrefix), token...) - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/esdtSetNewURIs_test.go b/integrationTests/vm/txsFee/esdtSetNewURIs_test.go index 2354f4b9625..66ec209c3ef 100644 --- a/integrationTests/vm/txsFee/esdtSetNewURIs_test.go +++ b/integrationTests/vm/txsFee/esdtSetNewURIs_test.go @@ -32,7 +32,7 @@ func runEsdtSetNewURIsTest(t *testing.T, tokenType string) { baseEsdtKeyPrefix := core.ProtectedKeyPrefix + core.ESDTKeyIdentifier key := append([]byte(baseEsdtKeyPrefix), token...) - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/esdt_test.go b/integrationTests/vm/txsFee/esdt_test.go index 07871a87750..d51848762e8 100644 --- a/integrationTests/vm/txsFee/esdt_test.go +++ b/integrationTests/vm/txsFee/esdt_test.go @@ -22,7 +22,7 @@ func TestESDTTransferShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -62,7 +62,7 @@ func TestESDTTransferShouldWorkToMuchGasShouldConsumeAllGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -102,7 +102,7 @@ func TestESDTTransferInvalidESDTValueShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -143,7 +143,7 @@ func TestESDTTransferCallBackOnErrorShouldNotGenerateSCRsFurther(t *testing.T) { } shardC, _ := sharding.NewMultiShardCoordinator(2, 0) - testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinator(config.EnableEpochs{}, shardC) + testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinator(config.EnableEpochs{}, shardC, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/guardAccount_test.go b/integrationTests/vm/txsFee/guardAccount_test.go index 6ccde4df164..52a64322bb1 100644 --- a/integrationTests/vm/txsFee/guardAccount_test.go +++ b/integrationTests/vm/txsFee/guardAccount_test.go @@ -97,11 +97,13 @@ func prepareTestContextForGuardedAccounts(tb testing.TB) *vm.VMTestContext { GovernanceEnableEpoch: unreachableEpoch, SetSenderInEeiOutputTransferEnableEpoch: unreachableEpoch, RefactorPeersMiniBlocksEnableEpoch: unreachableEpoch, + FixRelayedBaseCostEnableEpoch: unreachableEpoch, }, testscommon.NewMultiShardsCoordinatorMock(2), db, gasScheduleNotifier, testscommon.GetDefaultRoundsConfig(), + 1, ) require.Nil(tb, err) @@ -977,7 +979,7 @@ func TestGuardAccounts_RelayedTransactionV1(t *testing.T) { alice, david, gasPrice, - transferGas+guardianSigVerificationGas, + 1+guardianSigVerificationGas, make([]byte, 0)) userTx.GuardianAddr = bob @@ -985,7 +987,7 @@ func TestGuardAccounts_RelayedTransactionV1(t *testing.T) { userTx.Version = txWithOptionVersion rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + transferGas + guardianSigVerificationGas + uint64(len(rtxData)) + rTxGasLimit := minGasLimit + guardianSigVerificationGas + minGasLimit + uint64(len(rtxData)) rtx := vm.CreateTransaction(getNonce(testContext, charlie), big.NewInt(0), charlie, alice, gasPrice, rTxGasLimit, rtxData) returnCode, err = testContext.TxProcessor.ProcessTransaction(rtx) require.Nil(t, err) @@ -1016,13 +1018,13 @@ func TestGuardAccounts_RelayedTransactionV1(t *testing.T) { alice, david, gasPrice, - transferGas+guardianSigVerificationGas, + minGasLimit, make([]byte, 0)) userTx.Version = txWithOptionVersion rtxData = integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit = 1 + transferGas + guardianSigVerificationGas + uint64(len(rtxData)) + rTxGasLimit = minGasLimit + minGasLimit + uint64(len(rtxData)) rtx = vm.CreateTransaction(getNonce(testContext, charlie), big.NewInt(0), charlie, alice, gasPrice, rTxGasLimit, rtxData) returnCode, err = testContext.TxProcessor.ProcessTransaction(rtx) require.Nil(t, err) @@ -1095,14 +1097,14 @@ func TestGuardAccounts_RelayedTransactionV2(t *testing.T) { testContext.CleanIntermediateTransactions(t) // step 3 - charlie sends a relayed transaction v1 on the behalf of alice - // 3.1 cosigned transaction should work + // 3.1 cosigned transaction should not work userTx := vm.CreateTransaction( getNonce(testContext, alice), transferValue, alice, david, gasPrice, - transferGas+guardianSigVerificationGas, + 1+guardianSigVerificationGas, make([]byte, 0)) userTx.GuardianAddr = bob @@ -1110,7 +1112,7 @@ func TestGuardAccounts_RelayedTransactionV2(t *testing.T) { userTx.Version = txWithOptionVersion rtxData := integrationTests.PrepareRelayedTxDataV2(userTx) - rTxGasLimit := 1 + transferGas + guardianSigVerificationGas + uint64(len(rtxData)) + rTxGasLimit := minGasLimit + guardianSigVerificationGas + minGasLimit + uint64(len(rtxData)) rtx := vm.CreateTransaction(getNonce(testContext, charlie), big.NewInt(0), charlie, alice, gasPrice, rTxGasLimit, rtxData) returnCode, err = testContext.TxProcessor.ProcessTransaction(rtx) require.Nil(t, err) @@ -1129,7 +1131,8 @@ func TestGuardAccounts_RelayedTransactionV2(t *testing.T) { assert.Equal(t, aliceCurrentBalance, getBalance(testContext, alice)) bobExpectedBalance := big.NewInt(0).Set(initialMint) assert.Equal(t, bobExpectedBalance, getBalance(testContext, bob)) - charlieExpectedBalance := big.NewInt(0).Sub(initialMint, big.NewInt(int64(rTxGasLimit*gasPrice))) + charlieConsumed := minGasLimit + guardianSigVerificationGas + minGasLimit + uint64(len(rtxData)) + charlieExpectedBalance := big.NewInt(0).Sub(initialMint, big.NewInt(int64(charlieConsumed*gasPrice))) assert.Equal(t, charlieExpectedBalance, getBalance(testContext, charlie)) assert.Equal(t, initialMint, getBalance(testContext, david)) @@ -1143,13 +1146,13 @@ func TestGuardAccounts_RelayedTransactionV2(t *testing.T) { alice, david, gasPrice, - transferGas+guardianSigVerificationGas, + minGasLimit, make([]byte, 0)) userTx.Version = txWithOptionVersion rtxData = integrationTests.PrepareRelayedTxDataV2(userTx) - rTxGasLimit = 1 + transferGas + guardianSigVerificationGas + uint64(len(rtxData)) + rTxGasLimit = minGasLimit + minGasLimit + uint64(len(rtxData)) rtx = vm.CreateTransaction(getNonce(testContext, charlie), big.NewInt(0), charlie, alice, gasPrice, rTxGasLimit, rtxData) returnCode, err = testContext.TxProcessor.ProcessTransaction(rtx) require.Nil(t, err) diff --git a/integrationTests/vm/txsFee/migrateDataTrie_test.go b/integrationTests/vm/txsFee/migrateDataTrie_test.go index 02eecc0e1c3..d089be8fc14 100644 --- a/integrationTests/vm/txsFee/migrateDataTrie_test.go +++ b/integrationTests/vm/txsFee/migrateDataTrie_test.go @@ -45,7 +45,7 @@ func TestMigrateDataTrieBuiltInFunc(t *testing.T) { t.Run("deterministic trie", func(t *testing.T) { t.Parallel() - testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGas(enableEpochs, shardCoordinator, integrationTests.CreateMemUnit(), gasScheduleNotifier) + testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGas(enableEpochs, shardCoordinator, integrationTests.CreateMemUnit(), gasScheduleNotifier, 1) require.Nil(t, err) defer testContext.Close() @@ -123,7 +123,7 @@ func TestMigrateDataTrieBuiltInFunc(t *testing.T) { t.Run("random trie - all leaves are migrated in multiple transactions", func(t *testing.T) { t.Parallel() - testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGas(enableEpochs, shardCoordinator, integrationTests.CreateMemUnit(), gasScheduleNotifier) + testContext, err := vm.CreatePreparedTxProcessorWithVMsWithShardCoordinatorDBAndGas(enableEpochs, shardCoordinator, integrationTests.CreateMemUnit(), gasScheduleNotifier, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/moveBalance_test.go b/integrationTests/vm/txsFee/moveBalance_test.go index 28907f5a2c6..8e847dba20b 100644 --- a/integrationTests/vm/txsFee/moveBalance_test.go +++ b/integrationTests/vm/txsFee/moveBalance_test.go @@ -22,7 +22,7 @@ func TestMoveBalanceSelfShouldWorkAndConsumeTxFee(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -61,7 +61,7 @@ func TestMoveBalanceAllFlagsEnabledLessBalanceThanGasLimitMulGasPrice(t *testing t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -82,7 +82,7 @@ func TestMoveBalanceShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -126,7 +126,7 @@ func TestMoveBalanceInvalidHasGasButNoValueShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -159,7 +159,7 @@ func TestMoveBalanceHigherNonceShouldNotConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -193,7 +193,7 @@ func TestMoveBalanceMoreGasThanGasLimitPerMiniBlockForSafeCrossShard(t *testing. t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -228,7 +228,7 @@ func TestMoveBalanceInvalidUserNames(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/multiESDTTransfer_test.go b/integrationTests/vm/txsFee/multiESDTTransfer_test.go index c85a1a2bc1b..adaf89ad340 100644 --- a/integrationTests/vm/txsFee/multiESDTTransfer_test.go +++ b/integrationTests/vm/txsFee/multiESDTTransfer_test.go @@ -19,7 +19,7 @@ func TestMultiESDTTransferShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -80,7 +80,7 @@ func TestMultiESDTTransferFailsBecauseOfMaxLimit(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMsAndCustomGasSchedule(config.EnableEpochs{}, func(gasMap wasmConfig.GasScheduleMap) { gasMap[common.MaxPerTransaction]["MaxNumberOfTransfersPerTx"] = 1 - }) + }, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/multiShard/asyncCallWithChangeOwner_test.go b/integrationTests/vm/txsFee/multiShard/asyncCallWithChangeOwner_test.go index 28130046e11..573370bab26 100644 --- a/integrationTests/vm/txsFee/multiShard/asyncCallWithChangeOwner_test.go +++ b/integrationTests/vm/txsFee/multiShard/asyncCallWithChangeOwner_test.go @@ -25,7 +25,7 @@ func TestDoChangeOwnerCrossShardFromAContract(t *testing.T) { ChangeOwnerAddressCrossShardThroughSCEnableEpoch: 0, } - testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs) + testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs, 1) require.Nil(t, err) defer testContextSource.Close() @@ -42,7 +42,7 @@ func TestDoChangeOwnerCrossShardFromAContract(t *testing.T) { require.Equal(t, uint32(0), testContextSource.ShardCoordinator.ComputeId(firstContract)) require.Equal(t, uint32(0), testContextSource.ShardCoordinator.ComputeId(firstOwner)) - testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs) + testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs, 1) require.Nil(t, err) defer testContextSecondContract.Close() diff --git a/integrationTests/vm/txsFee/multiShard/asyncCall_test.go b/integrationTests/vm/txsFee/multiShard/asyncCall_test.go index e6e7fe5ce6e..c02aed11578 100644 --- a/integrationTests/vm/txsFee/multiShard/asyncCall_test.go +++ b/integrationTests/vm/txsFee/multiShard/asyncCall_test.go @@ -23,15 +23,15 @@ func TestAsyncCallShouldWork(t *testing.T) { DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, } - testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs) + testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs, 1) require.Nil(t, err) defer testContextFirstContract.Close() - testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs) + testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs, 1) require.Nil(t, err) defer testContextSecondContract.Close() - testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, enableEpochs) + testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, enableEpochs, 1) require.Nil(t, err) defer testContextSender.Close() @@ -131,15 +131,15 @@ func TestAsyncCallDisabled(t *testing.T) { activationRound.Round = "0" roundsConfig.RoundActivations["DisableAsyncCallV1"] = activationRound - testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(0, enableEpochs, roundsConfig) + testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(0, enableEpochs, roundsConfig, 1) require.Nil(t, err) defer testContextFirstContract.Close() - testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(1, enableEpochs, roundsConfig) + testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(1, enableEpochs, roundsConfig, 1) require.Nil(t, err) defer testContextSecondContract.Close() - testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(2, enableEpochs, roundsConfig) + testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShardAndRoundConfig(2, enableEpochs, roundsConfig, 1) require.Nil(t, err) defer testContextSender.Close() diff --git a/integrationTests/vm/txsFee/multiShard/asyncESDT_test.go b/integrationTests/vm/txsFee/multiShard/asyncESDT_test.go index 21a894662a7..aa37bc6bf94 100644 --- a/integrationTests/vm/txsFee/multiShard/asyncESDT_test.go +++ b/integrationTests/vm/txsFee/multiShard/asyncESDT_test.go @@ -22,15 +22,15 @@ func TestAsyncESDTTransferWithSCCallShouldWork(t *testing.T) { DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, } - testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs) + testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs, 1) require.Nil(t, err) defer testContextSender.Close() - testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs) + testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs, 1) require.Nil(t, err) defer testContextFirstContract.Close() - testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, enableEpochs) + testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, enableEpochs, 1) require.Nil(t, err) defer testContextSecondContract.Close() @@ -138,15 +138,15 @@ func TestAsyncESDTTransferWithSCCallSecondContractAnotherToken(t *testing.T) { DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, } - testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs) + testContextSender, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs, 1) require.Nil(t, err) defer testContextSender.Close() - testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs) + testContextFirstContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs, 1) require.Nil(t, err) defer testContextFirstContract.Close() - testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, enableEpochs) + testContextSecondContract, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, enableEpochs, 1) require.Nil(t, err) defer testContextSecondContract.Close() diff --git a/integrationTests/vm/txsFee/multiShard/builtInFunctions_test.go b/integrationTests/vm/txsFee/multiShard/builtInFunctions_test.go index fd0232072c2..b8aff559fbc 100644 --- a/integrationTests/vm/txsFee/multiShard/builtInFunctions_test.go +++ b/integrationTests/vm/txsFee/multiShard/builtInFunctions_test.go @@ -41,7 +41,8 @@ func TestBuiltInFunctionExecuteOnSourceAndDestinationShouldWork(t *testing.T) { config.EnableEpochs{ PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, + 1) require.Nil(t, err) defer testContextSource.Close() @@ -50,7 +51,8 @@ func TestBuiltInFunctionExecuteOnSourceAndDestinationShouldWork(t *testing.T) { config.EnableEpochs{ PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, + 1) require.Nil(t, err) defer testContextDst.Close() diff --git a/integrationTests/vm/txsFee/multiShard/esdtLiquidity_test.go b/integrationTests/vm/txsFee/multiShard/esdtLiquidity_test.go index 036c17d9cef..6d2fe8cfa00 100644 --- a/integrationTests/vm/txsFee/multiShard/esdtLiquidity_test.go +++ b/integrationTests/vm/txsFee/multiShard/esdtLiquidity_test.go @@ -25,11 +25,11 @@ func TestSystemAccountLiquidityAfterCrossShardTransferAndBurn(t *testing.T) { tokenID := []byte("MYNFT") sh0Addr := []byte("12345678901234567890123456789010") sh1Addr := []byte("12345678901234567890123456789011") - sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer sh0Context.Close() - sh1Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + sh1Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer sh1Context.Close() _, _ = vm.CreateAccount(sh1Context.Accounts, sh1Addr, 0, big.NewInt(1000000000)) @@ -77,11 +77,11 @@ func TestSystemAccountLiquidityAfterNFTWipe(t *testing.T) { tokenID := []byte("MYNFT-0a0a0a") sh0Addr := bytes.Repeat([]byte{1}, 31) sh0Addr = append(sh0Addr, 0) - sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer sh0Context.Close() - metaContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(core.MetachainShardId, config.EnableEpochs{}) + metaContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(core.MetachainShardId, config.EnableEpochs{}, 1) require.Nil(t, err) defer metaContext.Close() @@ -127,11 +127,11 @@ func TestSystemAccountLiquidityAfterSFTWipe(t *testing.T) { tokenID := []byte("MYSFT-0a0a0a") sh0Addr := bytes.Repeat([]byte{1}, 31) sh0Addr = append(sh0Addr, 0) - sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer sh0Context.Close() - metaContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(core.MetachainShardId, config.EnableEpochs{}) + metaContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(core.MetachainShardId, config.EnableEpochs{}, 1) require.Nil(t, err) defer metaContext.Close() diff --git a/integrationTests/vm/txsFee/multiShard/esdt_test.go b/integrationTests/vm/txsFee/multiShard/esdt_test.go index 8f978daee1c..9dd828eb8c1 100644 --- a/integrationTests/vm/txsFee/multiShard/esdt_test.go +++ b/integrationTests/vm/txsFee/multiShard/esdt_test.go @@ -20,7 +20,7 @@ func TestESDTTransferShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -61,11 +61,11 @@ func TestMultiESDTNFTTransferViaRelayedV2(t *testing.T) { relayerSh0 := []byte("12345678901234567890123456789110") relayerSh1 := []byte("12345678901234567890123456789111") - sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer sh0Context.Close() - sh1Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + sh1Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer sh1Context.Close() _, _ = vm.CreateAccount(sh1Context.Accounts, sh1Addr, 0, big.NewInt(10000000000)) diff --git a/integrationTests/vm/txsFee/multiShard/moveBalance_test.go b/integrationTests/vm/txsFee/multiShard/moveBalance_test.go index 8c5f6bd6015..dcf42bce5b9 100644 --- a/integrationTests/vm/txsFee/multiShard/moveBalance_test.go +++ b/integrationTests/vm/txsFee/multiShard/moveBalance_test.go @@ -18,7 +18,7 @@ func TestMoveBalanceShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -57,7 +57,7 @@ func TestMoveBalanceContractAddressDataFieldNilShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -99,7 +99,7 @@ func TestMoveBalanceContractAddressDataFieldNotNilShouldConsumeGas(t *testing.T) t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -141,11 +141,11 @@ func TestMoveBalanceExecuteOneSourceAndDestinationShard(t *testing.T) { t.Skip("this is not a short test") } - testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextSource.Close() - testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextDst.Close() diff --git a/integrationTests/vm/txsFee/multiShard/nftTransferUpdate_test.go b/integrationTests/vm/txsFee/multiShard/nftTransferUpdate_test.go index 1fdd2f6f78f..4a15002f5c0 100644 --- a/integrationTests/vm/txsFee/multiShard/nftTransferUpdate_test.go +++ b/integrationTests/vm/txsFee/multiShard/nftTransferUpdate_test.go @@ -40,11 +40,11 @@ func TestNFTTransferAndUpdateOnOldTypeToken(t *testing.T) { initialAttribute := []byte("initial attribute") newAttribute := []byte("new attribute") - sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs) + sh0Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs, 1) require.Nil(t, err) defer sh0Context.Close() - sh1Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs) + sh1Context, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs, 1) require.Nil(t, err) defer sh1Context.Close() diff --git a/integrationTests/vm/txsFee/multiShard/relayedBuiltInFunctions_test.go b/integrationTests/vm/txsFee/multiShard/relayedBuiltInFunctions_test.go index e987d4dbc74..49a0e256483 100644 --- a/integrationTests/vm/txsFee/multiShard/relayedBuiltInFunctions_test.go +++ b/integrationTests/vm/txsFee/multiShard/relayedBuiltInFunctions_test.go @@ -23,7 +23,8 @@ func TestRelayedBuiltInFunctionExecuteOnRelayerAndDstShardShouldWork(t *testing. 2, config.EnableEpochs{ PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, + 1) require.Nil(t, err) defer testContextRelayer.Close() @@ -31,7 +32,8 @@ func TestRelayedBuiltInFunctionExecuteOnRelayerAndDstShardShouldWork(t *testing. 1, config.EnableEpochs{ PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, + 1) require.Nil(t, err) defer testContextInner.Close() diff --git a/integrationTests/vm/txsFee/multiShard/relayedMoveBalance_test.go b/integrationTests/vm/txsFee/multiShard/relayedMoveBalance_test.go index aa206c591b4..2d2013fd0e8 100644 --- a/integrationTests/vm/txsFee/multiShard/relayedMoveBalance_test.go +++ b/integrationTests/vm/txsFee/multiShard/relayedMoveBalance_test.go @@ -13,52 +13,68 @@ import ( "github.com/stretchr/testify/require" ) +const ( + minGasLimit = uint64(1) + gasPriceModifier = float64(0.1) +) + func TestRelayedMoveBalanceRelayerShard0InnerTxSenderAndReceiverShard1ShouldWork(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed base cost fix", testRelayedMoveBalanceRelayerShard0InnerTxSenderAndReceiverShard1ShouldWork(integrationTests.UnreachableEpoch)) +} + +func testRelayedMoveBalanceRelayerShard0InnerTxSenderAndReceiverShard1ShouldWork(relayedFixActivationEpoch uint32) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789030") - shardID := testContext.ShardCoordinator.ComputeId(relayerAddr) - require.Equal(t, uint32(0), shardID) + relayerAddr := []byte("12345678901234567890123456789030") + shardID := testContext.ShardCoordinator.ComputeId(relayerAddr) + require.Equal(t, uint32(0), shardID) - sndAddr := []byte("12345678901234567890123456789011") - shardID = testContext.ShardCoordinator.ComputeId(sndAddr) - require.Equal(t, uint32(1), shardID) + sndAddr := []byte("12345678901234567890123456789011") + shardID = testContext.ShardCoordinator.ComputeId(sndAddr) + require.Equal(t, uint32(1), shardID) - rcvAddr := []byte("12345678901234567890123456789021") - shardID = testContext.ShardCoordinator.ComputeId(rcvAddr) - require.Equal(t, uint32(1), shardID) + rcvAddr := []byte("12345678901234567890123456789021") + shardID = testContext.ShardCoordinator.ComputeId(rcvAddr) + require.Equal(t, uint32(1), shardID) - gasPrice := uint64(10) - gasLimit := uint64(100) + gasPrice := uint64(10) + gasLimit := uint64(100) - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, []byte("aaaa")) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(100)) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(3000)) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, []byte("aaaa")) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := gasLimit + minGasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) - // check balance inner tx sender - utils.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - // check balance inner tx receiver - utils.TestAccount(t, testContext.Accounts, rcvAddr, 0, big.NewInt(100)) + // check balance inner tx sender + utils.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(1000), accumulatedFees) + // check balance inner tx receiver + utils.TestAccount(t, testContext.Accounts, rcvAddr, 0, big.NewInt(100)) + + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, big.NewInt(100), accumulatedFees) + } } func TestRelayedMoveBalanceRelayerAndInnerTxSenderShard0ReceiverShard1(t *testing.T) { @@ -66,48 +82,56 @@ func TestRelayedMoveBalanceRelayerAndInnerTxSenderShard0ReceiverShard1(t *testin t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed base cost fix", testRelayedMoveBalanceRelayerAndInnerTxSenderShard0ReceiverShard1(integrationTests.UnreachableEpoch)) +} + +func testRelayedMoveBalanceRelayerAndInnerTxSenderShard0ReceiverShard1(relayedFixActivationEpoch uint32) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789030") - shardID := testContext.ShardCoordinator.ComputeId(relayerAddr) - require.Equal(t, uint32(0), shardID) + relayerAddr := []byte("12345678901234567890123456789030") + shardID := testContext.ShardCoordinator.ComputeId(relayerAddr) + require.Equal(t, uint32(0), shardID) - sndAddr := []byte("12345678901234567890123456789011") - shardID = testContext.ShardCoordinator.ComputeId(sndAddr) - require.Equal(t, uint32(1), shardID) + sndAddr := []byte("12345678901234567890123456789011") + shardID = testContext.ShardCoordinator.ComputeId(sndAddr) + require.Equal(t, uint32(1), shardID) - scAddress := "00000000000000000000dbb53e4b23392b0d6f36cce32deb2d623e9625ab3132" - scAddrBytes, _ := hex.DecodeString(scAddress) - scAddrBytes[31] = 1 - shardID = testContext.ShardCoordinator.ComputeId(scAddrBytes) - require.Equal(t, uint32(1), shardID) + scAddress := "00000000000000000000dbb53e4b23392b0d6f36cce32deb2d623e9625ab3132" + scAddrBytes, _ := hex.DecodeString(scAddress) + scAddrBytes[31] = 1 + shardID = testContext.ShardCoordinator.ComputeId(scAddrBytes) + require.Equal(t, uint32(1), shardID) - gasPrice := uint64(10) - gasLimit := uint64(100) + gasPrice := uint64(10) + gasLimit := uint64(100) - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddrBytes, gasPrice, gasLimit, nil) + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddrBytes, gasPrice, gasLimit, nil) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := gasLimit + minGasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) + require.Nil(t, err) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - // check inner tx receiver - account, err := testContext.Accounts.GetExistingAccount(scAddrBytes) - require.Nil(t, account) - require.NotNil(t, err) + // check inner tx receiver + account, err := testContext.Accounts.GetExistingAccount(scAddrBytes) + require.Nil(t, account) + require.NotNil(t, err) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(1000), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, big.NewInt(100), accumulatedFees) + } } func TestRelayedMoveBalanceExecuteOnSourceAndDestination(t *testing.T) { @@ -115,67 +139,79 @@ func TestRelayedMoveBalanceExecuteOnSourceAndDestination(t *testing.T) { t.Skip("this is not a short test") } - testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextSource.Close() - - testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextDst.Close() - - relayerAddr := []byte("12345678901234567890123456789030") - shardID := testContextSource.ShardCoordinator.ComputeId(relayerAddr) - require.Equal(t, uint32(0), shardID) - - sndAddr := []byte("12345678901234567890123456789011") - shardID = testContextSource.ShardCoordinator.ComputeId(sndAddr) - require.Equal(t, uint32(1), shardID) - - scAddress := "00000000000000000000dbb53e4b23392b0d6f36cce32deb2d623e9625ab3132" - scAddrBytes, _ := hex.DecodeString(scAddress) - scAddrBytes[31] = 1 - shardID = testContextSource.ShardCoordinator.ComputeId(scAddrBytes) - require.Equal(t, uint32(1), shardID) - - gasPrice := uint64(10) - gasLimit := uint64(100) - - _, _ = vm.CreateAccount(testContextSource.Accounts, relayerAddr, 0, big.NewInt(100000)) - - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddrBytes, gasPrice, gasLimit, nil) - - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - - // execute on source shard - retCode, err := testContextSource.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) - - // check relayed balance - utils.TestAccount(t, testContextSource.Accounts, relayerAddr, 1, big.NewInt(97270)) - - // check accumulated fees - accumulatedFees := testContextSource.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(1630), accumulatedFees) - - // execute on destination shard - retCode, err = testContextDst.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) - require.Nil(t, err) - - _, err = testContextDst.Accounts.Commit() - require.Nil(t, err) - - // check inner tx receiver - account, err := testContextDst.Accounts.GetExistingAccount(scAddrBytes) - require.Nil(t, account) - require.NotNil(t, err) + t.Run("before relayed base cost fix", testRelayedMoveBalanceExecuteOnSourceAndDestination(integrationTests.UnreachableEpoch)) +} - // check accumulated fees - accumulatedFees = testContextDst.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(1000), accumulatedFees) +func testRelayedMoveBalanceExecuteOnSourceAndDestination(relayedFixActivationEpoch uint32) func(t *testing.T) { + return func(t *testing.T) { + testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextSource.Close() + + testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextDst.Close() + + relayerAddr := []byte("12345678901234567890123456789030") + shardID := testContextSource.ShardCoordinator.ComputeId(relayerAddr) + require.Equal(t, uint32(0), shardID) + + sndAddr := []byte("12345678901234567890123456789011") + shardID = testContextSource.ShardCoordinator.ComputeId(sndAddr) + require.Equal(t, uint32(1), shardID) + + scAddress := "00000000000000000000dbb53e4b23392b0d6f36cce32deb2d623e9625ab3132" + scAddrBytes, _ := hex.DecodeString(scAddress) + scAddrBytes[31] = 1 + shardID = testContextSource.ShardCoordinator.ComputeId(scAddrBytes) + require.Equal(t, uint32(1), shardID) + + gasPrice := uint64(10) + gasLimit := uint64(100) + + _, _ = vm.CreateAccount(testContextSource.Accounts, relayerAddr, 0, big.NewInt(100000)) + _, _ = vm.CreateAccount(testContextSource.Accounts, sndAddr, 0, big.NewInt(100)) + + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddrBytes, gasPrice, gasLimit, nil) + + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + + // execute on source shard + retCode, err := testContextSource.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) + + // check relayed balance + // 100000 - rTxFee(163)*gasPrice(10) - txFeeInner(1000*gasPriceModifier(0.1)) = 98270 + utils.TestAccount(t, testContextSource.Accounts, relayerAddr, 1, big.NewInt(98270)) + + // check accumulated fees + accumulatedFees := testContextSource.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, big.NewInt(1630), accumulatedFees) + + // execute on destination shard + retCode, err = testContextDst.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) + require.Nil(t, err) + + _, err = testContextDst.Accounts.Commit() + require.Nil(t, err) + + // check inner tx receiver + account, err := testContextDst.Accounts.GetExistingAccount(scAddrBytes) + require.Nil(t, account) + require.NotNil(t, err) + + // check accumulated fees + accumulatedFees = testContextDst.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, big.NewInt(100), accumulatedFees) + } } func TestRelayedMoveBalanceExecuteOnSourceAndDestinationRelayerAndInnerTxSenderShard0InnerTxReceiverShard1ShouldWork(t *testing.T) { @@ -183,63 +219,83 @@ func TestRelayedMoveBalanceExecuteOnSourceAndDestinationRelayerAndInnerTxSenderS t.Skip("this is not a short test") } - testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextSource.Close() - - testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextDst.Close() - - relayerAddr := []byte("12345678901234567890123456789030") - shardID := testContextSource.ShardCoordinator.ComputeId(relayerAddr) - require.Equal(t, uint32(0), shardID) - - sndAddr := []byte("12345678901234567890123456789010") - shardID = testContextSource.ShardCoordinator.ComputeId(sndAddr) - require.Equal(t, uint32(0), shardID) - - rcvAddr := []byte("12345678901234567890123456789011") - shardID = testContextSource.ShardCoordinator.ComputeId(rcvAddr) - require.Equal(t, uint32(1), shardID) - - gasPrice := uint64(10) - gasLimit := uint64(100) - - _, _ = vm.CreateAccount(testContextSource.Accounts, relayerAddr, 0, big.NewInt(100000)) - - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, nil) - - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - - // execute on source shard - retCode, err := testContextSource.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) - - // check relayed balance - utils.TestAccount(t, testContextSource.Accounts, relayerAddr, 1, big.NewInt(97270)) - // check inner tx sender - utils.TestAccount(t, testContextSource.Accounts, sndAddr, 1, big.NewInt(0)) - - // check accumulated fees - accumulatedFees := testContextSource.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(2630), accumulatedFees) - - // get scr for destination shard - txs := testContextSource.GetIntermediateTransactions(t) - scr := txs[0] - - utils.ProcessSCRResult(t, testContextDst, scr, vmcommon.Ok, nil) - - // check balance receiver - utils.TestAccount(t, testContextDst.Accounts, rcvAddr, 0, big.NewInt(100)) + t.Run("before relayed base cost fix", testRelayedMoveBalanceExecuteOnSourceAndDestinationRelayerAndInnerTxSenderShard0InnerTxReceiverShard1ShouldWork(integrationTests.UnreachableEpoch)) + t.Run("after relayed base cost fix", testRelayedMoveBalanceExecuteOnSourceAndDestinationRelayerAndInnerTxSenderShard0InnerTxReceiverShard1ShouldWork(0)) +} - // check accumulated fess - accumulatedFees = testContextDst.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(0), accumulatedFees) +func testRelayedMoveBalanceExecuteOnSourceAndDestinationRelayerAndInnerTxSenderShard0InnerTxReceiverShard1ShouldWork(relayedFixActivationEpoch uint32) func(t *testing.T) { + return func(t *testing.T) { + testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextSource.Close() + + testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextDst.Close() + + relayerAddr := []byte("12345678901234567890123456789030") + shardID := testContextSource.ShardCoordinator.ComputeId(relayerAddr) + require.Equal(t, uint32(0), shardID) + + sndAddr := []byte("12345678901234567890123456789010") + shardID = testContextSource.ShardCoordinator.ComputeId(sndAddr) + require.Equal(t, uint32(0), shardID) + + rcvAddr := []byte("12345678901234567890123456789011") + shardID = testContextSource.ShardCoordinator.ComputeId(rcvAddr) + require.Equal(t, uint32(1), shardID) + + gasPrice := uint64(10) + gasLimit := uint64(100) + + _, _ = vm.CreateAccount(testContextSource.Accounts, relayerAddr, 0, big.NewInt(100000)) + _, _ = vm.CreateAccount(testContextSource.Accounts, sndAddr, 0, big.NewInt(100)) + + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, nil) + + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := gasLimit + minGasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + + // execute on source shard + retCode, err := testContextSource.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) + + // check relayed balance + // before base cost fix: 100000 - rTxFee(163)*gasPrice(10) - innerTxFee(1000*gasPriceModifier(0.1)) = 98270 + // after base cost fix: 100000 - rTxFee(163)*gasPrice(10) - innerTxFee(10) = 98360 + expectedRelayerBalance := big.NewInt(98270) + expectedAccumulatedFees := big.NewInt(1730) + if relayedFixActivationEpoch != integrationTests.UnreachableEpoch { + expectedRelayerBalance = big.NewInt(98360) + expectedAccumulatedFees = big.NewInt(1640) + } + utils.TestAccount(t, testContextSource.Accounts, relayerAddr, 1, expectedRelayerBalance) + // check inner tx sender + utils.TestAccount(t, testContextSource.Accounts, sndAddr, 1, big.NewInt(0)) + + // check accumulated fees + accumulatedFees := testContextSource.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccumulatedFees, accumulatedFees) + + // get scr for destination shard + txs := testContextSource.GetIntermediateTransactions(t) + scr := txs[0] + + utils.ProcessSCRResult(t, testContextDst, scr, vmcommon.Ok, nil) + + // check balance receiver + utils.TestAccount(t, testContextDst.Accounts, rcvAddr, 0, big.NewInt(100)) + + // check accumulated fess + accumulatedFees = testContextDst.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, big.NewInt(0), accumulatedFees) + } } func TestRelayedMoveBalanceRelayerAndInnerTxReceiverShard0SenderShard1(t *testing.T) { @@ -247,75 +303,87 @@ func TestRelayedMoveBalanceRelayerAndInnerTxReceiverShard0SenderShard1(t *testin t.Skip("this is not a short test") } - testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextSource.Close() + t.Run("before relayed base cost fix", testRelayedMoveBalanceRelayerAndInnerTxReceiverShard0SenderShard1(integrationTests.UnreachableEpoch)) +} + +func testRelayedMoveBalanceRelayerAndInnerTxReceiverShard0SenderShard1(relayedFixActivationEpoch uint32) func(t *testing.T) { + return func(t *testing.T) { + testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextSource.Close() - testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextDst.Close() + testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextDst.Close() - relayerAddr := []byte("12345678901234567890123456789030") - shardID := testContextSource.ShardCoordinator.ComputeId(relayerAddr) - require.Equal(t, uint32(0), shardID) + relayerAddr := []byte("12345678901234567890123456789030") + shardID := testContextSource.ShardCoordinator.ComputeId(relayerAddr) + require.Equal(t, uint32(0), shardID) - sndAddr := []byte("12345678901234567890123456789011") - shardID = testContextSource.ShardCoordinator.ComputeId(sndAddr) - require.Equal(t, uint32(1), shardID) + sndAddr := []byte("12345678901234567890123456789011") + shardID = testContextSource.ShardCoordinator.ComputeId(sndAddr) + require.Equal(t, uint32(1), shardID) - rcvAddr := []byte("12345678901234567890123456789010") - shardID = testContextSource.ShardCoordinator.ComputeId(rcvAddr) - require.Equal(t, uint32(0), shardID) + rcvAddr := []byte("12345678901234567890123456789010") + shardID = testContextSource.ShardCoordinator.ComputeId(rcvAddr) + require.Equal(t, uint32(0), shardID) - gasPrice := uint64(10) - gasLimit := uint64(100) + gasPrice := uint64(10) + gasLimit := uint64(100) - _, _ = vm.CreateAccount(testContextSource.Accounts, relayerAddr, 0, big.NewInt(100000)) + _, _ = vm.CreateAccount(testContextSource.Accounts, relayerAddr, 0, big.NewInt(100000)) + _, _ = vm.CreateAccount(testContextDst.Accounts, sndAddr, 0, big.NewInt(100)) - innerTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, nil) + innerTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, nil) - rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - // execute on relayer shard - retCode, err := testContextSource.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) + // execute on relayer shard + retCode, err := testContextSource.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) - // check relayed balance - utils.TestAccount(t, testContextSource.Accounts, relayerAddr, 1, big.NewInt(97270)) + // check relayed balance + // 100000 - rTxFee(163)*gasPrice(10) - innerTxFee(1000*gasPriceModifier(0.1)) = 98270 + utils.TestAccount(t, testContextSource.Accounts, relayerAddr, 1, big.NewInt(98270)) - // check inner Tx receiver - innerTxSenderAccount, err := testContextSource.Accounts.GetExistingAccount(sndAddr) - require.Nil(t, innerTxSenderAccount) - require.NotNil(t, err) + // check inner Tx receiver + innerTxSenderAccount, err := testContextSource.Accounts.GetExistingAccount(sndAddr) + require.Nil(t, innerTxSenderAccount) + require.NotNil(t, err) - // check accumulated fees - accumulatedFees := testContextSource.TxFeeHandler.GetAccumulatedFees() - expectedAccFees := big.NewInt(1630) - require.Equal(t, expectedAccFees, accumulatedFees) + // check accumulated fees + accumulatedFees := testContextSource.TxFeeHandler.GetAccumulatedFees() + expectedAccFees := big.NewInt(1630) + require.Equal(t, expectedAccFees, accumulatedFees) - // execute on destination shard - retCode, err = testContextDst.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) + // execute on destination shard + retCode, err = testContextDst.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) - utils.TestAccount(t, testContextDst.Accounts, sndAddr, 1, big.NewInt(0)) + utils.TestAccount(t, testContextDst.Accounts, sndAddr, 1, big.NewInt(0)) - // check accumulated fees - accumulatedFees = testContextDst.TxFeeHandler.GetAccumulatedFees() - expectedAccFees = big.NewInt(1000) - require.Equal(t, expectedAccFees, accumulatedFees) + // check accumulated fees + accumulatedFees = testContextDst.TxFeeHandler.GetAccumulatedFees() + expectedAccFees = big.NewInt(100) + require.Equal(t, expectedAccFees, accumulatedFees) - txs := testContextDst.GetIntermediateTransactions(t) - scr := txs[0] + txs := testContextDst.GetIntermediateTransactions(t) + scr := txs[0] - // execute generated SCR from shard1 on shard 0 - utils.ProcessSCRResult(t, testContextSource, scr, vmcommon.Ok, nil) + // execute generated SCR from shard1 on shard 0 + utils.ProcessSCRResult(t, testContextSource, scr, vmcommon.Ok, nil) - // check receiver balance - utils.TestAccount(t, testContextSource.Accounts, rcvAddr, 0, big.NewInt(100)) + // check receiver balance + utils.TestAccount(t, testContextSource.Accounts, rcvAddr, 0, big.NewInt(100)) + } } func TestMoveBalanceRelayerShard0InnerTxSenderShard1InnerTxReceiverShard2ShouldWork(t *testing.T) { @@ -323,77 +391,91 @@ func TestMoveBalanceRelayerShard0InnerTxSenderShard1InnerTxReceiverShard2ShouldW t.Skip("this is not a short test") } - testContextRelayer, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextRelayer.Close() - - testContextInnerSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextInnerSource.Close() - - testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}) - require.Nil(t, err) - defer testContextDst.Close() - - relayerAddr := []byte("12345678901234567890123456789030") - shardID := testContextRelayer.ShardCoordinator.ComputeId(relayerAddr) - require.Equal(t, uint32(0), shardID) - - sndAddr := []byte("12345678901234567890123456789011") - shardID = testContextRelayer.ShardCoordinator.ComputeId(sndAddr) - require.Equal(t, uint32(1), shardID) - - rcvAddr := []byte("12345678901234567890123456789012") - shardID = testContextRelayer.ShardCoordinator.ComputeId(rcvAddr) - require.Equal(t, uint32(2), shardID) - - gasPrice := uint64(10) - gasLimit := uint64(100) - - _, _ = vm.CreateAccount(testContextRelayer.Accounts, relayerAddr, 0, big.NewInt(100000)) - - innerTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, nil) - - rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - - // execute on relayer shard - retCode, err := testContextRelayer.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) - - // check relayed balance - utils.TestAccount(t, testContextRelayer.Accounts, relayerAddr, 1, big.NewInt(97270)) - - // check inner Tx receiver - innerTxSenderAccount, err := testContextRelayer.Accounts.GetExistingAccount(sndAddr) - require.Nil(t, innerTxSenderAccount) - require.NotNil(t, err) - - // check accumulated fees - accumulatedFees := testContextRelayer.TxFeeHandler.GetAccumulatedFees() - expectedAccFees := big.NewInt(1630) - require.Equal(t, expectedAccFees, accumulatedFees) - - // execute on inner tx sender shard - retCode, err = testContextInnerSource.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) - - utils.TestAccount(t, testContextInnerSource.Accounts, sndAddr, 1, big.NewInt(0)) - - // check accumulated fees - accumulatedFees = testContextInnerSource.TxFeeHandler.GetAccumulatedFees() - expectedAccFees = big.NewInt(1000) - require.Equal(t, expectedAccFees, accumulatedFees) - - // execute on inner tx receiver shard - txs := testContextInnerSource.GetIntermediateTransactions(t) - scr := txs[0] - - utils.ProcessSCRResult(t, testContextDst, scr, vmcommon.Ok, nil) + t.Run("before relayed base cost fix", testMoveBalanceRelayerShard0InnerTxSenderShard1InnerTxReceiverShard2ShouldWork(integrationTests.UnreachableEpoch)) +} - // check receiver balance - utils.TestAccount(t, testContextDst.Accounts, rcvAddr, 0, big.NewInt(100)) +func testMoveBalanceRelayerShard0InnerTxSenderShard1InnerTxReceiverShard2ShouldWork(relayedFixActivationEpoch uint32) func(t *testing.T) { + return func(t *testing.T) { + testContextRelayer, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextRelayer.Close() + + testContextInnerSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextInnerSource.Close() + + testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContextDst.Close() + + relayerAddr := []byte("12345678901234567890123456789030") + shardID := testContextRelayer.ShardCoordinator.ComputeId(relayerAddr) + require.Equal(t, uint32(0), shardID) + + sndAddr := []byte("12345678901234567890123456789011") + shardID = testContextRelayer.ShardCoordinator.ComputeId(sndAddr) + require.Equal(t, uint32(1), shardID) + + rcvAddr := []byte("12345678901234567890123456789012") + shardID = testContextRelayer.ShardCoordinator.ComputeId(rcvAddr) + require.Equal(t, uint32(2), shardID) + + gasPrice := uint64(10) + gasLimit := uint64(100) + + _, _ = vm.CreateAccount(testContextRelayer.Accounts, relayerAddr, 0, big.NewInt(100000)) + _, _ = vm.CreateAccount(testContextInnerSource.Accounts, sndAddr, 0, big.NewInt(100)) + + innerTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, nil) + + rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + + // execute on relayer shard + retCode, err := testContextRelayer.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) + + // check relayed balance + // 100000 - rTxFee(164)*gasPrice(10) - innerTxFee(1000*gasPriceModifier(0.1)) = 98270 + utils.TestAccount(t, testContextRelayer.Accounts, relayerAddr, 1, big.NewInt(98270)) + + // check inner Tx receiver + innerTxSenderAccount, err := testContextRelayer.Accounts.GetExistingAccount(sndAddr) + require.Nil(t, innerTxSenderAccount) + require.NotNil(t, err) + + // check accumulated fees + accumulatedFees := testContextRelayer.TxFeeHandler.GetAccumulatedFees() + expectedAccFees := big.NewInt(1630) + require.Equal(t, expectedAccFees, accumulatedFees) + + // execute on inner tx sender shard + retCode, err = testContextInnerSource.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) + + utils.TestAccount(t, testContextInnerSource.Accounts, sndAddr, 1, big.NewInt(0)) + + // check accumulated fees + accumulatedFees = testContextInnerSource.TxFeeHandler.GetAccumulatedFees() + expectedAccFees = big.NewInt(100) + require.Equal(t, expectedAccFees, accumulatedFees) + + // execute on inner tx receiver shard + txs := testContextInnerSource.GetIntermediateTransactions(t) + scr := txs[0] + + utils.ProcessSCRResult(t, testContextDst, scr, vmcommon.Ok, nil) + + // check receiver balance + utils.TestAccount(t, testContextDst.Accounts, rcvAddr, 0, big.NewInt(100)) + } } diff --git a/integrationTests/vm/txsFee/multiShard/relayedScDeploy_test.go b/integrationTests/vm/txsFee/multiShard/relayedScDeploy_test.go index 7700c55b0f4..de22bb57d60 100644 --- a/integrationTests/vm/txsFee/multiShard/relayedScDeploy_test.go +++ b/integrationTests/vm/txsFee/multiShard/relayedScDeploy_test.go @@ -18,11 +18,11 @@ func TestRelayedSCDeployShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContextRelayer, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}) + testContextRelayer, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextRelayer.Close() - testContextInner, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContextInner, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextInner.Close() diff --git a/integrationTests/vm/txsFee/multiShard/relayedTxScCalls_test.go b/integrationTests/vm/txsFee/multiShard/relayedTxScCalls_test.go index bbab4208aa2..736783b11ae 100644 --- a/integrationTests/vm/txsFee/multiShard/relayedTxScCalls_test.go +++ b/integrationTests/vm/txsFee/multiShard/relayedTxScCalls_test.go @@ -31,15 +31,15 @@ func TestRelayedTxScCallMultiShardShouldWork(t *testing.T) { DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, } - testContextRelayer, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, enableEpochs) + testContextRelayer, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, enableEpochs, 1) require.Nil(t, err) defer testContextRelayer.Close() - testContextInnerSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs) + testContextInnerSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs, 1) require.Nil(t, err) defer testContextInnerSource.Close() - testContextInnerDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs) + testContextInnerDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs, 1) require.Nil(t, err) defer testContextInnerDst.Close() @@ -140,15 +140,15 @@ func TestRelayedTxScCallMultiShardFailOnInnerTxDst(t *testing.T) { t.Skip("this is not a short test") } - testContextRelayer, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}) + testContextRelayer, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(2, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextRelayer.Close() - testContextInnerSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + testContextInnerSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextInnerSource.Close() - testContextInnerDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContextInnerDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextInnerDst.Close() diff --git a/integrationTests/vm/txsFee/multiShard/scCallWithValueTransfer_test.go b/integrationTests/vm/txsFee/multiShard/scCallWithValueTransfer_test.go index 8f66a649a3b..c2a7356d1f3 100644 --- a/integrationTests/vm/txsFee/multiShard/scCallWithValueTransfer_test.go +++ b/integrationTests/vm/txsFee/multiShard/scCallWithValueTransfer_test.go @@ -30,14 +30,14 @@ func TestDeployContractAndTransferValueSCProcessorV2(t *testing.T) { } func testDeployContractAndTransferValue(t *testing.T, scProcessorV2EnabledEpoch uint32) { - testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextSource.Close() configEnabledEpochs := config.EnableEpochs{} configEnabledEpochs.SCProcessorV2EnableEpoch = scProcessorV2EnabledEpoch - testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, configEnabledEpochs) + testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, configEnabledEpochs, 1) require.Nil(t, err) defer testContextDst.Close() diff --git a/integrationTests/vm/txsFee/multiShard/scCalls_test.go b/integrationTests/vm/txsFee/multiShard/scCalls_test.go index 34aa049c7c4..9eb2d85fbe0 100644 --- a/integrationTests/vm/txsFee/multiShard/scCalls_test.go +++ b/integrationTests/vm/txsFee/multiShard/scCalls_test.go @@ -18,11 +18,11 @@ func TestScCallExecuteOnSourceAndDstShardShouldWork(t *testing.T) { enableEpochs := config.EnableEpochs{} - testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs) + testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, enableEpochs, 1) require.Nil(t, err) defer testContextSource.Close() - testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs) + testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, enableEpochs, 1) require.Nil(t, err) defer testContextDst.Close() @@ -98,11 +98,11 @@ func TestScCallExecuteOnSourceAndDstShardInvalidOnDst(t *testing.T) { t.Skip("this is not a short test") } - testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + testContextSource, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextSource.Close() - testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContextDst, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextDst.Close() diff --git a/integrationTests/vm/txsFee/relayedAsyncCall_test.go b/integrationTests/vm/txsFee/relayedAsyncCall_test.go index d98a440b648..9b4e243ec6a 100644 --- a/integrationTests/vm/txsFee/relayedAsyncCall_test.go +++ b/integrationTests/vm/txsFee/relayedAsyncCall_test.go @@ -42,7 +42,7 @@ func TestRelayedAsyncCallShouldWork(t *testing.T) { } func testRelayedAsyncCallShouldWork(t *testing.T, enableEpochs config.EnableEpochs, senderAddr []byte) *vm.VMTestContext { - testContext, err := vm.CreatePreparedTxProcessorWithVMs(enableEpochs) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(enableEpochs, 1) require.Nil(t, err) localEgldBalance := big.NewInt(100000000) diff --git a/integrationTests/vm/txsFee/relayedAsyncESDT_test.go b/integrationTests/vm/txsFee/relayedAsyncESDT_test.go index 204f8e4b885..bb8b05606a7 100644 --- a/integrationTests/vm/txsFee/relayedAsyncESDT_test.go +++ b/integrationTests/vm/txsFee/relayedAsyncESDT_test.go @@ -20,7 +20,7 @@ func TestRelayedAsyncESDTCallShouldWork(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -82,7 +82,7 @@ func TestRelayedAsyncESDTCall_InvalidCallFirstContract(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -144,7 +144,7 @@ func TestRelayedAsyncESDTCall_InvalidOutOfGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/relayedBuiltInFunctions_test.go b/integrationTests/vm/txsFee/relayedBuiltInFunctions_test.go index 93396ce5deb..7688f147729 100644 --- a/integrationTests/vm/txsFee/relayedBuiltInFunctions_test.go +++ b/integrationTests/vm/txsFee/relayedBuiltInFunctions_test.go @@ -20,51 +20,62 @@ func TestRelayedBuildInFunctionChangeOwnerCallShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs( - config.EnableEpochs{ - PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, - }) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed base cost fix", testRelayedBuildInFunctionChangeOwnerCallShouldWork(integrationTests.UnreachableEpoch, big.NewInt(25610), big.NewInt(4390))) + t.Run("after relayed base cost fix", testRelayedBuildInFunctionChangeOwnerCallShouldWork(0, big.NewInt(24854), big.NewInt(5146))) +} - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") - testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) - utils.CleanAccumulatedIntermediateTransactions(t, testContext) +func testRelayedBuildInFunctionChangeOwnerCallShouldWork( + relayedFixActivationEpoch uint32, + expectedBalanceRelayer *big.Int, + expectedAccumulatedFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs( + config.EnableEpochs{ + PenalizedTooMuchGasEnableEpoch: integrationTests.UnreachableEpoch, + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - newOwner := []byte("12345678901234567890123456789112") - gasLimit := uint64(1000) + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9991691, 8309, 39) + testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) + utils.CleanAccumulatedIntermediateTransactions(t, testContext) - txData := []byte(core.BuiltInFunctionChangeOwnerAddress + "@" + hex.EncodeToString(newOwner)) - innerTx := vm.CreateTransaction(1, big.NewInt(0), owner, scAddress, gasPrice, gasLimit, txData) + relayerAddr := []byte("12345678901234567890123456789033") + newOwner := []byte("12345678901234567890123456789112") + gasLimit := uint64(1000) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) + txData := []byte(core.BuiltInFunctionChangeOwnerAddress + "@" + hex.EncodeToString(newOwner)) + innerTx := vm.CreateTransaction(1, big.NewInt(0), owner, scAddress, gasPrice, gasLimit, txData) - rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, owner, gasPrice, rTxGasLimit, rtxData) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) + rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, owner, gasPrice, rTxGasLimit, rtxData) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) - utils.CheckOwnerAddr(t, testContext, scAddress, newOwner) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalanceRelayer := big.NewInt(16610) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) + utils.CheckOwnerAddr(t, testContext, scAddress, newOwner) - expectedBalance := big.NewInt(9988100) - vm.TestAccount(t, testContext.Accounts, owner, 2, expectedBalance) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(13390), accumulatedFees) + expectedBalance := big.NewInt(9991691) + vm.TestAccount(t, testContext.Accounts, owner, 2, expectedBalance) - developerFees := testContext.TxFeeHandler.GetDeveloperFees() - require.Equal(t, big.NewInt(915), developerFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccumulatedFees, accumulatedFees) + + developerFees := testContext.TxFeeHandler.GetDeveloperFees() + require.Equal(t, big.NewInt(91), developerFees) + } } func TestRelayedBuildInFunctionChangeOwnerCallWrongOwnerShouldConsumeGas(t *testing.T) { @@ -72,49 +83,61 @@ func TestRelayedBuildInFunctionChangeOwnerCallWrongOwnerShouldConsumeGas(t *test t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed base cost fix", testRelayedBuildInFunctionChangeOwnerCallWrongOwnerShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(25610), big.NewInt(4390))) + t.Run("after relayed base cost fix", testRelayedBuildInFunctionChangeOwnerCallWrongOwnerShouldConsumeGas(0, big.NewInt(25610), big.NewInt(4390))) +} - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") - testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) - utils.CleanAccumulatedIntermediateTransactions(t, testContext) +func testRelayedBuildInFunctionChangeOwnerCallWrongOwnerShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedBalanceRelayer *big.Int, + expectedAccumulatedFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789113") - newOwner := []byte("12345678901234567890123456789112") - gasLimit := uint64(1000) + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9991691, 8309, 39) + testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) + utils.CleanAccumulatedIntermediateTransactions(t, testContext) - txData := []byte(core.BuiltInFunctionChangeOwnerAddress + "@" + hex.EncodeToString(newOwner)) - innerTx := vm.CreateTransaction(1, big.NewInt(0), sndAddr, scAddress, gasPrice, gasLimit, txData) + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789113") + newOwner := []byte("12345678901234567890123456789112") + gasLimit := uint64(1000) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) + txData := []byte(core.BuiltInFunctionChangeOwnerAddress + "@" + hex.EncodeToString(newOwner)) + innerTx := vm.CreateTransaction(1, big.NewInt(0), sndAddr, scAddress, gasPrice, gasLimit, txData) - rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, owner, gasPrice, rTxGasLimit, rtxData) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) - require.Equal(t, process.ErrFailedTransaction, err) + rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, owner, gasPrice, rTxGasLimit, rtxData) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) + require.Equal(t, process.ErrFailedTransaction, err) - utils.CheckOwnerAddr(t, testContext, scAddress, owner) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalanceRelayer := big.NewInt(16610) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) + utils.CheckOwnerAddr(t, testContext, scAddress, owner) - expectedBalance := big.NewInt(9988100) - vm.TestAccount(t, testContext.Accounts, owner, 1, expectedBalance) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(13390), accumulatedFees) + expectedBalance := big.NewInt(9991691) + vm.TestAccount(t, testContext.Accounts, owner, 1, expectedBalance) - developerFees := testContext.TxFeeHandler.GetDeveloperFees() - require.Equal(t, big.NewInt(0), developerFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccumulatedFees, accumulatedFees) + + developerFees := testContext.TxFeeHandler.GetDeveloperFees() + require.Equal(t, big.NewInt(0), developerFees) + } } func TestRelayedBuildInFunctionChangeOwnerInvalidAddressShouldConsumeGas(t *testing.T) { @@ -122,11 +145,11 @@ func TestRelayedBuildInFunctionChangeOwnerInvalidAddressShouldConsumeGas(t *test t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) utils.CleanAccumulatedIntermediateTransactions(t, testContext) @@ -140,7 +163,7 @@ func TestRelayedBuildInFunctionChangeOwnerInvalidAddressShouldConsumeGas(t *test _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, owner, gasPrice, rTxGasLimit, rtxData) retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) @@ -173,13 +196,15 @@ func TestRelayedBuildInFunctionChangeOwnerCallInsufficientGasLimitShouldConsumeG t.Run("nonce fix is disabled, should increase the sender's nonce", func(t *testing.T) { testRelayedBuildInFunctionChangeOwnerCallInsufficientGasLimitShouldConsumeGas(t, config.EnableEpochs{ - RelayedNonceFixEnableEpoch: 1000, + RelayedNonceFixEnableEpoch: 1000, + FixRelayedBaseCostEnableEpoch: 1000, }) }) t.Run("nonce fix is enabled, should still increase the sender's nonce", func(t *testing.T) { testRelayedBuildInFunctionChangeOwnerCallInsufficientGasLimitShouldConsumeGas(t, config.EnableEpochs{ - RelayedNonceFixEnableEpoch: 0, + RelayedNonceFixEnableEpoch: 0, + FixRelayedBaseCostEnableEpoch: 1000, }) }) } @@ -188,11 +213,11 @@ func testRelayedBuildInFunctionChangeOwnerCallInsufficientGasLimitShouldConsumeG t *testing.T, enableEpochs config.EnableEpochs, ) { - testContext, err := vm.CreatePreparedTxProcessorWithVMs(enableEpochs) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(enableEpochs, 1) require.Nil(t, err) defer testContext.Close() - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) utils.CleanAccumulatedIntermediateTransactions(t, testContext) @@ -206,7 +231,7 @@ func testRelayedBuildInFunctionChangeOwnerCallInsufficientGasLimitShouldConsumeG _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, owner, gasPrice, rTxGasLimit, rtxData) retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) @@ -236,11 +261,11 @@ func TestRelayedBuildInFunctionChangeOwnerCallOutOfGasShouldConsumeGas(t *testin t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, owner := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) testContext.TxFeeHandler.CreateBlockStarted(getZeroGasAndFees()) utils.CleanAccumulatedIntermediateTransactions(t, testContext) @@ -248,13 +273,13 @@ func TestRelayedBuildInFunctionChangeOwnerCallOutOfGasShouldConsumeGas(t *testin newOwner := []byte("12345678901234567890123456789112") txData := []byte(core.BuiltInFunctionChangeOwnerAddress + "@" + hex.EncodeToString(newOwner)) - gasLimit := uint64(len(txData) + 1) + gasLimit := uint64(len(txData)) + minGasLimit innerTx := vm.CreateTransaction(1, big.NewInt(0), owner, scAddress, gasPrice, gasLimit, txData) _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, owner, gasPrice, rTxGasLimit, rtxData) retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) diff --git a/integrationTests/vm/txsFee/relayedDns_test.go b/integrationTests/vm/txsFee/relayedDns_test.go index 54c70be0ee8..389941886e7 100644 --- a/integrationTests/vm/txsFee/relayedDns_test.go +++ b/integrationTests/vm/txsFee/relayedDns_test.go @@ -18,7 +18,7 @@ func TestRelayedTxDnsTransaction_ShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/relayedESDT_test.go b/integrationTests/vm/txsFee/relayedESDT_test.go index c9837fb7075..55a7e1bde04 100644 --- a/integrationTests/vm/txsFee/relayedESDT_test.go +++ b/integrationTests/vm/txsFee/relayedESDT_test.go @@ -17,95 +17,121 @@ func TestRelayedESDTTransferShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed base cost fix", testRelayedESDTTransferShouldWork(integrationTests.UnreachableEpoch, big.NewInt(9997614), big.NewInt(2386))) + t.Run("after relayed base cost fix", testRelayedESDTTransferShouldWork(0, big.NewInt(9997299), big.NewInt(2701))) +} + +func testRelayedESDTTransferShouldWork( + relayedFixActivationEpoch uint32, + expectedRelayerBalance *big.Int, + expectedAccFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789012") - rcvAddr := []byte("12345678901234567890123456789022") + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789012") + rcvAddr := []byte("12345678901234567890123456789022") - relayerBalance := big.NewInt(10000000) - localEsdtBalance := big.NewInt(100000000) - token := []byte("miiutoken") - utils.CreateAccountWithESDTBalance(t, testContext.Accounts, sndAddr, big.NewInt(0), token, 0, localEsdtBalance) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, relayerBalance) + relayerBalance := big.NewInt(10000000) + localEsdtBalance := big.NewInt(100000000) + token := []byte("miiutoken") + utils.CreateAccountWithESDTBalance(t, testContext.Accounts, sndAddr, big.NewInt(0), token, 0, localEsdtBalance) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, relayerBalance) - gasLimit := uint64(40) - innerTx := utils.CreateESDTTransferTx(0, sndAddr, rcvAddr, token, big.NewInt(100), gasPrice, gasLimit) + gasLimit := uint64(40) + innerTx := utils.CreateESDTTransferTx(0, sndAddr, rcvAddr, token, big.NewInt(100), gasPrice, gasLimit) - rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalanceSnd := big.NewInt(99999900) - utils.CheckESDTBalance(t, testContext, sndAddr, token, expectedBalanceSnd) + expectedBalanceSnd := big.NewInt(99999900) + utils.CheckESDTBalance(t, testContext, sndAddr, token, expectedBalanceSnd) - expectedReceiverBalance := big.NewInt(100) - utils.CheckESDTBalance(t, testContext, rcvAddr, token, expectedReceiverBalance) + expectedReceiverBalance := big.NewInt(100) + utils.CheckESDTBalance(t, testContext, rcvAddr, token, expectedReceiverBalance) - expectedEGLDBalance := big.NewInt(0) - utils.TestAccount(t, testContext.Accounts, sndAddr, 1, expectedEGLDBalance) + expectedEGLDBalance := big.NewInt(0) + utils.TestAccount(t, testContext.Accounts, sndAddr, 1, expectedEGLDBalance) - utils.TestAccount(t, testContext.Accounts, relayerAddr, 1, big.NewInt(9997290)) + utils.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedRelayerBalance) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(2710), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccFees, accumulatedFees) + } } -func TestTestRelayedESTTransferNotEnoughESTValueShouldConsumeGas(t *testing.T) { +func TestRelayedESTTransferNotEnoughESTValueShouldConsumeGas(t *testing.T) { if testing.Short() { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed base cost fix", testRelayedESTTransferNotEnoughESTValueShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(9997488), big.NewInt(2512))) + t.Run("after relayed base cost fix", testRelayedESTTransferNotEnoughESTValueShouldConsumeGas(0, big.NewInt(9997119), big.NewInt(2881))) +} + +func testRelayedESTTransferNotEnoughESTValueShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedRelayerBalance *big.Int, + expectedAccFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789012") - rcvAddr := []byte("12345678901234567890123456789022") + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789012") + rcvAddr := []byte("12345678901234567890123456789022") - relayerBalance := big.NewInt(10000000) - localEsdtBalance := big.NewInt(100000000) - token := []byte("miiutoken") - utils.CreateAccountWithESDTBalance(t, testContext.Accounts, sndAddr, big.NewInt(0), token, 0, localEsdtBalance) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, relayerBalance) + relayerBalance := big.NewInt(10000000) + localEsdtBalance := big.NewInt(100000000) + token := []byte("miiutoken") + utils.CreateAccountWithESDTBalance(t, testContext.Accounts, sndAddr, big.NewInt(0), token, 0, localEsdtBalance) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, relayerBalance) - gasLimit := uint64(40) - innerTx := utils.CreateESDTTransferTx(0, sndAddr, rcvAddr, token, big.NewInt(100000001), gasPrice, gasLimit) + gasLimit := uint64(42) + innerTx := utils.CreateESDTTransferTx(0, sndAddr, rcvAddr, token, big.NewInt(100000001), gasPrice, gasLimit) - rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rtxData := integrationTests.PrepareRelayedTxDataV1(innerTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, innerTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.ExecutionFailed, retCode) + require.Nil(t, err) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalanceSnd := big.NewInt(100000000) - utils.CheckESDTBalance(t, testContext, sndAddr, token, expectedBalanceSnd) + expectedBalanceSnd := big.NewInt(100000000) + utils.CheckESDTBalance(t, testContext, sndAddr, token, expectedBalanceSnd) - expectedReceiverBalance := big.NewInt(0) - utils.CheckESDTBalance(t, testContext, rcvAddr, token, expectedReceiverBalance) + expectedReceiverBalance := big.NewInt(0) + utils.CheckESDTBalance(t, testContext, rcvAddr, token, expectedReceiverBalance) - expectedEGLDBalance := big.NewInt(0) - utils.TestAccount(t, testContext.Accounts, sndAddr, 1, expectedEGLDBalance) + expectedEGLDBalance := big.NewInt(0) + utils.TestAccount(t, testContext.Accounts, sndAddr, 1, expectedEGLDBalance) - utils.TestAccount(t, testContext.Accounts, relayerAddr, 1, big.NewInt(9997130)) + utils.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedRelayerBalance) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(2870), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccFees, accumulatedFees) + } } diff --git a/integrationTests/vm/txsFee/relayedMoveBalance_test.go b/integrationTests/vm/txsFee/relayedMoveBalance_test.go index accdffbfb4e..1a81602ff82 100644 --- a/integrationTests/vm/txsFee/relayedMoveBalance_test.go +++ b/integrationTests/vm/txsFee/relayedMoveBalance_test.go @@ -23,7 +23,9 @@ func TestRelayedMoveBalanceShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: integrationTests.UnreachableEpoch, + }, 1) require.Nil(t, err) defer testContext.Close() @@ -32,7 +34,7 @@ func TestRelayedMoveBalanceShouldWork(t *testing.T) { rcvAddr := []byte("12345678901234567890123456789022") senderNonce := uint64(0) - senderBalance := big.NewInt(0) + senderBalance := big.NewInt(100) gasLimit := uint64(100) _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) @@ -42,8 +44,8 @@ func TestRelayedMoveBalanceShouldWork(t *testing.T) { userTx := vm.CreateTransaction(senderNonce, big.NewInt(100), sndAddr, rcvAddr, gasPrice, gasLimit, []byte("aaaa")) rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rTxGasLimit := gasLimit + minGasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) require.Equal(t, vmcommon.Ok, retCode) @@ -53,8 +55,8 @@ func TestRelayedMoveBalanceShouldWork(t *testing.T) { require.Nil(t, err) // check relayer balance - // 3000 - value(100) - gasLimit(275)*gasPrice(10) = 2850 - expectedBalanceRelayer := big.NewInt(150) + // 3000 - rTxFee(175)*gasPrice(10) + txFeeInner(1000) = 2750 + expectedBalanceRelayer := big.NewInt(250) vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) // check balance inner tx sender @@ -73,7 +75,7 @@ func TestRelayedMoveBalanceInvalidGasLimitShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -88,7 +90,7 @@ func TestRelayedMoveBalanceInvalidGasLimitShouldConsumeGas(t *testing.T) { rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) rTxGasLimit := 2 + userTx.GasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, 1, rTxGasLimit, rtxData) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, 1, rTxGasLimit, rtxData) _, err = testContext.TxProcessor.ProcessTransaction(rtx) require.Equal(t, process.ErrFailedTransaction, err) @@ -109,7 +111,9 @@ func TestRelayedMoveBalanceInvalidUserTxShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: integrationTests.UnreachableEpoch, + }, 1) require.Nil(t, err) defer testContext.Close() @@ -117,14 +121,14 @@ func TestRelayedMoveBalanceInvalidUserTxShouldConsumeGas(t *testing.T) { sndAddr := []byte("12345678901234567890123456789012") rcvAddr := []byte("12345678901234567890123456789022") - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(100)) userTx := vm.CreateTransaction(1, big.NewInt(100), sndAddr, rcvAddr, 1, 100, []byte("aaaa")) _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(3000)) rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + userTx.GasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, 1, rTxGasLimit, rtxData) + rTxGasLimit := minGasLimit + userTx.GasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, 1, rTxGasLimit, rtxData) retcode, _ := testContext.TxProcessor.ProcessTransaction(rtx) require.Equal(t, vmcommon.UserError, retcode) @@ -132,6 +136,7 @@ func TestRelayedMoveBalanceInvalidUserTxShouldConsumeGas(t *testing.T) { _, err = testContext.Accounts.Commit() require.Nil(t, err) + // 3000 - rTxFee(179)*gasPrice(1) - innerTxFee(100) = 2721 expectedBalanceRelayer := big.NewInt(2721) vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) @@ -146,8 +151,9 @@ func TestRelayedMoveBalanceInvalidUserTxValueShouldConsumeGas(t *testing.T) { } testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ - RelayedNonceFixEnableEpoch: 1, - }) + RelayedNonceFixEnableEpoch: 1, + FixRelayedBaseCostEnableEpoch: integrationTests.UnreachableEpoch, + }, 1) require.Nil(t, err) defer testContext.Close() @@ -155,14 +161,14 @@ func TestRelayedMoveBalanceInvalidUserTxValueShouldConsumeGas(t *testing.T) { sndAddr := []byte("12345678901234567890123456789012") rcvAddr := []byte("12345678901234567890123456789022") - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(100)) userTx := vm.CreateTransaction(0, big.NewInt(150), sndAddr, rcvAddr, 1, 100, []byte("aaaa")) _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(3000)) rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + userTx.GasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, big.NewInt(100), relayerAddr, sndAddr, 1, rTxGasLimit, rtxData) + rTxGasLimit := minGasLimit + userTx.GasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, 1, rTxGasLimit, rtxData) retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) require.Equal(t, vmcommon.UserError, retCode) @@ -170,6 +176,7 @@ func TestRelayedMoveBalanceInvalidUserTxValueShouldConsumeGas(t *testing.T) { _, err = testContext.Accounts.Commit() require.Nil(t, err) + // 3000 - rTxFee(175)*gasPrice(1) - innerTxFee(100) = 2750 expectedBalanceRelayer := big.NewInt(2725) vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) @@ -185,7 +192,7 @@ func TestRelayedMoveBalanceHigherNonce(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ RelayedNonceFixEnableEpoch: 1, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -241,7 +248,7 @@ func TestRelayedMoveBalanceLowerNonce(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ RelayedNonceFixEnableEpoch: 1, - }) + }, 1) require.Nil(t, err) defer testContext.Close() @@ -305,6 +312,7 @@ func TestRelayedMoveBalanceHigherNonceWithActivatedFixCrossShard(t *testing.T) { shardCoordinator0, integrationtests.CreateMemUnit(), vm.CreateMockGasScheduleNotifier(), + 1, ) require.Nil(t, err) @@ -314,6 +322,7 @@ func TestRelayedMoveBalanceHigherNonceWithActivatedFixCrossShard(t *testing.T) { shardCoordinator1, integrationtests.CreateMemUnit(), vm.CreateMockGasScheduleNotifier(), + 1, ) require.Nil(t, err) defer testContext0.Close() @@ -357,7 +366,7 @@ func executeRelayedTransaction( ) { testContext.TxsLogsProcessor.Clean() relayerAccount := getAccount(tb, testContext, relayerAddress) - gasLimit := 1 + userTx.GasLimit + uint64(len(userTxPrepared)) + gasLimit := minGasLimit + userTx.GasLimit + uint64(len(userTxPrepared)) relayedTx := vm.CreateTransaction(relayerAccount.GetNonce(), value, relayerAddress, senderAddress, 1, gasLimit, userTxPrepared) retCode, _ := testContext.TxProcessor.ProcessTransaction(relayedTx) diff --git a/integrationTests/vm/txsFee/relayedScCalls_test.go b/integrationTests/vm/txsFee/relayedScCalls_test.go index 7441d55541f..20ee29b02e5 100644 --- a/integrationTests/vm/txsFee/relayedScCalls_test.go +++ b/integrationTests/vm/txsFee/relayedScCalls_test.go @@ -19,47 +19,59 @@ func TestRelayedScCallShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ - DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed base cost fix", testRelayedScCallShouldWork(integrationTests.UnreachableEpoch, big.NewInt(29982306), big.NewInt(25903), big.NewInt(1608))) + t.Run("after relayed base cost fix", testRelayedScCallShouldWork(0, big.NewInt(29982216), big.NewInt(25993), big.NewInt(1608))) +} - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") - utils.CleanAccumulatedIntermediateTransactions(t, testContext) +func testRelayedScCallShouldWork( + relayedFixActivationEpoch uint32, + expectedRelayerBalance *big.Int, + expectedAccFees *big.Int, + expectedDevFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789112") - gasLimit := uint64(100000) + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9991691, 8309, 39) + utils.CleanAccumulatedIntermediateTransactions(t, testContext) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000000)) + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789112") + gasLimit := uint64(100000) - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddress, gasPrice, gasLimit, []byte("increment")) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000000)) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddress, gasPrice, gasLimit, []byte("increment")) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) - ret := vm.GetIntValueFromSC(nil, testContext.Accounts, scAddress, "get") - require.Equal(t, big.NewInt(2), ret) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalance := big.NewInt(29840970) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) + ret := vm.GetIntValueFromSC(nil, testContext.Accounts, scAddress, "get") + require.Equal(t, big.NewInt(2), ret) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(170830), accumulatedFees) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedRelayerBalance) - developerFees := testContext.TxFeeHandler.GetDeveloperFees() - require.Equal(t, big.NewInt(16093), developerFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccFees, accumulatedFees) + + developerFees := testContext.TxFeeHandler.GetDeveloperFees() + require.Equal(t, expectedDevFees, developerFees) + } } func TestRelayedScCallContractNotFoundShouldConsumeGas(t *testing.T) { @@ -67,42 +79,54 @@ func TestRelayedScCallContractNotFoundShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed fix", testRelayedScCallContractNotFoundShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(27130), big.NewInt(2870))) + t.Run("after relayed fix", testRelayedScCallContractNotFoundShouldConsumeGas(0, big.NewInt(27040), big.NewInt(2960))) +} - scAddress := "00000000000000000500dbb53e4b23392b0d6f36cce32deb2d623e9625ab3132" - scAddrBytes, _ := hex.DecodeString(scAddress) +func testRelayedScCallContractNotFoundShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedRelayerBalance *big.Int, + expectedAccFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789112") - gasLimit := uint64(1000) + scAddress := "00000000000000000500dbb53e4b23392b0d6f36cce32deb2d623e9625ab3132" + scAddrBytes, _ := hex.DecodeString(scAddress) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789112") + gasLimit := uint64(1000) - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddrBytes, gasPrice, gasLimit, []byte("increment")) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddrBytes, gasPrice, gasLimit, []byte("increment")) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) - require.Nil(t, err) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) + require.Nil(t, err) + + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalance := big.NewInt(18130) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedRelayerBalance) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(11870), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccFees, accumulatedFees) - developerFees := testContext.TxFeeHandler.GetDeveloperFees() - require.Equal(t, big.NewInt(0), developerFees) + developerFees := testContext.TxFeeHandler.GetDeveloperFees() + require.Equal(t, big.NewInt(0), developerFees) + } } func TestRelayedScCallInvalidMethodShouldConsumeGas(t *testing.T) { @@ -110,42 +134,54 @@ func TestRelayedScCallInvalidMethodShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed fix", testRelayedScCallInvalidMethodShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(26924), big.NewInt(11385))) + t.Run("after relayed fix", testRelayedScCallInvalidMethodShouldConsumeGas(0, big.NewInt(26924), big.NewInt(11385))) +} - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") - utils.CleanAccumulatedIntermediateTransactions(t, testContext) +func testRelayedScCallInvalidMethodShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedRelayerBalance *big.Int, + expectedAccFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + RelayedNonceFixEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789112") - gasLimit := uint64(1000) + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9991691, 8309, 39) + utils.CleanAccumulatedIntermediateTransactions(t, testContext) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789112") + gasLimit := uint64(1000) - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddress, gasPrice, gasLimit, []byte("invalidMethod")) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddress, gasPrice, gasLimit, []byte("invalidMethod")) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) - require.Nil(t, err) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) + require.Nil(t, err) - expectedBalance := big.NewInt(18050) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(23850), accumulatedFees) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedRelayerBalance) - developerFees := testContext.TxFeeHandler.GetDeveloperFees() - require.Equal(t, big.NewInt(399), developerFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccFees, accumulatedFees) + + developerFees := testContext.TxFeeHandler.GetDeveloperFees() + require.Equal(t, big.NewInt(39), developerFees) + } } func TestRelayedScCallInsufficientGasLimitShouldConsumeGas(t *testing.T) { @@ -153,41 +189,54 @@ func TestRelayedScCallInsufficientGasLimitShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed fix", testRelayedScCallInsufficientGasLimitShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(28140), big.NewInt(10169))) + t.Run("after relayed fix", testRelayedScCallInsufficientGasLimitShouldConsumeGas(0, big.NewInt(28050), big.NewInt(10259))) +} - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") - utils.CleanAccumulatedIntermediateTransactions(t, testContext) +func testRelayedScCallInsufficientGasLimitShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedBalance *big.Int, + expectedAccumulatedFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789112") - gasLimit := uint64(5) + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9991691, 8309, 39) + utils.CleanAccumulatedIntermediateTransactions(t, testContext) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789112") + data := "increment" + gasLimit := minGasLimit + uint64(len(data)) - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddress, gasPrice, gasLimit, []byte("increment")) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddress, gasPrice, gasLimit, []byte(data)) - retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) + + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalance := big.NewInt(28100) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(13800), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccumulatedFees, accumulatedFees) - developerFees := testContext.TxFeeHandler.GetDeveloperFees() - require.Equal(t, big.NewInt(399), developerFees) + developerFees := testContext.TxFeeHandler.GetDeveloperFees() + require.Equal(t, big.NewInt(39), developerFees) + } } func TestRelayedScCallOutOfGasShouldConsumeGas(t *testing.T) { @@ -195,42 +244,54 @@ func TestRelayedScCallOutOfGasShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed fix", testRelayedScCallOutOfGasShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(28040), big.NewInt(10269))) + t.Run("after relayed fix", testRelayedScCallOutOfGasShouldConsumeGas(0, big.NewInt(28040), big.NewInt(10269))) +} - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") - utils.CleanAccumulatedIntermediateTransactions(t, testContext) +func testRelayedScCallOutOfGasShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedRelayerBalance *big.Int, + expectedAccFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + RelayedNonceFixEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789112") - gasLimit := uint64(20) + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9991691, 8309, 39) + utils.CleanAccumulatedIntermediateTransactions(t, testContext) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789112") + gasLimit := uint64(20) - userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddress, gasPrice, gasLimit, []byte("increment")) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, big.NewInt(0)) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(30000)) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + userTx := vm.CreateTransaction(0, big.NewInt(100), sndAddr, scAddress, gasPrice, gasLimit, []byte("increment")) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) - require.Nil(t, err) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) + require.Nil(t, err) + + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalance := big.NewInt(27950) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedRelayerBalance) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(13950), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccFees, accumulatedFees) - developerFees := testContext.TxFeeHandler.GetDeveloperFees() - require.Equal(t, big.NewInt(399), developerFees) + developerFees := testContext.TxFeeHandler.GetDeveloperFees() + require.Equal(t, big.NewInt(39), developerFees) + } } func TestRelayedDeployInvalidContractShouldIncrementNonceOnSender(t *testing.T) { @@ -281,7 +342,7 @@ func testRelayedDeployInvalidContractShouldIncrementNonceOnSender( senderAddr []byte, senderNonce uint64, ) *vm.VMTestContext { - testContext, err := vm.CreatePreparedTxProcessorWithVMs(enableEpochs) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(enableEpochs, 1) require.Nil(t, err) relayerAddr := []byte("12345678901234567890123456789033") @@ -294,7 +355,7 @@ func testRelayedDeployInvalidContractShouldIncrementNonceOnSender( userTx := vm.CreateTransaction(senderNonce, big.NewInt(100), senderAddr, emptyAddress, gasPrice, gasLimit, nil) rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) + rTxGasLimit := minGasLimit + gasLimit + uint64(len(rtxData)) rtx := vm.CreateTransaction(0, userTx.Value, relayerAddr, senderAddr, gasPrice, rTxGasLimit, rtxData) retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) diff --git a/integrationTests/vm/txsFee/relayedScDeploy_test.go b/integrationTests/vm/txsFee/relayedScDeploy_test.go index 15d6d677b44..21bd43df7e2 100644 --- a/integrationTests/vm/txsFee/relayedScDeploy_test.go +++ b/integrationTests/vm/txsFee/relayedScDeploy_test.go @@ -17,43 +17,55 @@ func TestRelayedScDeployShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed fix", testRelayedScDeployShouldWork(integrationTests.UnreachableEpoch, big.NewInt(20170), big.NewInt(29830))) + t.Run("after relayed fix", testRelayedScDeployShouldWork(0, big.NewInt(8389), big.NewInt(41611))) +} + +func testRelayedScDeployShouldWork( + relayedFixActivationEpoch uint32, + expectedRelayerBalance *big.Int, + expectedAccFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789012") + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789012") - senderNonce := uint64(0) - senderBalance := big.NewInt(0) - gasLimit := uint64(1962) + senderNonce := uint64(0) + senderBalance := big.NewInt(0) + gasLimit := uint64(2000) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(50000)) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(50000)) - scCode := wasm.GetSCCode("../wasm/testdata/misc/fib_wasm/output/fib_wasm.wasm") - userTx := vm.CreateTransaction(senderNonce, big.NewInt(0), sndAddr, vm.CreateEmptyAddress(), gasPrice, gasLimit, []byte(wasm.CreateDeployTxData(scCode))) + scCode := wasm.GetSCCode("../wasm/testdata/misc/fib_wasm/output/fib_wasm.wasm") + userTx := vm.CreateTransaction(senderNonce, big.NewInt(0), sndAddr, vm.CreateEmptyAddress(), gasPrice, gasLimit, []byte(wasm.CreateDeployTxData(scCode))) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.Ok, retCode) - require.Nil(t, err) + retCode, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.Ok, retCode) + require.Nil(t, err) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalanceRelayer := big.NewInt(2530) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedRelayerBalance) - // check balance inner tx sender - vm.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) + // check balance inner tx sender + vm.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(47470), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccFees, accumulatedFees) + } } func TestRelayedScDeployInvalidCodeShouldConsumeGas(t *testing.T) { @@ -61,44 +73,56 @@ func TestRelayedScDeployInvalidCodeShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed fix", testRelayedScDeployInvalidCodeShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(20716), big.NewInt(29284))) + t.Run("after relayed fix", testRelayedScDeployInvalidCodeShouldConsumeGas(0, big.NewInt(8890), big.NewInt(41110))) +} + +func testRelayedScDeployInvalidCodeShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedBalance *big.Int, + expectedAccumulatedFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789012") + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789012") - senderNonce := uint64(0) - senderBalance := big.NewInt(0) - gasLimit := uint64(500) + senderNonce := uint64(0) + senderBalance := big.NewInt(0) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(50000)) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(50000)) - scCode := wasm.GetSCCode("../wasm/testdata/misc/fib_wasm/output/fib_wasm.wasm") - scCodeBytes := []byte(wasm.CreateDeployTxData(scCode)) - scCodeBytes = append(scCodeBytes, []byte("aaaaa")...) - userTx := vm.CreateTransaction(senderNonce, big.NewInt(0), sndAddr, vm.CreateEmptyAddress(), gasPrice, gasLimit, scCodeBytes) + scCode := wasm.GetSCCode("../wasm/testdata/misc/fib_wasm/output/fib_wasm.wasm") + scCodeBytes := []byte(wasm.CreateDeployTxData(scCode)) + scCodeBytes = append(scCodeBytes, []byte("aaaaa")...) + gasLimit := minGasLimit + uint64(len(scCodeBytes)) + userTx := vm.CreateTransaction(senderNonce, big.NewInt(0), sndAddr, vm.CreateEmptyAddress(), gasPrice, gasLimit, scCodeBytes) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) + retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalanceRelayer := big.NewInt(17030) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) - // check balance inner tx sender - vm.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) + // check balance inner tx sender + vm.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(32970), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccumulatedFees, accumulatedFees) + } } func TestRelayedScDeployInsufficientGasLimitShouldConsumeGas(t *testing.T) { @@ -106,42 +130,55 @@ func TestRelayedScDeployInsufficientGasLimitShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed fix", testRelayedScDeployInsufficientGasLimitShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(20821), big.NewInt(29179))) + t.Run("after relayed fix", testRelayedScDeployInsufficientGasLimitShouldConsumeGas(0, big.NewInt(9040), big.NewInt(40960))) +} + +func testRelayedScDeployInsufficientGasLimitShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedBalance *big.Int, + expectedAccumulatedFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789012") + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789012") - senderNonce := uint64(0) - senderBalance := big.NewInt(0) - gasLimit := uint64(500) + senderNonce := uint64(0) + senderBalance := big.NewInt(0) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(50000)) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(50000)) - scCode := wasm.GetSCCode("../wasm/testdata/misc/fib_wasm/output/fib_wasm.wasm") - userTx := vm.CreateTransaction(senderNonce, big.NewInt(0), sndAddr, vm.CreateEmptyAddress(), gasPrice, gasLimit, []byte(wasm.CreateDeployTxData(scCode))) + scCode := wasm.GetSCCode("../wasm/testdata/misc/fib_wasm/output/fib_wasm.wasm") + data := wasm.CreateDeployTxData(scCode) + gasLimit := minGasLimit + uint64(len(data)) + userTx := vm.CreateTransaction(senderNonce, big.NewInt(0), sndAddr, vm.CreateEmptyAddress(), gasPrice, gasLimit, []byte(data)) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, retCode) + retCode, _ := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, retCode) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalanceRelayer := big.NewInt(17130) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) - // check balance inner tx sender - vm.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) + // check balance inner tx sender + vm.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(32870), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccumulatedFees, accumulatedFees) + } } func TestRelayedScDeployOutOfGasShouldConsumeGas(t *testing.T) { @@ -149,41 +186,54 @@ func TestRelayedScDeployOutOfGasShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) - require.Nil(t, err) - defer testContext.Close() + t.Run("before relayed fix", testRelayedScDeployOutOfGasShouldConsumeGas(integrationTests.UnreachableEpoch, big.NewInt(20821), big.NewInt(29179))) + t.Run("after relayed fix", testRelayedScDeployOutOfGasShouldConsumeGas(0, big.NewInt(9040), big.NewInt(40960))) +} + +func testRelayedScDeployOutOfGasShouldConsumeGas( + relayedFixActivationEpoch uint32, + expectedBalance *big.Int, + expectedAccumulatedFees *big.Int, +) func(t *testing.T) { + return func(t *testing.T) { + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ + FixRelayedBaseCostEnableEpoch: relayedFixActivationEpoch, + }, gasPriceModifier) + require.Nil(t, err) + defer testContext.Close() - relayerAddr := []byte("12345678901234567890123456789033") - sndAddr := []byte("12345678901234567890123456789012") + relayerAddr := []byte("12345678901234567890123456789033") + sndAddr := []byte("12345678901234567890123456789012") - senderNonce := uint64(0) - senderBalance := big.NewInt(0) - gasLimit := uint64(570) + senderNonce := uint64(0) + senderBalance := big.NewInt(0) - _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) - _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(50000)) + _, _ = vm.CreateAccount(testContext.Accounts, sndAddr, 0, senderBalance) + _, _ = vm.CreateAccount(testContext.Accounts, relayerAddr, 0, big.NewInt(50000)) - scCode := wasm.GetSCCode("../wasm/testdata/misc/fib_wasm/output/fib_wasm.wasm") - userTx := vm.CreateTransaction(senderNonce, big.NewInt(0), sndAddr, vm.CreateEmptyAddress(), gasPrice, gasLimit, []byte(wasm.CreateDeployTxData(scCode))) + scCode := wasm.GetSCCode("../wasm/testdata/misc/fib_wasm/output/fib_wasm.wasm") + data := wasm.CreateDeployTxData(scCode) + gasLimit := minGasLimit + uint64(len(data)) + userTx := vm.CreateTransaction(senderNonce, big.NewInt(0), sndAddr, vm.CreateEmptyAddress(), gasPrice, gasLimit, []byte(data)) - rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) - rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) - rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) + rtxData := integrationTests.PrepareRelayedTxDataV1(userTx) + rTxGasLimit := 1 + gasLimit + uint64(len(rtxData)) + rtx := vm.CreateTransaction(0, big.NewInt(0), relayerAddr, sndAddr, gasPrice, rTxGasLimit, rtxData) - code, err := testContext.TxProcessor.ProcessTransaction(rtx) - require.Equal(t, vmcommon.UserError, code) - require.Nil(t, err) + code, err := testContext.TxProcessor.ProcessTransaction(rtx) + require.Equal(t, vmcommon.UserError, code) + require.Nil(t, err) - _, err = testContext.Accounts.Commit() - require.Nil(t, err) + _, err = testContext.Accounts.Commit() + require.Nil(t, err) - expectedBalanceRelayer := big.NewInt(16430) - vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalanceRelayer) + vm.TestAccount(t, testContext.Accounts, relayerAddr, 1, expectedBalance) - // check balance inner tx sender - vm.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) + // check balance inner tx sender + vm.TestAccount(t, testContext.Accounts, sndAddr, 1, big.NewInt(0)) - // check accumulated fees - accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() - require.Equal(t, big.NewInt(33570), accumulatedFees) + // check accumulated fees + accumulatedFees := testContext.TxFeeHandler.GetAccumulatedFees() + require.Equal(t, expectedAccumulatedFees, accumulatedFees) + } } diff --git a/integrationTests/vm/txsFee/scCalls_test.go b/integrationTests/vm/txsFee/scCalls_test.go index 0c2262a9362..c17474eb9e3 100644 --- a/integrationTests/vm/txsFee/scCalls_test.go +++ b/integrationTests/vm/txsFee/scCalls_test.go @@ -66,6 +66,7 @@ func prepareTestContextForEpoch836(tb testing.TB) (*vm.VMTestContext, []byte) { db, gasScheduleNotifier, testscommon.GetDefaultRoundsConfig(), + 1, ) require.Nil(tb, err) @@ -92,11 +93,11 @@ func TestScCallShouldWork(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) utils.CleanAccumulatedIntermediateTransactions(t, testContext) sndAddr := []byte("12345678901234567890123456789112") @@ -138,7 +139,7 @@ func TestScCallContractNotFoundShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -171,11 +172,11 @@ func TestScCallInvalidMethodToCallShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) utils.CleanAccumulatedIntermediateTransactions(t, testContext) sndAddr := []byte("12345678901234567890123456789112") @@ -208,11 +209,11 @@ func TestScCallInsufficientGasLimitShouldNotConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) sndAddr := []byte("12345678901234567890123456789112") senderBalance := big.NewInt(100000) @@ -246,11 +247,11 @@ func TestScCallOutOfGasShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) utils.CleanAccumulatedIntermediateTransactions(t, testContext) sndAddr := []byte("12345678901234567890123456789112") @@ -285,13 +286,13 @@ func TestScCallAndGasChangeShouldWork(t *testing.T) { testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{ DynamicGasCostForDataTrieStorageLoadEnableEpoch: integrationTests.UnreachableEpoch, - }) + }, 1) require.Nil(t, err) defer testContext.Close() mockGasSchedule := testContext.GasSchedule.(*mock.GasScheduleNotifierMock) - scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm") + scAddress, _ := utils.DoDeploy(t, testContext, "../wasm/testdata/counter/output/counter.wasm", 9988100, 11900, 399) utils.CleanAccumulatedIntermediateTransactions(t, testContext) sndAddr := []byte("12345678901234567890123456789112") @@ -332,7 +333,7 @@ func TestESDTScCallAndGasChangeShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -421,7 +422,7 @@ func prepareTestContextForEpoch460(tb testing.TB) (*vm.VMTestContext, []byte) { RefactorPeersMiniBlocksEnableEpoch: unreachableEpoch, RuntimeMemStoreLimitEnableEpoch: unreachableEpoch, MaxBlockchainHookCountersEnableEpoch: unreachableEpoch, - }) + }, 1) require.Nil(tb, err) senderBalance := big.NewInt(1000000000000000000) diff --git a/integrationTests/vm/txsFee/scDeploy_test.go b/integrationTests/vm/txsFee/scDeploy_test.go index 8410bcf4917..ea646e6db73 100644 --- a/integrationTests/vm/txsFee/scDeploy_test.go +++ b/integrationTests/vm/txsFee/scDeploy_test.go @@ -17,7 +17,7 @@ func TestScDeployShouldWork(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -52,7 +52,7 @@ func TestScDeployInvalidContractCodeShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -88,7 +88,7 @@ func TestScDeployInsufficientGasLimitShouldNotConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() @@ -123,7 +123,7 @@ func TestScDeployOutOfGasShouldConsumeGas(t *testing.T) { t.Skip("this is not a short test") } - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) defer testContext.Close() diff --git a/integrationTests/vm/txsFee/utils/utils.go b/integrationTests/vm/txsFee/utils/utils.go index 3eea35a4833..bc7abfbeaf0 100644 --- a/integrationTests/vm/txsFee/utils/utils.go +++ b/integrationTests/vm/txsFee/utils/utils.go @@ -37,8 +37,11 @@ func DoDeploy( t *testing.T, testContext *vm.VMTestContext, pathToContract string, + expectedBalance, + expectedAccFees, + expectedDevFees int64, ) (scAddr []byte, owner []byte) { - return doDeployInternal(t, testContext, pathToContract, 9988100, 11900, 399) + return doDeployInternal(t, testContext, pathToContract, expectedBalance, expectedAccFees, expectedDevFees) } // DoDeployOldCounter - diff --git a/integrationTests/vm/txsFee/validatorSC_test.go b/integrationTests/vm/txsFee/validatorSC_test.go index 6de545c5c93..c54025a90b1 100644 --- a/integrationTests/vm/txsFee/validatorSC_test.go +++ b/integrationTests/vm/txsFee/validatorSC_test.go @@ -54,7 +54,7 @@ func TestValidatorsSC_DoStakePutInQueueUnStakeAndUnBondShouldRefund(t *testing.T t.Skip("this is not a short test") } - testContextMeta, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(core.MetachainShardId, config.EnableEpochs{}) + testContextMeta, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(core.MetachainShardId, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextMeta.Close() @@ -120,6 +120,7 @@ func TestValidatorsSC_DoStakePutInQueueUnStakeAndUnBondTokensShouldRefund(t *tes StakingV4Step1EnableEpoch: stakingV4Step1EnableEpoch, StakingV4Step2EnableEpoch: stakingV4Step2EnableEpoch, }, + 1, ) require.Nil(t, err) @@ -170,7 +171,7 @@ func TestValidatorsSC_DoStakeWithTopUpValueTryToUnStakeTokensAndUnBondTokens(t * } func testValidatorsSCDoStakeWithTopUpValueTryToUnStakeTokensAndUnBondTokens(t *testing.T, enableEpochs config.EnableEpochs) { - testContextMeta, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(core.MetachainShardId, enableEpochs) + testContextMeta, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(core.MetachainShardId, enableEpochs, 1) require.Nil(t, err) defer testContextMeta.Close() @@ -207,6 +208,7 @@ func TestValidatorsSC_ToStakePutInQueueUnStakeAndUnBondShouldRefundUnBondTokens( StakingV4Step1EnableEpoch: stakingV4Step1EnableEpoch, StakingV4Step2EnableEpoch: stakingV4Step2EnableEpoch, }, + 1, ) require.Nil(t, err) @@ -263,6 +265,7 @@ func TestValidatorsSC_ToStakePutInQueueUnStakeNodesAndUnBondNodesShouldRefund(t StakingV4Step1EnableEpoch: stakingV4Step1EnableEpoch, StakingV4Step2EnableEpoch: stakingV4Step2EnableEpoch, }, + 1, ) require.Nil(t, err) diff --git a/integrationTests/vm/wasm/utils.go b/integrationTests/vm/wasm/utils.go index bfe7b4b7ca9..7ec28bb8f45 100644 --- a/integrationTests/vm/wasm/utils.go +++ b/integrationTests/vm/wasm/utils.go @@ -53,6 +53,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/guardianMocks" "github.com/multiversx/mx-chain-go/testscommon/integrationtests" "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" storageStubs "github.com/multiversx/mx-chain-go/testscommon/storage" "github.com/multiversx/mx-chain-go/vm/systemSmartContracts/defaults" vmcommon "github.com/multiversx/mx-chain-vm-common-go" @@ -391,37 +392,40 @@ func (context *TestContext) initTxProcessorWithOneSCExecutorWithVMs() { GasHandler: &testscommon.GasHandlerStub{ SetGasRefundedCalled: func(gasRefunded uint64, hash []byte) {}, }, - GasSchedule: mock.NewGasScheduleNotifierMock(gasSchedule), - TxLogsProcessor: context.TxLogsProcessor, - EnableRoundsHandler: context.EnableRoundsHandler, - EnableEpochsHandler: context.EnableEpochsHandler, - WasmVMChangeLocker: context.WasmVMChangeLocker, - VMOutputCacher: txcache.NewDisabledCache(), + GasSchedule: mock.NewGasScheduleNotifierMock(gasSchedule), + TxLogsProcessor: context.TxLogsProcessor, + EnableRoundsHandler: context.EnableRoundsHandler, + EnableEpochsHandler: context.EnableEpochsHandler, + WasmVMChangeLocker: context.WasmVMChangeLocker, + VMOutputCacher: txcache.NewDisabledCache(), + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } context.ScProcessor, err = processProxy.NewTestSmartContractProcessorProxy(argsNewSCProcessor, context.EpochNotifier) require.Nil(context.T, err) argsNewTxProcessor := processTransaction.ArgsNewTxProcessor{ - Accounts: context.Accounts, - Hasher: hasher, - PubkeyConv: pkConverter, - Marshalizer: marshalizer, - SignMarshalizer: marshalizer, - ShardCoordinator: oneShardCoordinator, - ScProcessor: context.ScProcessor, - TxFeeHandler: context.UnsignexTxHandler, - TxTypeHandler: txTypeHandler, - EconomicsFee: context.EconomicsFee, - ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, - BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, - ArgsParser: smartContract.NewArgumentParser(), - ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, - EnableRoundsHandler: context.EnableRoundsHandler, - EnableEpochsHandler: context.EnableEpochsHandler, - TxVersionChecker: &testscommon.TxVersionCheckerStub{}, - GuardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, - TxLogsProcessor: context.TxLogsProcessor, + Accounts: context.Accounts, + Hasher: hasher, + PubkeyConv: pkConverter, + Marshalizer: marshalizer, + SignMarshalizer: marshalizer, + ShardCoordinator: oneShardCoordinator, + ScProcessor: context.ScProcessor, + TxFeeHandler: context.UnsignexTxHandler, + TxTypeHandler: txTypeHandler, + EconomicsFee: context.EconomicsFee, + ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, + BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, + ArgsParser: smartContract.NewArgumentParser(), + ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, + EnableRoundsHandler: context.EnableRoundsHandler, + EnableEpochsHandler: context.EnableEpochsHandler, + TxVersionChecker: &testscommon.TxVersionCheckerStub{}, + GuardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, + TxLogsProcessor: context.TxLogsProcessor, + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } context.TxProcessor, err = processTransaction.NewTxProcessor(argsNewTxProcessor) diff --git a/integrationTests/vm/wasm/wasmvm/scenariosConverter/scenariosConverterUtils.go b/integrationTests/vm/wasm/wasmvm/scenariosConverter/scenariosConverterUtils.go index 2d3d15f681d..ad23085011f 100644 --- a/integrationTests/vm/wasm/wasmvm/scenariosConverter/scenariosConverterUtils.go +++ b/integrationTests/vm/wasm/wasmvm/scenariosConverter/scenariosConverterUtils.go @@ -119,7 +119,7 @@ func SetStateFromScenariosTest(scenariosTestPath string) (testContext *vm.VMTest if err != nil { return nil, nil, exporter.InvalidBenchmarkTxPos, err } - testContext, err = vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err = vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) if err != nil { return nil, nil, exporter.InvalidBenchmarkTxPos, err } @@ -140,7 +140,7 @@ func SetStateFromScenariosTest(scenariosTestPath string) (testContext *vm.VMTest func CheckConverter(t *testing.T, scenariosTestPath string) { stateAndBenchmarkInfo, err := exporter.GetAccountsAndTransactionsFromScenarios(scenariosTestPath) require.Nil(t, err) - testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}) + testContext, err := vm.CreatePreparedTxProcessorWithVMs(config.EnableEpochs{}, 1) require.Nil(t, err) err = CreateAccountsFromScenariosAccs(testContext, stateAndBenchmarkInfo.Accs) require.Nil(t, err) diff --git a/integrationTests/vm/wasm/wasmvm/wasmVM_test.go b/integrationTests/vm/wasm/wasmvm/wasmVM_test.go index 0028787d84e..9ad6a861235 100644 --- a/integrationTests/vm/wasm/wasmvm/wasmVM_test.go +++ b/integrationTests/vm/wasm/wasmvm/wasmVM_test.go @@ -31,6 +31,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/economicsmocks" "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/integrationtests" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" logger "github.com/multiversx/mx-chain-logger-go" vmcommon "github.com/multiversx/mx-chain-vm-common-go" "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" @@ -629,23 +630,25 @@ func TestExecuteTransactionAndTimeToProcessChange(t *testing.T) { _, _ = vm.CreateAccount(accnts, ownerAddressBytes, ownerNonce, ownerBalance) argsNewTxProcessor := processTransaction.ArgsNewTxProcessor{ - Accounts: accnts, - Hasher: testHasher, - PubkeyConv: pubkeyConv, - Marshalizer: testMarshalizer, - SignMarshalizer: testMarshalizer, - ShardCoordinator: shardCoordinator, - ScProcessor: &testscommon.SCProcessorMock{}, - TxFeeHandler: &testscommon.UnsignedTxHandlerStub{}, - TxTypeHandler: txTypeHandler, - EconomicsFee: &economicsmocks.EconomicsHandlerStub{}, - ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, - BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, - ArgsParser: smartContract.NewArgumentParser(), - ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, - EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, - EnableEpochsHandler: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, - TxLogsProcessor: &mock.TxLogsProcessorStub{}, + Accounts: accnts, + Hasher: testHasher, + PubkeyConv: pubkeyConv, + Marshalizer: testMarshalizer, + SignMarshalizer: testMarshalizer, + ShardCoordinator: shardCoordinator, + ScProcessor: &testscommon.SCProcessorMock{}, + TxFeeHandler: &testscommon.UnsignedTxHandlerStub{}, + TxTypeHandler: txTypeHandler, + EconomicsFee: &economicsmocks.EconomicsHandlerStub{}, + ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, + BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, + ArgsParser: smartContract.NewArgumentParser(), + ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, + EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, + EnableEpochsHandler: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + TxLogsProcessor: &mock.TxLogsProcessorStub{}, + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } txProc, _ := processTransaction.NewTxProcessor(argsNewTxProcessor) @@ -945,11 +948,11 @@ func TestCommunityContract_CrossShard_TxProcessor(t *testing.T) { zero := big.NewInt(0) transferEGLD := big.NewInt(42) - testContextFunderSC, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}) + testContextFunderSC, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(0, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextFunderSC.Close() - testContextParentSC, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}) + testContextParentSC, err := vm.CreatePreparedTxProcessorWithVMsMultiShard(1, config.EnableEpochs{}, 1) require.Nil(t, err) defer testContextParentSC.Close() diff --git a/node/chainSimulator/chainSimulator.go b/node/chainSimulator/chainSimulator.go index 8004d629b2f..742d040c8c8 100644 --- a/node/chainSimulator/chainSimulator.go +++ b/node/chainSimulator/chainSimulator.go @@ -42,22 +42,23 @@ type transactionWithResult struct { // ArgsChainSimulator holds the arguments needed to create a new instance of simulator type ArgsChainSimulator struct { - BypassTxSignatureCheck bool - TempDir string - PathToInitialConfig string - NumOfShards uint32 - MinNodesPerShard uint32 - MetaChainMinNodes uint32 - NumNodesWaitingListShard uint32 - NumNodesWaitingListMeta uint32 - GenesisTimestamp int64 - InitialRound int64 - InitialEpoch uint32 - InitialNonce uint64 - RoundDurationInMillis uint64 - RoundsPerEpoch core.OptionalUint64 - ApiInterface components.APIConfigurator - AlterConfigsFunction func(cfg *config.Configs) + BypassTxSignatureCheck bool + TempDir string + PathToInitialConfig string + NumOfShards uint32 + MinNodesPerShard uint32 + MetaChainMinNodes uint32 + NumNodesWaitingListShard uint32 + NumNodesWaitingListMeta uint32 + GenesisTimestamp int64 + InitialRound int64 + InitialEpoch uint32 + InitialNonce uint64 + RoundDurationInMillis uint64 + RoundsPerEpoch core.OptionalUint64 + ApiInterface components.APIConfigurator + AlterConfigsFunction func(cfg *config.Configs) + VmQueryDelayAfterStartInMs uint64 } // ArgsBaseChainSimulator holds the arguments needed to create a new instance of simulator @@ -156,7 +157,7 @@ func (s *simulator) createChainHandlers(args ArgsBaseChainSimulator) error { } allValidatorsInfo, errGet := node.GetProcessComponents().ValidatorsStatistics().GetValidatorInfoForRootHash(currentRootHash) - if errRootHash != nil { + if errGet != nil { return errGet } @@ -212,6 +213,7 @@ func (s *simulator) createTestNode( MinNodesMeta: args.MetaChainMinNodes, MetaChainConsensusGroupSize: args.MetaChainConsensusGroupSize, RoundDurationInMillis: args.RoundDurationInMillis, + VmQueryDelayAfterStartInMs: args.VmQueryDelayAfterStartInMs, } return components.NewTestOnlyProcessingNode(argsTestOnlyProcessorNode) diff --git a/node/chainSimulator/chainSimulator_test.go b/node/chainSimulator/chainSimulator_test.go index 15a32de29c8..18f54ccbfe9 100644 --- a/node/chainSimulator/chainSimulator_test.go +++ b/node/chainSimulator/chainSimulator_test.go @@ -1,16 +1,19 @@ package chainSimulator import ( + "github.com/multiversx/mx-chain-go/errors" "math/big" + "strings" "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" chainSimulatorCommon "github.com/multiversx/mx-chain-go/integrationTests/chainSimulator" "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" - - "github.com/multiversx/mx-chain-core-go/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -27,7 +30,7 @@ func TestNewChainSimulator(t *testing.T) { startTime := time.Now().Unix() roundDurationInMillis := uint64(6000) chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -54,7 +57,7 @@ func TestChainSimulator_GenerateBlocksShouldWork(t *testing.T) { startTime := time.Now().Unix() roundDurationInMillis := uint64(6000) chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -100,7 +103,7 @@ func TestChainSimulator_GenerateBlocksAndEpochChangeShouldWork(t *testing.T) { Value: 20, } chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -157,7 +160,7 @@ func TestSimulator_TriggerChangeOfEpoch(t *testing.T) { Value: 15000, } chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -202,7 +205,7 @@ func TestChainSimulator_SetState(t *testing.T) { Value: 20, } chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -233,7 +236,7 @@ func TestChainSimulator_SetEntireState(t *testing.T) { Value: 20, } chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -281,7 +284,7 @@ func TestChainSimulator_SetEntireStateWithRemoval(t *testing.T) { Value: 20, } chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -328,7 +331,7 @@ func TestChainSimulator_GetAccount(t *testing.T) { Value: 20, } chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -362,7 +365,7 @@ func TestSimulator_SendTransactions(t *testing.T) { Value: 20, } chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, TempDir: t.TempDir(), PathToInitialConfig: defaultPathToInitialConfig, NumOfShards: 3, @@ -380,3 +383,50 @@ func TestSimulator_SendTransactions(t *testing.T) { chainSimulatorCommon.CheckGenerateTransactions(t, chainSimulator) } + +func TestSimulator_SentMoveBalanceNoGasForFee(t *testing.T) { + if testing.Short() { + t.Skip("this is not a short test") + } + + startTime := time.Now().Unix() + roundDurationInMillis := uint64(6000) + roundsPerEpoch := core.OptionalUint64{ + HasValue: true, + Value: 20, + } + chainSimulator, err := NewChainSimulator(ArgsChainSimulator{ + BypassTxSignatureCheck: true, + TempDir: t.TempDir(), + PathToInitialConfig: defaultPathToInitialConfig, + NumOfShards: 3, + GenesisTimestamp: startTime, + RoundDurationInMillis: roundDurationInMillis, + RoundsPerEpoch: roundsPerEpoch, + ApiInterface: api.NewNoApiInterface(), + MinNodesPerShard: 1, + MetaChainMinNodes: 1, + }) + require.Nil(t, err) + require.NotNil(t, chainSimulator) + + defer chainSimulator.Close() + + wallet0, err := chainSimulator.GenerateAndMintWalletAddress(0, big.NewInt(0)) + require.Nil(t, err) + + ftx := &transaction.Transaction{ + Nonce: 0, + Value: big.NewInt(0), + SndAddr: wallet0.Bytes, + RcvAddr: wallet0.Bytes, + Data: []byte(""), + GasLimit: 50_000, + GasPrice: 1_000_000_000, + ChainID: []byte(configs.ChainID), + Version: 1, + Signature: []byte("010101"), + } + _, err = chainSimulator.sendTx(ftx) + require.True(t, strings.Contains(err.Error(), errors.ErrInsufficientFunds.Error())) +} diff --git a/node/chainSimulator/components/coreComponents_test.go b/node/chainSimulator/components/coreComponents_test.go index f8fc663fa64..7056d9ae48c 100644 --- a/node/chainSimulator/components/coreComponents_test.go +++ b/node/chainSimulator/components/coreComponents_test.go @@ -128,7 +128,7 @@ func createArgsCoreComponentsHolder() ArgsCoreComponentsHolder { ChanStopNodeProcess: make(chan endProcess.ArgEndProcess), InitialRound: 0, NodesSetupPath: "../../../sharding/mock/testdata/nodesSetupMock.json", - GasScheduleFilename: "../../../cmd/node/config/gasSchedules/gasScheduleV7.toml", + GasScheduleFilename: "../../../cmd/node/config/gasSchedules/gasScheduleV8.toml", NumShards: 3, WorkingDir: ".", MinNodesPerShard: 1, diff --git a/node/chainSimulator/components/cryptoComponents_test.go b/node/chainSimulator/components/cryptoComponents_test.go index fc8087f5cd4..3bba81c9b91 100644 --- a/node/chainSimulator/components/cryptoComponents_test.go +++ b/node/chainSimulator/components/cryptoComponents_test.go @@ -47,7 +47,7 @@ func createArgsCryptoComponentsHolder() ArgsCryptoComponentsHolder { }, }, AllValidatorKeysPemFileName: "allValidatorKeys.pem", - BypassTxSignatureCheck: false, + BypassTxSignatureCheck: true, } } diff --git a/node/chainSimulator/components/nodeFacade.go b/node/chainSimulator/components/nodeFacade.go index 7ed67018579..d62814fdf03 100644 --- a/node/chainSimulator/components/nodeFacade.go +++ b/node/chainSimulator/components/nodeFacade.go @@ -18,7 +18,7 @@ import ( "github.com/multiversx/mx-chain-go/process/mock" ) -func (node *testOnlyProcessingNode) createFacade(configs config.Configs, apiInterface APIConfigurator) error { +func (node *testOnlyProcessingNode) createFacade(configs config.Configs, apiInterface APIConfigurator, vmQueryDelayAfterStartInMs uint64) error { log.Debug("creating api resolver structure") err := node.createMetrics(configs) @@ -39,7 +39,7 @@ func (node *testOnlyProcessingNode) createFacade(configs config.Configs, apiInte allowVMQueriesChan := make(chan struct{}) go func() { - time.Sleep(time.Second) + time.Sleep(time.Duration(vmQueryDelayAfterStartInMs) * time.Millisecond) close(allowVMQueriesChan) node.StatusCoreComponents.AppStatusHandler().SetStringValue(common.MetricAreVMQueriesReady, strconv.FormatBool(true)) }() diff --git a/node/chainSimulator/components/processComponents.go b/node/chainSimulator/components/processComponents.go index 3bef305e8c7..6e00d776784 100644 --- a/node/chainSimulator/components/processComponents.go +++ b/node/chainSimulator/components/processComponents.go @@ -22,7 +22,7 @@ import ( "github.com/multiversx/mx-chain-go/genesis" "github.com/multiversx/mx-chain-go/genesis/parsing" "github.com/multiversx/mx-chain-go/process" - "github.com/multiversx/mx-chain-go/process/interceptors/disabled" + "github.com/multiversx/mx-chain-go/process/interceptors" "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/sharding/nodesCoordinator" "github.com/multiversx/mx-chain-go/storage/cache" @@ -100,6 +100,7 @@ type processComponentsHolder struct { accountsParser genesis.AccountsParser sentSignatureTracker process.SentSignaturesTracker epochStartSystemSCProcessor process.EpochStartSystemSCProcessor + relayedTxV3Processor process.RelayedTxV3Processor managedProcessComponentsCloser io.Closer } @@ -153,12 +154,22 @@ func CreateProcessComponents(args ArgsProcessComponentsHolder) (*processComponen return nil, err } - whiteListRequest, err := disabled.NewDisabledWhiteListDataVerifier() + lruCacheRequest, err := cache.NewLRUCache(int(args.Config.WhiteListPool.Capacity)) if err != nil { return nil, err + } + whiteListHandler, err := interceptors.NewWhiteListDataVerifier(lruCacheRequest) + if err != nil { + return nil, err + } + + lruCacheTx, err := cache.NewLRUCache(int(args.Config.WhiteListerVerifiedTxs.Capacity)) + if err != nil { + return nil, err - whiteListerVerifiedTxs, err := disabled.NewDisabledWhiteListDataVerifier() + } + whiteListVerifiedTxs, err := interceptors.NewWhiteListDataVerifier(lruCacheTx) if err != nil { return nil, err } @@ -196,8 +207,8 @@ func CreateProcessComponents(args ArgsProcessComponentsHolder) (*processComponen GasSchedule: gasScheduleNotifier, NodesCoordinator: args.NodesCoordinator, RequestedItemsHandler: requestedItemsHandler, - WhiteListHandler: whiteListRequest, - WhiteListerVerifiedTxs: whiteListerVerifiedTxs, + WhiteListHandler: whiteListHandler, + WhiteListerVerifiedTxs: whiteListVerifiedTxs, MaxRating: 50, SystemSCConfig: &args.SystemSCConfig, ImportStartHandler: importStartHandler, @@ -273,6 +284,7 @@ func CreateProcessComponents(args ArgsProcessComponentsHolder) (*processComponen accountsParser: managedProcessComponents.AccountsParser(), sentSignatureTracker: managedProcessComponents.SentSignaturesTracker(), epochStartSystemSCProcessor: managedProcessComponents.EpochSystemSCProcessor(), + relayedTxV3Processor: managedProcessComponents.RelayedTxV3Processor(), managedProcessComponentsCloser: managedProcessComponents, } @@ -513,6 +525,11 @@ func (p *processComponentsHolder) EpochSystemSCProcessor() process.EpochStartSys return p.epochStartSystemSCProcessor } +// RelayedTxV3Processor returns the relayed tx v3 processor +func (p *processComponentsHolder) RelayedTxV3Processor() process.RelayedTxV3Processor { + return p.relayedTxV3Processor +} + // Close will call the Close methods on all inner components func (p *processComponentsHolder) Close() error { return p.managedProcessComponentsCloser.Close() diff --git a/node/chainSimulator/components/processComponents_test.go b/node/chainSimulator/components/processComponents_test.go index efc5590e7f4..93b6a7689a3 100644 --- a/node/chainSimulator/components/processComponents_test.go +++ b/node/chainSimulator/components/processComponents_test.go @@ -66,7 +66,7 @@ func createArgsProcessComponentsHolder() ArgsProcessComponentsHolder { GasScheduleByEpochs: []config.GasScheduleByEpochs{ { StartEpoch: 0, - FileName: "../../../cmd/node/config/gasSchedules/gasScheduleV7.toml", + FileName: "../../../cmd/node/config/gasSchedules/gasScheduleV8.toml", }, }, }, @@ -408,6 +408,7 @@ func TestProcessComponentsHolder_Getters(t *testing.T) { require.NotNil(t, comp.AccountsParser()) require.NotNil(t, comp.ReceiptsRepository()) require.NotNil(t, comp.EpochSystemSCProcessor()) + require.NotNil(t, comp.RelayedTxV3Processor()) require.Nil(t, comp.CheckSubcomponents()) require.Empty(t, comp.String()) diff --git a/node/chainSimulator/components/statusComponents.go b/node/chainSimulator/components/statusComponents.go index fa0027ca967..be094472fc1 100644 --- a/node/chainSimulator/components/statusComponents.go +++ b/node/chainSimulator/components/statusComponents.go @@ -10,6 +10,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core/appStatusPolling" "github.com/multiversx/mx-chain-core-go/core/check" factoryMarshalizer "github.com/multiversx/mx-chain-core-go/marshal/factory" + indexerFactory "github.com/multiversx/mx-chain-es-indexer-go/process/factory" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/common/statistics" "github.com/multiversx/mx-chain-go/config" @@ -34,7 +35,7 @@ type statusComponentsHolder struct { } // CreateStatusComponents will create a new instance of status components holder -func CreateStatusComponents(shardID uint32, appStatusHandler core.AppStatusHandler, statusPollingIntervalSec int, external config.ExternalConfig) (*statusComponentsHolder, error) { +func CreateStatusComponents(shardID uint32, appStatusHandler core.AppStatusHandler, statusPollingIntervalSec int, external config.ExternalConfig, coreComponents process.CoreComponentsHolder) (*statusComponentsHolder, error) { if check.IfNil(appStatusHandler) { return nil, core.ErrNilAppStatusHandler } @@ -51,11 +52,12 @@ func CreateStatusComponents(shardID uint32, appStatusHandler core.AppStatusHandl return nil, err } instance.outportHandler, err = factory.CreateOutport(&factory.OutportFactoryArgs{ - IsImportDB: false, - ShardID: shardID, - RetrialInterval: time.Second, - HostDriversArgs: hostDriverArgs, - EventNotifierFactoryArgs: &factory.EventNotifierFactoryArgs{}, + IsImportDB: false, + ShardID: shardID, + RetrialInterval: time.Second, + HostDriversArgs: hostDriverArgs, + EventNotifierFactoryArgs: &factory.EventNotifierFactoryArgs{}, + ElasticIndexerFactoryArgs: makeElasticIndexerArgs(external, coreComponents), }) if err != nil { return nil, err @@ -90,6 +92,26 @@ func makeHostDriversArgs(external config.ExternalConfig) ([]factory.ArgsHostDriv return argsHostDriverFactorySlice, nil } +func makeElasticIndexerArgs(external config.ExternalConfig, coreComponents process.CoreComponentsHolder) indexerFactory.ArgsIndexerFactory { + elasticSearchConfig := external.ElasticSearchConnector + return indexerFactory.ArgsIndexerFactory{ + Enabled: elasticSearchConfig.Enabled, + BulkRequestMaxSize: elasticSearchConfig.BulkRequestMaxSizeInBytes, + Url: elasticSearchConfig.URL, + UserName: elasticSearchConfig.Username, + Password: elasticSearchConfig.Password, + Marshalizer: coreComponents.InternalMarshalizer(), + Hasher: coreComponents.Hasher(), + AddressPubkeyConverter: coreComponents.AddressPubKeyConverter(), + ValidatorPubkeyConverter: coreComponents.ValidatorPubKeyConverter(), + EnabledIndexes: elasticSearchConfig.EnabledIndexes, + Denomination: 18, + UseKibana: elasticSearchConfig.UseKibana, + ImportDB: false, + HeaderMarshaller: coreComponents.InternalMarshalizer(), + } +} + // OutportHandler will return the outport handler func (s *statusComponentsHolder) OutportHandler() outport.OutportHandler { return s.outportHandler diff --git a/node/chainSimulator/components/statusComponents_test.go b/node/chainSimulator/components/statusComponents_test.go index b6e2e296fbb..24f3b4595c1 100644 --- a/node/chainSimulator/components/statusComponents_test.go +++ b/node/chainSimulator/components/statusComponents_test.go @@ -21,7 +21,7 @@ func TestCreateStatusComponents(t *testing.T) { t.Run("should work", func(t *testing.T) { t.Parallel() - comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}) + comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}, &mock.CoreComponentsStub{}) require.NoError(t, err) require.NotNil(t, comp) @@ -31,7 +31,7 @@ func TestCreateStatusComponents(t *testing.T) { t.Run("nil app status handler should error", func(t *testing.T) { t.Parallel() - comp, err := CreateStatusComponents(0, nil, 5, config.ExternalConfig{}) + comp, err := CreateStatusComponents(0, nil, 5, config.ExternalConfig{}, &mock.CoreComponentsStub{}) require.Equal(t, core.ErrNilAppStatusHandler, err) require.Nil(t, comp) }) @@ -43,7 +43,7 @@ func TestStatusComponentsHolder_IsInterfaceNil(t *testing.T) { var comp *statusComponentsHolder require.True(t, comp.IsInterfaceNil()) - comp, _ = CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}) + comp, _ = CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}, &mock.CoreComponentsStub{}) require.False(t, comp.IsInterfaceNil()) require.Nil(t, comp.Close()) } @@ -51,7 +51,7 @@ func TestStatusComponentsHolder_IsInterfaceNil(t *testing.T) { func TestStatusComponentsHolder_Getters(t *testing.T) { t.Parallel() - comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}) + comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}, &mock.CoreComponentsStub{}) require.NoError(t, err) require.NotNil(t, comp.OutportHandler()) @@ -65,7 +65,7 @@ func TestStatusComponentsHolder_Getters(t *testing.T) { func TestStatusComponentsHolder_SetForkDetector(t *testing.T) { t.Parallel() - comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}) + comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}, &mock.CoreComponentsStub{}) require.NoError(t, err) err = comp.SetForkDetector(nil) @@ -83,7 +83,7 @@ func TestStatusComponentsHolder_StartPolling(t *testing.T) { t.Run("nil fork detector should error", func(t *testing.T) { t.Parallel() - comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}) + comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 5, config.ExternalConfig{}, &mock.CoreComponentsStub{}) require.NoError(t, err) err = comp.StartPolling() @@ -92,7 +92,7 @@ func TestStatusComponentsHolder_StartPolling(t *testing.T) { t.Run("NewAppStatusPolling failure should error", func(t *testing.T) { t.Parallel() - comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 0, config.ExternalConfig{}) + comp, err := CreateStatusComponents(0, &statusHandler.AppStatusHandlerStub{}, 0, config.ExternalConfig{}, &mock.CoreComponentsStub{}) require.NoError(t, err) err = comp.SetForkDetector(&mock.ForkDetectorStub{}) @@ -114,7 +114,7 @@ func TestStatusComponentsHolder_StartPolling(t *testing.T) { wasSetUInt64ValueCalled.SetValue(true) }, } - comp, err := CreateStatusComponents(0, appStatusHandler, providedStatusPollingIntervalSec, config.ExternalConfig{}) + comp, err := CreateStatusComponents(0, appStatusHandler, providedStatusPollingIntervalSec, config.ExternalConfig{}, &mock.CoreComponentsStub{}) require.NoError(t, err) forkDetector := &mock.ForkDetectorStub{ diff --git a/node/chainSimulator/components/testOnlyProcessingNode.go b/node/chainSimulator/components/testOnlyProcessingNode.go index f74598ce666..28256c4820f 100644 --- a/node/chainSimulator/components/testOnlyProcessingNode.go +++ b/node/chainSimulator/components/testOnlyProcessingNode.go @@ -49,6 +49,7 @@ type ArgsTestOnlyProcessingNode struct { MinNodesMeta uint32 MetaChainConsensusGroupSize uint32 RoundDurationInMillis uint64 + VmQueryDelayAfterStartInMs uint64 } type testOnlyProcessingNode struct { @@ -152,6 +153,7 @@ func NewTestOnlyProcessingNode(args ArgsTestOnlyProcessingNode) (*testOnlyProces instance.StatusCoreComponents.AppStatusHandler(), args.Configs.GeneralConfig.GeneralSettings.StatusPollingIntervalSec, *args.Configs.ExternalConfig, + instance.CoreComponentsHolder, ) if err != nil { return nil, err @@ -233,7 +235,7 @@ func NewTestOnlyProcessingNode(args ArgsTestOnlyProcessingNode) (*testOnlyProces return nil, err } - err = instance.createFacade(args.Configs, args.APIInterface) + err = instance.createFacade(args.Configs, args.APIInterface, args.VmQueryDelayAfterStartInMs) if err != nil { return nil, err } diff --git a/node/external/dtos.go b/node/external/dtos.go index f884d8d32c9..12a6b153c46 100644 --- a/node/external/dtos.go +++ b/node/external/dtos.go @@ -1,20 +1,24 @@ package external +import "github.com/multiversx/mx-chain-core-go/data/transaction" + // 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 + InnerTransactions []*transaction.Transaction } diff --git a/node/external/transactionAPI/unmarshaller.go b/node/external/transactionAPI/unmarshaller.go index c9526217f4f..bc997cdf042 100644 --- a/node/external/transactionAPI/unmarshaller.go +++ b/node/external/transactionAPI/unmarshaller.go @@ -13,6 +13,8 @@ import ( "github.com/multiversx/mx-chain-go/sharding" ) +const operationTransfer = "transfer" + type txUnmarshaller struct { shardCoordinator sharding.Coordinator addressPubKeyConverter core.PubkeyConverter @@ -86,8 +88,25 @@ func (tu *txUnmarshaller) unmarshalTransaction(txBytes []byte, txType transactio } apiTx = tu.prepareUnsignedTx(&tx) } - if err != nil { - return nil, err + + isRelayedV3 := len(apiTx.InnerTransactions) > 0 + if isRelayedV3 { + apiTx.Operation = operationTransfer + for _, innerTx := range apiTx.InnerTransactions { + apiTx.Receivers = append(apiTx.Receivers, innerTx.Receiver) + + rcvBytes, errDecode := tu.addressPubKeyConverter.Decode(innerTx.Receiver) + if errDecode != nil { + log.Warn("bech32PubkeyConverter.Decode() failed while decoding innerTx.Receiver", "error", errDecode) + continue + } + + apiTx.ReceiversShardIDs = append(apiTx.ReceiversShardIDs, tu.shardCoordinator.ComputeId(rcvBytes)) + } + + apiTx.IsRelayed = true + + return apiTx, nil } res := tu.dataFieldParser.Parse(apiTx.Data, apiTx.Tx.GetSndAddr(), apiTx.Tx.GetRcvAddr(), tu.shardCoordinator.NumberOfShards()) @@ -111,21 +130,22 @@ func (tu *txUnmarshaller) prepareNormalTx(tx *transaction.Transaction) *transact senderAddress := tu.addressPubKeyConverter.SilentEncode(tx.SndAddr, log) apiTx := &transaction.ApiTransactionResult{ - Tx: tx, - Type: string(transaction.TxTypeNormal), - Nonce: tx.Nonce, - Value: tx.Value.String(), - Receiver: receiverAddress, - ReceiverUsername: tx.RcvUserName, - Sender: senderAddress, - SenderUsername: tx.SndUserName, - GasPrice: tx.GasPrice, - GasLimit: tx.GasLimit, - Data: tx.Data, - Signature: hex.EncodeToString(tx.Signature), - Options: tx.Options, - Version: tx.Version, - ChainID: string(tx.ChainID), + Tx: tx, + Type: string(transaction.TxTypeNormal), + Nonce: tx.Nonce, + Value: tx.Value.String(), + Receiver: receiverAddress, + ReceiverUsername: tx.RcvUserName, + Sender: senderAddress, + SenderUsername: tx.SndUserName, + GasPrice: tx.GasPrice, + GasLimit: tx.GasLimit, + Data: tx.Data, + Signature: hex.EncodeToString(tx.Signature), + Options: tx.Options, + Version: tx.Version, + ChainID: string(tx.ChainID), + InnerTransactions: tu.prepareInnerTxs(tx), } if len(tx.GuardianAddr) > 0 { @@ -133,29 +153,72 @@ func (tu *txUnmarshaller) prepareNormalTx(tx *transaction.Transaction) *transact apiTx.GuardianSignature = hex.EncodeToString(tx.GuardianSignature) } + if len(tx.RelayerAddr) > 0 { + apiTx.RelayerAddress = tu.addressPubKeyConverter.SilentEncode(tx.RelayerAddr, log) + } + return apiTx } +func (tu *txUnmarshaller) prepareInnerTxs(tx *transaction.Transaction) []*transaction.FrontendTransaction { + if len(tx.InnerTransactions) == 0 { + return nil + } + + innerTxs := make([]*transaction.FrontendTransaction, 0, len(tx.InnerTransactions)) + for _, innerTx := range tx.InnerTransactions { + frontEndTx := &transaction.FrontendTransaction{ + Nonce: innerTx.Nonce, + Value: innerTx.Value.String(), + Receiver: tu.addressPubKeyConverter.SilentEncode(innerTx.RcvAddr, log), + Sender: tu.addressPubKeyConverter.SilentEncode(innerTx.SndAddr, log), + SenderUsername: innerTx.SndUserName, + ReceiverUsername: innerTx.RcvUserName, + GasPrice: innerTx.GasPrice, + GasLimit: innerTx.GasLimit, + Data: innerTx.Data, + Signature: hex.EncodeToString(innerTx.Signature), + ChainID: string(innerTx.ChainID), + Version: innerTx.Version, + Options: innerTx.Options, + } + + if len(innerTx.GuardianAddr) > 0 { + frontEndTx.GuardianAddr = tu.addressPubKeyConverter.SilentEncode(innerTx.GuardianAddr, log) + frontEndTx.GuardianSignature = hex.EncodeToString(innerTx.GuardianSignature) + } + + if len(innerTx.RelayerAddr) > 0 { + frontEndTx.Relayer = tu.addressPubKeyConverter.SilentEncode(innerTx.RelayerAddr, log) + } + + innerTxs = append(innerTxs, frontEndTx) + } + + return innerTxs +} + func (tu *txUnmarshaller) prepareInvalidTx(tx *transaction.Transaction) *transaction.ApiTransactionResult { receiverAddress := tu.addressPubKeyConverter.SilentEncode(tx.RcvAddr, log) senderAddress := tu.addressPubKeyConverter.SilentEncode(tx.SndAddr, log) apiTx := &transaction.ApiTransactionResult{ - Tx: tx, - Type: string(transaction.TxTypeInvalid), - Nonce: tx.Nonce, - Value: tx.Value.String(), - Receiver: receiverAddress, - ReceiverUsername: tx.RcvUserName, - Sender: senderAddress, - SenderUsername: tx.SndUserName, - GasPrice: tx.GasPrice, - GasLimit: tx.GasLimit, - Data: tx.Data, - Signature: hex.EncodeToString(tx.Signature), - Options: tx.Options, - Version: tx.Version, - ChainID: string(tx.ChainID), + Tx: tx, + Type: string(transaction.TxTypeInvalid), + Nonce: tx.Nonce, + Value: tx.Value.String(), + Receiver: receiverAddress, + ReceiverUsername: tx.RcvUserName, + Sender: senderAddress, + SenderUsername: tx.SndUserName, + GasPrice: tx.GasPrice, + GasLimit: tx.GasLimit, + Data: tx.Data, + Signature: hex.EncodeToString(tx.Signature), + Options: tx.Options, + Version: tx.Version, + ChainID: string(tx.ChainID), + InnerTransactions: tu.prepareInnerTxs(tx), } if len(tx.GuardianAddr) > 0 { @@ -163,6 +226,10 @@ func (tu *txUnmarshaller) prepareInvalidTx(tx *transaction.Transaction) *transac apiTx.GuardianSignature = hex.EncodeToString(tx.GuardianSignature) } + if len(tx.RelayerAddr) > 0 { + apiTx.RelayerAddress = tu.addressPubKeyConverter.SilentEncode(tx.RelayerAddr, log) + } + return apiTx } diff --git a/node/metrics/metrics.go b/node/metrics/metrics.go index 25356b0513c..c380c08b95d 100644 --- a/node/metrics/metrics.go +++ b/node/metrics/metrics.go @@ -121,6 +121,8 @@ func InitConfigMetrics( appStatusHandler.SetUInt64Value(common.MetricReturnDataToLastTransferEnableEpoch, uint64(enableEpochs.ReturnDataToLastTransferEnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricSenderInOutTransferEnableEpoch, uint64(enableEpochs.SenderInOutTransferEnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricRelayedTransactionsV2EnableEpoch, uint64(enableEpochs.RelayedTransactionsV2EnableEpoch)) + appStatusHandler.SetUInt64Value(common.MetricRelayedTransactionsV3EnableEpoch, uint64(enableEpochs.RelayedTransactionsV3EnableEpoch)) + appStatusHandler.SetUInt64Value(common.MetricFixRelayedBaseCostEnableEpoch, uint64(enableEpochs.FixRelayedBaseCostEnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricUnbondTokensV2EnableEpoch, uint64(enableEpochs.UnbondTokensV2EnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricSaveJailedAlwaysEnableEpoch, uint64(enableEpochs.SaveJailedAlwaysEnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricValidatorToDelegationEnableEpoch, uint64(enableEpochs.ValidatorToDelegationEnableEpoch)) @@ -199,6 +201,7 @@ func InitConfigMetrics( appStatusHandler.SetUInt64Value(common.MetricDynamicESDTEnableEpoch, uint64(enableEpochs.DynamicESDTEnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricEGLDInMultiTransferEnableEpoch, uint64(enableEpochs.EGLDInMultiTransferEnableEpoch)) appStatusHandler.SetUInt64Value(common.MetricCryptoOpcodesV2EnableEpoch, uint64(enableEpochs.CryptoOpcodesV2EnableEpoch)) + appStatusHandler.SetUInt64Value(common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch, uint64(enableEpochs.MultiESDTNFTTransferAndExecuteByUserEnableEpoch)) 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 fdfbc3bb533..395d42afc15 100644 --- a/node/metrics/metrics_test.go +++ b/node/metrics/metrics_test.go @@ -208,6 +208,9 @@ func TestInitConfigMetrics(t *testing.T) { EGLDInMultiTransferEnableEpoch: 101, CryptoOpcodesV2EnableEpoch: 102, ScToScLogEventEnableEpoch: 103, + RelayedTransactionsV3EnableEpoch: 104, + FixRelayedBaseCostEnableEpoch: 105, + MultiESDTNFTTransferAndExecuteByUserEnableEpoch: 106, MaxNodesChangeEnableEpoch: []config.MaxNodesChangeConfig{ { EpochEnable: 0, @@ -326,6 +329,9 @@ func TestInitConfigMetrics(t *testing.T) { "erd_egld_in_multi_transfer_enable_epoch": uint32(101), "erd_crypto_opcodes_v2_enable_epoch": uint32(102), "erd_set_sc_to_sc_log_event_enable_epoch": uint32(103), + "erd_relayed_transactions_v3_enable_epoch": uint32(104), + "erd_fix_relayed_base_cost_enable_epoch": uint32(105), + "erd_multi_esdt_transfer_execute_by_user_enable_epoch": uint32(106), "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 992cba53768..7331b9d44ca 100644 --- a/node/node.go +++ b/node/node.go @@ -54,8 +54,7 @@ var log = logger.GetOrCreate("node") var _ facade.NodeHandler = (*Node)(nil) // Option represents a functional configuration parameter that can operate -// -// over the None struct. +// over the None struct. type Option func(*Node) error type filter interface { @@ -294,7 +293,7 @@ func (n *Node) GetKeyValuePairs(address string, options api.AccountQueryOptions, } if check.IfNil(userAccount.DataTrie()) { - return map[string]string{}, api.BlockInfo{}, nil + return map[string]string{}, blockInfo, nil } mapToReturn, err := n.getKeys(userAccount, ctx) @@ -799,6 +798,8 @@ func (n *Node) commonTransactionValidation( enableSignWithTxHash, n.coreComponents.TxSignHasher(), n.coreComponents.TxVersionChecker(), + n.coreComponents.EnableEpochsHandler(), + n.processComponents.RelayedTxV3Processor(), ) if err != nil { return nil, nil, err @@ -892,19 +893,20 @@ func (n *Node) CreateTransaction(txArgs *external.ArgsCreateTransaction) (*trans } tx := &transaction.Transaction{ - Nonce: txArgs.Nonce, - Value: valAsBigInt, - RcvAddr: receiverAddress, - RcvUserName: txArgs.ReceiverUsername, - SndAddr: senderAddress, - SndUserName: txArgs.SenderUsername, - GasPrice: txArgs.GasPrice, - GasLimit: txArgs.GasLimit, - Data: txArgs.DataField, - Signature: signatureBytes, - ChainID: []byte(txArgs.ChainID), - Version: txArgs.Version, - Options: txArgs.Options, + Nonce: txArgs.Nonce, + Value: valAsBigInt, + RcvAddr: receiverAddress, + RcvUserName: txArgs.ReceiverUsername, + SndAddr: senderAddress, + SndUserName: txArgs.SenderUsername, + GasPrice: txArgs.GasPrice, + GasLimit: txArgs.GasLimit, + Data: txArgs.DataField, + Signature: signatureBytes, + ChainID: []byte(txArgs.ChainID), + Version: txArgs.Version, + Options: txArgs.Options, + InnerTransactions: txArgs.InnerTransactions, } if len(txArgs.Guardian) > 0 { @@ -914,6 +916,13 @@ func (n *Node) CreateTransaction(txArgs *external.ArgsCreateTransaction) (*trans } } + if len(txArgs.Relayer) > 0 { + tx.RelayerAddr, err = addrPubKeyConverter.Decode(txArgs.Relayer) + if err != nil { + return nil, nil, errors.New("could not create relayer address from provided param") + } + } + var txHash []byte txHash, err = core.CalculateHash(n.coreComponents.InternalMarshalizer(), n.coreComponents.Hasher(), tx) if err != nil { @@ -962,6 +971,10 @@ func (n *Node) GetAccountWithKeys(address string, options api.AccountQueryOption var keys map[string]string if options.WithKeys { + if accInfo.account == nil || accInfo.account.DataTrie() == nil { + return accInfo.accountResponse, accInfo.block, nil + } + keys, err = n.getKeys(accInfo.account, ctx) if err != nil { return api.AccountResponse{}, api.BlockInfo{}, err diff --git a/node/node_test.go b/node/node_test.go index d2c19011830..b584dc2370b 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -61,6 +61,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/mainFactoryMocks" "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" "github.com/multiversx/mx-chain-go/testscommon/stakingcommon" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" @@ -1850,21 +1851,22 @@ func TestGenerateTransaction_CorrectParamsShouldNotError(t *testing.T) { func getDefaultTransactionArgs() *external.ArgsCreateTransaction { return &external.ArgsCreateTransaction{ - Nonce: uint64(0), - Value: new(big.Int).SetInt64(10).String(), - Receiver: "rcv", - ReceiverUsername: []byte("rcvrUsername"), - Sender: "snd", - SenderUsername: []byte("sndrUsername"), - GasPrice: uint64(10), - GasLimit: uint64(20), - DataField: []byte("-"), - SignatureHex: hex.EncodeToString(bytes.Repeat([]byte{0}, 10)), - ChainID: "chainID", - Version: 1, - Options: 0, - Guardian: "", - GuardianSigHex: "", + Nonce: uint64(0), + Value: new(big.Int).SetInt64(10).String(), + Receiver: "rcv", + ReceiverUsername: []byte("rcvrUsername"), + Sender: "snd", + SenderUsername: []byte("sndrUsername"), + GasPrice: uint64(10), + GasLimit: uint64(20), + DataField: []byte("-"), + SignatureHex: hex.EncodeToString(bytes.Repeat([]byte{0}, 10)), + ChainID: "chainID", + Version: 1, + Options: 0, + Guardian: "", + GuardianSigHex: "", + InnerTransactions: nil, } } @@ -3536,6 +3538,54 @@ func TestNode_GetAccountAccountWithKeysShouldWork(t *testing.T) { require.Equal(t, hex.EncodeToString(v2), recovAccnt.Pairs[hex.EncodeToString(k2)]) } +func TestNode_GetAccountAccountWithKeysNeverUsedAccountShouldWork(t *testing.T) { + t.Parallel() + + accDB := &stateMock.AccountsStub{ + GetAccountWithBlockInfoCalled: func(address []byte, options common.RootHashHolder) (vmcommon.AccountHandler, common.BlockInfo, error) { + return nil, nil, nil + }, + RecreateTrieCalled: func(options common.RootHashHolder) error { + return nil + }, + } + + n := getNodeWithAccount(accDB) + + recovAccnt, blockInfo, err := n.GetAccountWithKeys(testscommon.TestAddressBob, api.AccountQueryOptions{WithKeys: true}, context.Background()) + + require.Nil(t, err) + require.Equal(t, uint64(0), recovAccnt.Nonce) + require.Equal(t, testscommon.TestAddressBob, recovAccnt.Address) + require.Equal(t, api.BlockInfo{}, blockInfo) +} + +func TestNode_GetAccountAccountWithKeysNilDataTrieShouldWork(t *testing.T) { + t.Parallel() + + accnt := createAcc(testscommon.TestPubKeyBob) + accnt.SetDataTrie(nil) + _ = accnt.AddToBalance(big.NewInt(1)) + + accDB := &stateMock.AccountsStub{ + GetAccountWithBlockInfoCalled: func(address []byte, options common.RootHashHolder) (vmcommon.AccountHandler, common.BlockInfo, error) { + return accnt, nil, nil + }, + RecreateTrieCalled: func(options common.RootHashHolder) error { + return nil + }, + } + + n := getNodeWithAccount(accDB) + + recovAccnt, blockInfo, err := n.GetAccountWithKeys(testscommon.TestAddressBob, api.AccountQueryOptions{WithKeys: true}, context.Background()) + + require.Nil(t, err) + require.Equal(t, uint64(0), recovAccnt.Nonce) + require.Equal(t, testscommon.TestAddressBob, recovAccnt.Address) + require.Equal(t, api.BlockInfo{}, blockInfo) +} + func getNodeWithAccount(accDB *stateMock.AccountsStub) *node.Node { coreComponents := getDefaultCoreComponents() dataComponents := getDefaultDataComponents() @@ -5199,18 +5249,19 @@ func getDefaultCoreComponents() *nodeMockFactory.CoreComponentsMock { MinTransactionVersionCalled: func() uint32 { return 1 }, - WDTimer: &testscommon.WatchdogMock{}, - Alarm: &testscommon.AlarmSchedulerStub{}, - NtpTimer: &testscommon.SyncTimerStub{}, - RoundHandlerField: &testscommon.RoundHandlerMock{}, - EconomicsHandler: &economicsmocks.EconomicsHandlerMock{}, - APIEconomicsHandler: &economicsmocks.EconomicsHandlerMock{}, - RatingsConfig: &testscommon.RatingsInfoMock{}, - RatingHandler: &testscommon.RaterMock{}, - NodesConfig: &genesisMocks.NodesSetupStub{}, - StartTime: time.Time{}, - EpochChangeNotifier: &epochNotifier.EpochNotifierStub{}, - TxVersionCheckHandler: versioning.NewTxVersionChecker(0), + WDTimer: &testscommon.WatchdogMock{}, + Alarm: &testscommon.AlarmSchedulerStub{}, + NtpTimer: &testscommon.SyncTimerStub{}, + RoundHandlerField: &testscommon.RoundHandlerMock{}, + EconomicsHandler: &economicsmocks.EconomicsHandlerMock{}, + APIEconomicsHandler: &economicsmocks.EconomicsHandlerMock{}, + RatingsConfig: &testscommon.RatingsInfoMock{}, + RatingHandler: &testscommon.RaterMock{}, + NodesConfig: &genesisMocks.NodesSetupStub{}, + StartTime: time.Time{}, + EpochChangeNotifier: &epochNotifier.EpochNotifierStub{}, + TxVersionCheckHandler: versioning.NewTxVersionChecker(0), + EnableEpochsHandlerField: &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, } } @@ -5246,6 +5297,7 @@ func getDefaultProcessComponents() *factoryMock.ProcessComponentsMock { TxsSenderHandlerField: &txsSenderMock.TxsSenderHandlerMock{}, ScheduledTxsExecutionHandlerInternal: &testscommon.ScheduledTxsExecutionStub{}, HistoryRepositoryInternal: &dblookupext.HistoryRepositoryStub{}, + RelayedTxV3ProcessorField: &processMocks.RelayedTxV3ProcessorMock{}, } } diff --git a/outport/process/alteredaccounts/alteredAccountsProvider.go b/outport/process/alteredaccounts/alteredAccountsProvider.go index e7d855b1ebf..c95fea79b69 100644 --- a/outport/process/alteredaccounts/alteredAccountsProvider.go +++ b/outport/process/alteredaccounts/alteredAccountsProvider.go @@ -223,6 +223,7 @@ func (aap *alteredAccountsProvider) addTokensDataForMarkedAccount( Nonce: nonce, Properties: hex.EncodeToString(esdtToken.Properties), MetaData: aap.convertMetaData(esdtToken.TokenMetaData), + Type: getTokenType(esdtToken.Type, nonce), } if options.WithAdditionalOutportData { accountTokenData.AdditionalData = &alteredAccount.AdditionalAccountTokenData{ @@ -236,6 +237,16 @@ func (aap *alteredAccountsProvider) addTokensDataForMarkedAccount( return nil } +func getTokenType(tokenType uint32, tokenNonce uint64) string { + isNotFungible := tokenNonce != 0 + tokenTypeNotSet := isNotFungible && core.ESDTType(tokenType) == core.NonFungible + if tokenTypeNotSet { + return "" + } + + return core.ESDTType(tokenType).String() +} + func (aap *alteredAccountsProvider) convertMetaData(metaData *esdt.MetaData) *alteredAccount.TokenMetaData { if metaData == nil { return nil diff --git a/outport/process/alteredaccounts/alteredAccountsProvider_test.go b/outport/process/alteredaccounts/alteredAccountsProvider_test.go index 7832e6e55bb..c6fce787c71 100644 --- a/outport/process/alteredaccounts/alteredAccountsProvider_test.go +++ b/outport/process/alteredaccounts/alteredAccountsProvider_test.go @@ -620,6 +620,7 @@ func testExtractAlteredAccountsFromPoolShouldIncludeESDT(t *testing.T) { Nonce: 0, Properties: "6f6b", MetaData: nil, + Type: core.FungibleESDT, }, res[encodedAddr].Tokens[0]) } @@ -627,6 +628,7 @@ func testExtractAlteredAccountsFromPoolShouldIncludeNFT(t *testing.T) { t.Parallel() expectedToken := esdt.ESDigitalToken{ + Type: uint32(core.NonFungible), Value: big.NewInt(37), TokenMetaData: &esdt.MetaData{ Nonce: 38, @@ -757,6 +759,7 @@ func testExtractAlteredAccountsFromPoolShouldIncludeDestinationFromTokensLogsTop receiverOnDestination := []byte("receiver on destination shard") expectedToken := esdt.ESDigitalToken{ Value: big.NewInt(37), + Type: uint32(core.NonFungible), TokenMetaData: &esdt.MetaData{ Nonce: 38, Name: []byte("name"), @@ -903,12 +906,14 @@ func testExtractAlteredAccountsFromPoolMultiTransferEventV2(t *testing.T) { TokenMetaData: &esdt.MetaData{ Nonce: 1, }, + Type: uint32(core.NonFungible), } expectedToken2 := &esdt.ESDigitalToken{ Value: big.NewInt(10), TokenMetaData: &esdt.MetaData{ Nonce: 1, }, + Type: uint32(core.NonFungible), } args := getMockArgs() @@ -1003,6 +1008,7 @@ func testExtractAlteredAccountsFromPoolAddressHasMultipleNfts(t *testing.T) { } expectedToken1 := esdt.ESDigitalToken{ Value: big.NewInt(38), + Type: uint32(core.NonFungible), TokenMetaData: &esdt.MetaData{ Nonce: 5, Name: []byte("nft-0"), @@ -1010,6 +1016,7 @@ func testExtractAlteredAccountsFromPoolAddressHasMultipleNfts(t *testing.T) { } expectedToken2 := esdt.ESDigitalToken{ Value: big.NewInt(37), + Type: uint32(core.NonFungible), TokenMetaData: &esdt.MetaData{ Nonce: 6, Name: []byte("nft-0"), @@ -1124,6 +1131,7 @@ func testExtractAlteredAccountsFromPoolAddressHasMultipleNfts(t *testing.T) { Balance: expectedToken0.Value.String(), Nonce: 0, MetaData: nil, + Type: core.FungibleESDT, }) require.Contains(t, res[encodedAddr].Tokens, &alteredAccount.AccountTokenData{ @@ -1222,6 +1230,7 @@ func testExtractAlteredAccountsFromPoolESDTTransferBalanceNotChanged(t *testing. AdditionalData: &alteredAccount.AdditionalAccountTokenData{ IsNFTCreate: false, }, + Type: core.FungibleESDT, }, }, AdditionalData: &alteredAccount.AdditionalAccountData{ @@ -1241,6 +1250,7 @@ func testExtractAlteredAccountsFromPoolESDTTransferBalanceNotChanged(t *testing. AdditionalData: &alteredAccount.AdditionalAccountTokenData{ IsNFTCreate: false, }, + Type: core.FungibleESDT, }, }, AdditionalData: &alteredAccount.AdditionalAccountData{ @@ -1432,6 +1442,7 @@ func textExtractAlteredAccountsFromPoolNftCreate(t *testing.T) { AdditionalData: &alteredAccount.AdditionalAccountTokenData{ IsNFTCreate: true, }, + Type: core.FungibleESDT, }, }, AdditionalData: &alteredAccount.AdditionalAccountData{ diff --git a/outport/process/alteredaccounts/tokensProcessor.go b/outport/process/alteredaccounts/tokensProcessor.go index bb0839ef44a..687c543bcdf 100644 --- a/outport/process/alteredaccounts/tokensProcessor.go +++ b/outport/process/alteredaccounts/tokensProcessor.go @@ -7,6 +7,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" outportcore "github.com/multiversx/mx-chain-core-go/data/outport" "github.com/multiversx/mx-chain-go/sharding" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" ) const ( @@ -116,7 +117,7 @@ func (tp *tokensProcessor) processMultiTransferEvent(event data.EventHandler, ma // N = len(topics) // i := 0; i < N-1; i+=3 // { - // topics[i] --- token identifier + // topics[i] --- token identifier or EGLD token identifier // topics[i+1] --- token nonce // topics[i+2] --- transferred value // } @@ -133,6 +134,12 @@ func (tp *tokensProcessor) processMultiTransferEvent(event data.EventHandler, ma for i := 0; i < numOfTopics-1; i += 3 { tokenID := topics[i] nonceBigInt := big.NewInt(0).SetBytes(topics[i+1]) + + if string(tokenID) == vmcommon.EGLDIdentifier { + tp.processNativeEGLDTransferWithMultiTransfer(destinationAddress, markedAlteredAccounts) + return + } + // process event for the sender address tp.processEsdtDataForAddress(address, nonceBigInt, string(tokenID), markedAlteredAccounts, false) @@ -177,6 +184,24 @@ func (tp *tokensProcessor) processEsdtDataForAddress( } } +func (tp *tokensProcessor) processNativeEGLDTransferWithMultiTransfer(address []byte, markedAlteredAccounts map[string]*markedAlteredAccount) { + if !tp.isSameShard(address) { + return + } + + addressStr := string(address) + _, addressAlreadySelected := markedAlteredAccounts[addressStr] + if addressAlreadySelected { + markedAlteredAccounts[addressStr].balanceChanged = true + return + } + + markedAlteredAccounts[addressStr] = &markedAlteredAccount{ + balanceChanged: true, + } + +} + func (tp *tokensProcessor) isSameShard(address []byte) bool { return tp.shardCoordinator.SelfId() == tp.shardCoordinator.ComputeId(address) } diff --git a/outport/process/alteredaccounts/tokensProcessor_test.go b/outport/process/alteredaccounts/tokensProcessor_test.go index a7a6a65af96..af737a1de94 100644 --- a/outport/process/alteredaccounts/tokensProcessor_test.go +++ b/outport/process/alteredaccounts/tokensProcessor_test.go @@ -7,6 +7,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/process/mock" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" "github.com/stretchr/testify/require" ) @@ -61,3 +62,38 @@ func TestTokenProcessorProcessEventMultiTransferV2(t *testing.T) { require.Equal(t, markedAccount, markedAccounts["addr"]) require.Equal(t, markedAccount, markedAccounts["receiver"]) } + +func TestTokenProcessorProcessEventMultiTransferV2WithEGLD(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("receiver")}, + }, markedAccounts) + + require.Equal(t, 2, len(markedAccounts)) + markedAccount1 := &markedAlteredAccount{ + tokens: map[string]*markedAlteredAccountToken{ + "token1": { + identifier: "token1", + nonce: 0, + }, + }, + } + require.Equal(t, markedAccount1, markedAccounts["addr"]) + + markedAccount2 := &markedAlteredAccount{ + balanceChanged: true, + tokens: map[string]*markedAlteredAccountToken{ + "token1": { + identifier: "token1", + nonce: 0, + }, + }, + } + require.Equal(t, markedAccount2, markedAccounts["receiver"]) +} diff --git a/outport/process/transactionsfee/transactionsFeeProcessor.go b/outport/process/transactionsfee/transactionsFeeProcessor.go index c77956f5365..6520db7635d 100644 --- a/outport/process/transactionsfee/transactionsFeeProcessor.go +++ b/outport/process/transactionsfee/transactionsFeeProcessor.go @@ -115,6 +115,11 @@ func (tep *transactionsFeeProcessor) prepareNormalTxs(transactionsAndScrs *trans feeInfo.SetFee(initialPaidFee) } + if len(txHandler.GetUserTransactions()) > 0 { + tep.prepareRelayedTxV3WithResults(txHashHex, txWithResult) + continue + } + tep.prepareTxWithResults(txHashHex, txWithResult) } } @@ -141,6 +146,31 @@ func (tep *transactionsFeeProcessor) prepareTxWithResults(txHashHex string, txWi } +func (tep *transactionsFeeProcessor) prepareRelayedTxV3WithResults(txHashHex string, txWithResults *transactionWithResults) { + refundsValue := big.NewInt(0) + for _, scrHandler := range txWithResults.scrs { + scr, ok := scrHandler.GetTxHandler().(*smartContractResult.SmartContractResult) + if !ok { + continue + } + + if !isRefundForRelayed(scr, txWithResults.GetTxHandler()) { + continue + } + + refundsValue.Add(refundsValue, scr.Value) + } + + gasUsed, fee := tep.txFeeCalculator.ComputeGasUsedAndFeeBasedOnRefundValue(txWithResults.GetTxHandler(), refundsValue) + + txWithResults.GetFeeInfo().SetGasUsed(gasUsed) + txWithResults.GetFeeInfo().SetFee(fee) + + hasRefunds := refundsValue.Cmp(big.NewInt(0)) == 1 + tep.prepareTxWithResultsBasedOnLogs(txHashHex, txWithResults, hasRefunds) + +} + func (tep *transactionsFeeProcessor) prepareTxWithResultsBasedOnLogs( txHashHex string, txWithResults *transactionWithResults, diff --git a/process/block/baseProcess.go b/process/block/baseProcess.go index b12aa6b2783..0e3c573b23d 100644 --- a/process/block/baseProcess.go +++ b/process/block/baseProcess.go @@ -20,6 +20,8 @@ import ( "github.com/multiversx/mx-chain-core-go/display" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + logger "github.com/multiversx/mx-chain-logger-go" + nodeFactory "github.com/multiversx/mx-chain-go/cmd/node/factory" "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/common/errChan" @@ -42,7 +44,6 @@ import ( "github.com/multiversx/mx-chain-go/state/factory" "github.com/multiversx/mx-chain-go/state/parsers" "github.com/multiversx/mx-chain-go/storage/storageunit" - logger "github.com/multiversx/mx-chain-logger-go" ) var log = logger.GetOrCreate("process/block") @@ -576,7 +577,7 @@ func (bp *baseProcessor) createBlockStarted() error { bp.txCoordinator.CreateBlockStarted() bp.feeHandler.CreateBlockStarted(scheduledGasAndFees) - err := bp.txCoordinator.AddIntermediateTransactions(bp.scheduledTxsExecutionHandler.GetScheduledIntermediateTxs()) + err := bp.txCoordinator.AddIntermediateTransactions(bp.scheduledTxsExecutionHandler.GetScheduledIntermediateTxs(), nil) if err != nil { return err } diff --git a/process/block/postprocess/basePostProcess.go b/process/block/postprocess/basePostProcess.go index 058118dd88b..26473387dd7 100644 --- a/process/block/postprocess/basePostProcess.go +++ b/process/block/postprocess/basePostProcess.go @@ -9,10 +9,11 @@ import ( "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-logger-go" + "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/sharding" - "github.com/multiversx/mx-chain-logger-go" ) var _ process.DataMarshalizer = (*basePostProcessor)(nil) @@ -28,6 +29,14 @@ type txInfo struct { *txShardInfo } +type processedResult struct { + parentKey []byte + childrenKeys map[string]struct{} + results [][]byte +} + +const defaultCapacity = 100 + var log = logger.GetOrCreate("process/block/postprocess") type basePostProcessor struct { @@ -39,7 +48,7 @@ type basePostProcessor struct { mutInterResultsForBlock sync.Mutex interResultsForBlock map[string]*txInfo - mapProcessedResult map[string][][]byte + mapProcessedResult map[string]*processedResult intraShardMiniBlock *block.MiniBlock economicsFee process.FeeHandler index uint32 @@ -78,7 +87,7 @@ func (bpp *basePostProcessor) CreateBlockStarted() { bpp.mutInterResultsForBlock.Lock() bpp.interResultsForBlock = make(map[string]*txInfo) bpp.intraShardMiniBlock = nil - bpp.mapProcessedResult = make(map[string][][]byte) + bpp.mapProcessedResult = make(map[string]*processedResult) bpp.index = 0 bpp.mutInterResultsForBlock.Unlock() } @@ -170,24 +179,72 @@ func (bpp *basePostProcessor) RemoveProcessedResults(key []byte) [][]byte { bpp.mutInterResultsForBlock.Lock() defer bpp.mutInterResultsForBlock.Unlock() - txHashes, ok := bpp.mapProcessedResult[string(key)] + removedProcessedResults, ok := bpp.removeProcessedResultsAndLinks(string(key)) if !ok { return nil } - for _, txHash := range txHashes { - delete(bpp.interResultsForBlock, string(txHash)) + for _, result := range removedProcessedResults { + delete(bpp.interResultsForBlock, string(result)) } - return txHashes + return removedProcessedResults +} + +func (bpp *basePostProcessor) removeProcessedResultsAndLinks(key string) ([][]byte, bool) { + processedResults, ok := bpp.mapProcessedResult[key] + if !ok { + return nil, ok + } + delete(bpp.mapProcessedResult, key) + + collectedProcessedResultsKeys := make([][]byte, 0, defaultCapacity) + collectedProcessedResultsKeys = append(collectedProcessedResultsKeys, processedResults.results...) + + // go through the childrenKeys and do the same + for childKey := range processedResults.childrenKeys { + childProcessedResults, ok := bpp.removeProcessedResultsAndLinks(childKey) + if !ok { + continue + } + + collectedProcessedResultsKeys = append(collectedProcessedResultsKeys, childProcessedResults...) + } + + // remove link from parentKey + parent, ok := bpp.mapProcessedResult[string(processedResults.parentKey)] + if ok { + delete(parent.childrenKeys, key) + } + + return collectedProcessedResultsKeys, true } // InitProcessedResults will initialize the processed results -func (bpp *basePostProcessor) InitProcessedResults(key []byte) { +func (bpp *basePostProcessor) InitProcessedResults(key []byte, parentKey []byte) { bpp.mutInterResultsForBlock.Lock() defer bpp.mutInterResultsForBlock.Unlock() - bpp.mapProcessedResult[string(key)] = make([][]byte, 0) + pr := &processedResult{ + parentKey: parentKey, + childrenKeys: make(map[string]struct{}), + results: make([][]byte, 0), + } + + bpp.mapProcessedResult[string(key)] = pr + + if len(parentKey) > 0 { + parentPr, ok := bpp.mapProcessedResult[string(parentKey)] + if !ok { + bpp.mapProcessedResult[string(parentKey)] = &processedResult{ + parentKey: nil, + childrenKeys: map[string]struct{}{string(key): {}}, + results: make([][]byte, 0), + } + } else { + parentPr.childrenKeys[string(key)] = struct{}{} + } + } } func (bpp *basePostProcessor) splitMiniBlocksIfNeeded(miniBlocks []*block.MiniBlock) []*block.MiniBlock { @@ -275,13 +332,17 @@ func (bpp *basePostProcessor) addIntermediateTxToResultsForBlock( txHash []byte, sndShardID uint32, rcvShardID uint32, + key []byte, ) { addScrShardInfo := &txShardInfo{receiverShardID: rcvShardID, senderShardID: sndShardID} scrInfo := &txInfo{tx: txHandler, txShardInfo: addScrShardInfo, index: bpp.index} bpp.index++ bpp.interResultsForBlock[string(txHash)] = scrInfo - for key := range bpp.mapProcessedResult { - bpp.mapProcessedResult[key] = append(bpp.mapProcessedResult[key], txHash) + pr, ok := bpp.mapProcessedResult[string(key)] + if !ok { + return } + + pr.results = append(pr.results, txHash) } diff --git a/process/block/postprocess/basePostProcess_test.go b/process/block/postprocess/basePostProcess_test.go new file mode 100644 index 00000000000..021ef491840 --- /dev/null +++ b/process/block/postprocess/basePostProcess_test.go @@ -0,0 +1,171 @@ +package postprocess + +import ( + "sync" + "testing" + + "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-core-go/hashing" + "github.com/multiversx/mx-chain-core-go/hashing/sha256" + "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/stretchr/testify/require" +) + +func createBaseProcessors(numProcessors int) []*basePostProcessor { + basePostProcessors := make([]*basePostProcessor, numProcessors) + for i := 0; i < numProcessors; i++ { + basePostProcessors[i] = &basePostProcessor{ + hasher: sha256.NewSha256(), + marshalizer: &marshal.GogoProtoMarshalizer{}, + store: nil, + shardCoordinator: nil, + storageType: 0, + mutInterResultsForBlock: sync.Mutex{}, + interResultsForBlock: make(map[string]*txInfo), + mapProcessedResult: make(map[string]*processedResult), + intraShardMiniBlock: nil, + economicsFee: nil, + index: 0, + } + } + return basePostProcessors +} + +func createTxs(hasher hashing.Hasher, num int) ([]data.TransactionHandler, [][]byte) { + txs := make([]data.TransactionHandler, num) + txHashes := make([][]byte, num) + marshaller := &marshal.GogoProtoMarshalizer{} + + for i := 0; i < num; i++ { + txs[i] = &transaction.Transaction{ + Nonce: uint64(i), + } + marshalledTx, _ := marshaller.Marshal(txs[i]) + txHashes[i] = hasher.Compute(string(marshalledTx)) + } + + return txs, txHashes +} + +func createScrs(hasher hashing.Hasher, num int) ([]data.TransactionHandler, [][]byte) { + scrs := make([]data.TransactionHandler, num) + scrHashes := make([][]byte, num) + marshaller := &marshal.GogoProtoMarshalizer{} + + for i := 0; i < num; i++ { + scrs[i] = &smartContractResult.SmartContractResult{ + Nonce: uint64(i), + OriginalTxHash: []byte("original tx hash"), + } + marshalledTx, _ := marshaller.Marshal(scrs[i]) + scrHashes[i] = hasher.Compute(string(marshalledTx)) + } + + return scrs, scrHashes +} + +func TestBasePostProcessor_InitAddAndRemove(t *testing.T) { + numInstances := 1 + numTxs := 10000 + numScrs := 10000 + headerHash := []byte("headerHash") + miniBlockHash := []byte("miniBlockHash") + _, txHashes := createTxs(sha256.NewSha256(), numTxs) + scrs, scrHash := createScrs(sha256.NewSha256(), numScrs) + + t.Run("InitProcessedResults for header, miniblock and txs, remove one tx, then miniblock", func(t *testing.T) { + basePreProcs := createBaseProcessors(numInstances) + basePreProcs[0].InitProcessedResults(headerHash, nil) + basePreProcs[0].InitProcessedResults(miniBlockHash, headerHash) + require.Len(t, basePreProcs[0].mapProcessedResult[string(headerHash)].childrenKeys, 1) + require.Len(t, basePreProcs[0].mapProcessedResult[string(headerHash)].results, 0) + + for i := 0; i < numTxs; i++ { + basePreProcs[0].InitProcessedResults(txHashes[i], miniBlockHash) + basePreProcs[0].addIntermediateTxToResultsForBlock(scrs[i], scrHash[i], 0, 1, txHashes[i]) + } + require.Equal(t, numTxs, len(basePreProcs[0].mapProcessedResult[string(miniBlockHash)].childrenKeys)) + require.Len(t, basePreProcs[0].mapProcessedResult[string(miniBlockHash)].results, 0) + + for i := 0; i < numTxs; i++ { + require.Len(t, basePreProcs[0].mapProcessedResult[string(txHashes[i])].results, 1) + require.Len(t, basePreProcs[0].mapProcessedResult[string(txHashes[i])].childrenKeys, 0) + } + + results := basePreProcs[0].RemoveProcessedResults(txHashes[0]) + require.Len(t, results, 1) + + // miniBlockHash has numTxs-1 childrenKeys, as one was removed + // each child has one scr registered + results = basePreProcs[0].RemoveProcessedResults(miniBlockHash) + require.Len(t, results, numTxs-1) + + // headerHash no longer has childrenKeys and no direct results, so removing it should return an empty slice + results = basePreProcs[0].RemoveProcessedResults(headerHash) + require.Len(t, results, 0) + }) + t.Run("InitProcessedResults for header, miniblock and txs, remove directly the miniblock", func(t *testing.T) { + basePreProcs := createBaseProcessors(numInstances) + basePreProcs[0].InitProcessedResults(headerHash, nil) + basePreProcs[0].InitProcessedResults(miniBlockHash, headerHash) + require.Len(t, basePreProcs[0].mapProcessedResult[string(headerHash)].childrenKeys, 1) + require.Len(t, basePreProcs[0].mapProcessedResult[string(headerHash)].results, 0) + + for i := 0; i < numTxs; i++ { + basePreProcs[0].InitProcessedResults(txHashes[i], miniBlockHash) + basePreProcs[0].addIntermediateTxToResultsForBlock(scrs[i], scrHash[i], 0, 1, txHashes[i]) + } + require.Equal(t, numTxs, len(basePreProcs[0].mapProcessedResult[string(miniBlockHash)].childrenKeys)) + require.Len(t, basePreProcs[0].mapProcessedResult[string(miniBlockHash)].results, 0) + + for i := 0; i < numTxs; i++ { + require.Len(t, basePreProcs[0].mapProcessedResult[string(txHashes[i])].results, 1) + require.Len(t, basePreProcs[0].mapProcessedResult[string(txHashes[i])].childrenKeys, 0) + } + + // miniBlockHash has numTxs childrenKeys, each child has one scr registered + // removing directly the miniBlock should return numTxs results (the scrs) + results := basePreProcs[0].RemoveProcessedResults(miniBlockHash) + require.Len(t, results, numTxs) + for i := 0; i < numTxs; i++ { + require.Nil(t, basePreProcs[0].mapProcessedResult[string(txHashes[i])]) + } + + // headerHash no longer has childrenKeys and no direct results, so removing it should return an empty slice + results = basePreProcs[0].RemoveProcessedResults(headerHash) + require.Len(t, results, 0) + }) + + t.Run("InitProcessedResults for header, miniblock and txs, remove directly the headerhash", func(t *testing.T) { + basePreProcs := createBaseProcessors(numInstances) + basePreProcs[0].InitProcessedResults(headerHash, nil) + basePreProcs[0].InitProcessedResults(miniBlockHash, headerHash) + require.Len(t, basePreProcs[0].mapProcessedResult[string(headerHash)].childrenKeys, 1) + require.Len(t, basePreProcs[0].mapProcessedResult[string(headerHash)].results, 0) + + for i := 0; i < numTxs; i++ { + basePreProcs[0].InitProcessedResults(txHashes[i], miniBlockHash) + basePreProcs[0].addIntermediateTxToResultsForBlock(scrs[i], scrHash[i], 0, 1, txHashes[i]) + } + require.Equal(t, numTxs, len(basePreProcs[0].mapProcessedResult[string(miniBlockHash)].childrenKeys)) + require.Len(t, basePreProcs[0].mapProcessedResult[string(miniBlockHash)].results, 0) + + for i := 0; i < numTxs; i++ { + require.Len(t, basePreProcs[0].mapProcessedResult[string(txHashes[i])].results, 1) + require.Len(t, basePreProcs[0].mapProcessedResult[string(txHashes[i])].childrenKeys, 0) + } + + // headerHash has one child, miniBlockHash + // miniBlockHash has numTxs childrenKeys, each child has one scr registered + // removing directly the headerHash should return numTxs results (the scrs) for the removed chained childrenKeys + results := basePreProcs[0].RemoveProcessedResults(headerHash) + require.Len(t, results, numTxs) + require.Nil(t, basePreProcs[0].mapProcessedResult[string(miniBlockHash)]) + + for i := 0; i < numTxs; i++ { + require.Nil(t, basePreProcs[0].mapProcessedResult[string(txHashes[i])]) + } + }) +} diff --git a/process/block/postprocess/intermediateResults.go b/process/block/postprocess/intermediateResults.go index b10b99a03f8..d706e83623e 100644 --- a/process/block/postprocess/intermediateResults.go +++ b/process/block/postprocess/intermediateResults.go @@ -12,11 +12,12 @@ import ( "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + logger "github.com/multiversx/mx-chain-logger-go" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/sharding" - logger "github.com/multiversx/mx-chain-logger-go" ) var _ process.IntermediateTransactionHandler = (*intermediateResultsProcessor)(nil) @@ -89,7 +90,7 @@ func NewIntermediateResultsProcessor( shardCoordinator: args.Coordinator, store: args.Store, storageType: dataRetriever.UnsignedTransactionUnit, - mapProcessedResult: make(map[string][][]byte), + mapProcessedResult: make(map[string]*processedResult), economicsFee: args.EconomicsFee, } @@ -237,7 +238,7 @@ func (irp *intermediateResultsProcessor) VerifyInterMiniBlocks(body *block.Body) } // AddIntermediateTransactions adds smart contract results from smart contract processing for cross-shard calls -func (irp *intermediateResultsProcessor) AddIntermediateTransactions(txs []data.TransactionHandler) error { +func (irp *intermediateResultsProcessor) AddIntermediateTransactions(txs []data.TransactionHandler, key []byte) error { irp.mutInterResultsForBlock.Lock() defer irp.mutInterResultsForBlock.Unlock() @@ -261,7 +262,7 @@ func (irp *intermediateResultsProcessor) AddIntermediateTransactions(txs []data. } if log.GetLevel() == logger.LogTrace { - //spew.Sdump is very useful when debugging errors like `receipts hash mismatch` + // spew.Sdump is very useful when debugging errors like `receipts hash mismatch` log.Trace("scr added", "txHash", addScr.PrevTxHash, "hash", scrHash, "nonce", addScr.Nonce, "gasLimit", addScr.GasLimit, "value", addScr.Value, "dump", spew.Sdump(addScr)) } @@ -269,7 +270,7 @@ func (irp *intermediateResultsProcessor) AddIntermediateTransactions(txs []data. sndShId, dstShId := irp.getShardIdsFromAddresses(addScr.SndAddr, addScr.RcvAddr) irp.executionOrderHandler.Add(scrHash) - irp.addIntermediateTxToResultsForBlock(addScr, scrHash, sndShId, dstShId) + irp.addIntermediateTxToResultsForBlock(addScr, scrHash, sndShId, dstShId, key) } return nil diff --git a/process/block/postprocess/intermediateResults_test.go b/process/block/postprocess/intermediateResults_test.go index b9a0a8e8f83..9ef1f6d0358 100644 --- a/process/block/postprocess/intermediateResults_test.go +++ b/process/block/postprocess/intermediateResults_test.go @@ -13,6 +13,9 @@ import ( "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" @@ -23,8 +26,6 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" "github.com/multiversx/mx-chain-go/testscommon/storage" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const maxGasLimitPerBlock = uint64(1500000000) @@ -198,7 +199,7 @@ func TestIntermediateResultsProcessor_AddIntermediateTransactions(t *testing.T) assert.NotNil(t, irp) assert.Nil(t, err) - err = irp.AddIntermediateTransactions(nil) + err = irp.AddIntermediateTransactions(nil, nil) assert.Nil(t, err) } @@ -216,7 +217,7 @@ func TestIntermediateResultsProcessor_AddIntermediateTransactionsWrongType(t *te txs := make([]data.TransactionHandler, 0) txs = append(txs, &transaction.Transaction{}) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Equal(t, process.ErrWrongTypeAssertion, err) } @@ -242,7 +243,7 @@ func TestIntermediateResultsProcessor_AddIntermediateTransactionsNilSender(t *te shardC.ComputeIdCalled = func(address []byte) uint32 { return shardC.SelfId() } - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Equal(t, process.ErrNilSndAddr, err) } @@ -268,7 +269,7 @@ func TestIntermediateResultsProcessor_AddIntermediateTransactionsNilReceiver(t * shardC.ComputeIdCalled = func(address []byte) uint32 { return shardC.SelfId() } - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Equal(t, process.ErrNilRcvAddr, err) } @@ -303,7 +304,7 @@ func TestIntermediateResultsProcessor_AddIntermediateTransactionsShardIdMismatch txs = append(txs, scr) txs = append(txs, scr) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Equal(t, process.ErrShardIdMissmatch, err) } @@ -329,14 +330,14 @@ func TestIntermediateResultsProcessor_AddIntermediateTransactionsNegativeValueIn shardC.ComputeIdCalled = func(address []byte) uint32 { return shardC.SelfId() } - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) shardC.ComputeIdCalled = func(address []byte) uint32 { return shardC.SelfId() + 1 } - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Equal(t, process.ErrNegativeValue, err) } @@ -364,7 +365,7 @@ func TestIntermediateResultsProcessor_AddIntermediateTransactionsAddrGood(t *tes txs = append(txs, scr) txs = append(txs, scr) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) } @@ -394,25 +395,26 @@ func TestIntermediateResultsProcessor_AddIntermediateTransactionsAddAndRevert(t txs = append(txs, &smartContractResult.SmartContractResult{RcvAddr: []byte("rcv"), SndAddr: []byte("snd"), Value: big.NewInt(0), PrevTxHash: txHash, Nonce: 3}) txs = append(txs, &smartContractResult.SmartContractResult{RcvAddr: []byte("rcv"), SndAddr: []byte("snd"), Value: big.NewInt(0), PrevTxHash: txHash, Nonce: 4}) + parentKey := []byte("parentKey") key := []byte("key") - irp.InitProcessedResults(key) + irp.InitProcessedResults(key, parentKey) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, key) assert.Nil(t, err) irp.mutInterResultsForBlock.Lock() - assert.Equal(t, len(irp.mapProcessedResult[string(key)]), len(txs)) + assert.Equal(t, len(irp.mapProcessedResult[string(key)].results), len(txs)) assert.Equal(t, len(txs), calledCount) irp.mutInterResultsForBlock.Unlock() irp.RemoveProcessedResults(key) irp.mutInterResultsForBlock.Lock() assert.Equal(t, len(irp.interResultsForBlock), 0) - assert.Equal(t, len(irp.mapProcessedResult[string(key)]), len(txs)) + require.Nil(t, irp.mapProcessedResult[string(key)]) irp.mutInterResultsForBlock.Unlock() - irp.InitProcessedResults(key) + irp.InitProcessedResults(key, parentKey) irp.mutInterResultsForBlock.Lock() - assert.Equal(t, len(irp.mapProcessedResult[string(key)]), 0) + assert.Equal(t, len(irp.mapProcessedResult[string(key)].results), 0) irp.mutInterResultsForBlock.Unlock() } @@ -460,7 +462,7 @@ func TestIntermediateResultsProcessor_CreateAllInterMiniBlocksNotCrossShard(t *t txs = append(txs, scr) txs = append(txs, scr) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) mbs := irp.CreateAllInterMiniBlocks() @@ -500,7 +502,7 @@ func TestIntermediateResultsProcessor_CreateAllInterMiniBlocksCrossShard(t *test txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: []byte("recvaddr4"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: []byte("recvaddr5"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) mbs := irp.CreateAllInterMiniBlocks() @@ -545,7 +547,7 @@ func TestIntermediateResultsProcessor_GetNumOfCrossInterMbsAndTxsShouldWork(t *t txs = append(txs, &smartContractResult.SmartContractResult{Nonce: 8, SndAddr: snd, RcvAddr: []byte("3"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) txs = append(txs, &smartContractResult.SmartContractResult{Nonce: 9, SndAddr: snd, RcvAddr: []byte("3"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) - _ = irp.AddIntermediateTransactions(txs) + _ = irp.AddIntermediateTransactions(txs, nil) numMbs, numTxs := irp.GetNumOfCrossInterMbsAndTxs() assert.Equal(t, 3, numMbs) @@ -644,7 +646,7 @@ func TestIntermediateResultsProcessor_VerifyInterMiniBlocksBodyMiniBlockMissmatc txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: []byte("recvaddr4"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: []byte("recvaddr5"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) err = irp.VerifyInterMiniBlocks(body) @@ -689,7 +691,7 @@ func TestIntermediateResultsProcessor_VerifyInterMiniBlocksBodyShouldPass(t *tes txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: []byte("recvaddr4"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: []byte("recvaddr5"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) miniBlock := &block.MiniBlock{ @@ -763,7 +765,7 @@ func TestIntermediateResultsProcessor_SaveCurrentIntermediateTxToStorageShouldSa txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: []byte("recvaddr4"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: []byte("recvaddr5"), Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) irp.SaveCurrentIntermediateTxToStorage() @@ -843,7 +845,7 @@ func TestIntermediateResultsProcessor_CreateMarshalizedData(t *testing.T) { currHash, _ = core.CalculateHash(marshalizer, hasher, txs[4]) txHashes = append(txHashes, currHash) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) mrsTxs, err := irp.CreateMarshalledData(txHashes) @@ -889,7 +891,7 @@ func TestIntermediateResultsProcessor_GetAllCurrentUsedTxs(t *testing.T) { txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: snd, Nonce: 1, Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) txs = append(txs, &smartContractResult.SmartContractResult{SndAddr: snd, RcvAddr: snd, Nonce: 2, Value: big.NewInt(0), PrevTxHash: []byte("txHash")}) - err = irp.AddIntermediateTransactions(txs) + err = irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) usedTxs := irp.GetAllCurrentFinishedTxs() @@ -958,13 +960,13 @@ func TestIntermediateResultsProcessor_addIntermediateTxToResultsForBlock(t *test irp, _ := NewIntermediateResultsProcessor(createMockArgsNewIntermediateResultsProcessor()) key := []byte("key") - irp.InitProcessedResults(key) + irp.InitProcessedResults(key, nil) tx := &transaction.Transaction{} txHash := []byte("txHash") sndShardID := uint32(1) rcvShardID := uint32(2) - irp.addIntermediateTxToResultsForBlock(tx, txHash, sndShardID, rcvShardID) + irp.addIntermediateTxToResultsForBlock(tx, txHash, sndShardID, rcvShardID, key) require.Equal(t, 1, len(irp.interResultsForBlock)) require.Equal(t, 1, len(irp.mapProcessedResult)) @@ -977,6 +979,6 @@ func TestIntermediateResultsProcessor_addIntermediateTxToResultsForBlock(t *test intermediateResultsHashes, ok := irp.mapProcessedResult[string(key)] require.True(t, ok) - require.Equal(t, 1, len(intermediateResultsHashes)) - assert.Equal(t, txHash, intermediateResultsHashes[0]) + require.Equal(t, 1, len(intermediateResultsHashes.results)) + assert.Equal(t, txHash, intermediateResultsHashes.results[0]) } diff --git a/process/block/postprocess/oneMBPostProcessor.go b/process/block/postprocess/oneMBPostProcessor.go index 5c68c3b194b..6a87e32d6f4 100644 --- a/process/block/postprocess/oneMBPostProcessor.go +++ b/process/block/postprocess/oneMBPostProcessor.go @@ -10,6 +10,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/sharding" @@ -54,7 +55,7 @@ func NewOneMiniBlockPostProcessor( shardCoordinator: coordinator, store: store, storageType: storageType, - mapProcessedResult: make(map[string][][]byte), + mapProcessedResult: make(map[string]*processedResult), economicsFee: economicsFee, } @@ -143,7 +144,7 @@ func (opp *oneMBPostProcessor) VerifyInterMiniBlocks(body *block.Body) error { } // AddIntermediateTransactions adds receipts/bad transactions resulting from transaction processor -func (opp *oneMBPostProcessor) AddIntermediateTransactions(txs []data.TransactionHandler) error { +func (opp *oneMBPostProcessor) AddIntermediateTransactions(txs []data.TransactionHandler, key []byte) error { opp.mutInterResultsForBlock.Lock() defer opp.mutInterResultsForBlock.Unlock() @@ -155,7 +156,7 @@ func (opp *oneMBPostProcessor) AddIntermediateTransactions(txs []data.Transactio return err } - opp.addIntermediateTxToResultsForBlock(txs[i], txHash, selfId, selfId) + opp.addIntermediateTxToResultsForBlock(txs[i], txHash, selfId, selfId, key) } return nil diff --git a/process/block/postprocess/oneMBPostProcessor_test.go b/process/block/postprocess/oneMBPostProcessor_test.go index 5151fdc5f88..236f457198e 100644 --- a/process/block/postprocess/oneMBPostProcessor_test.go +++ b/process/block/postprocess/oneMBPostProcessor_test.go @@ -9,13 +9,14 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/stretchr/testify/assert" + "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/mock" "github.com/multiversx/mx-chain-go/testscommon/economicsmocks" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" "github.com/multiversx/mx-chain-go/testscommon/storage" - "github.com/stretchr/testify/assert" ) func TestNewOneMBPostProcessor_NilHasher(t *testing.T) { @@ -154,7 +155,9 @@ func TestOneMBPostProcessor_CreateAllInterMiniBlocksOneMinBlock(t *testing.T) { txs = append(txs, &transaction.Transaction{}) txs = append(txs, &transaction.Transaction{}) - err := irp.AddIntermediateTransactions(txs) + // with no InitProcessedResults, means that the transactions are added as scheduled transactions, not as + // processing results from the execution of other transactions or miniblocks + err := irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) mbs := irp.CreateAllInterMiniBlocks() @@ -198,7 +201,7 @@ func TestOneMBPostProcessor_VerifyTooManyBlock(t *testing.T) { txs = append(txs, &transaction.Transaction{SndAddr: []byte("snd"), RcvAddr: []byte("recvaddr4")}) txs = append(txs, &transaction.Transaction{SndAddr: []byte("snd"), RcvAddr: []byte("recvaddr5")}) - err := irp.AddIntermediateTransactions(txs) + err := irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) miniBlock := &block.MiniBlock{ @@ -267,7 +270,7 @@ func TestOneMBPostProcessor_VerifyOk(t *testing.T) { txs = append(txs, &transaction.Transaction{SndAddr: []byte("snd"), RcvAddr: []byte("recvaddr4")}) txs = append(txs, &transaction.Transaction{SndAddr: []byte("snd"), RcvAddr: []byte("recvaddr5")}) - err := irp.AddIntermediateTransactions(txs) + err := irp.AddIntermediateTransactions(txs, nil) assert.Nil(t, err) miniBlock := &block.MiniBlock{ diff --git a/process/block/preprocess/basePreProcess.go b/process/block/preprocess/basePreProcess.go index 58534fe4395..56ea615559e 100644 --- a/process/block/preprocess/basePreProcess.go +++ b/process/block/preprocess/basePreProcess.go @@ -12,6 +12,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" @@ -497,9 +498,9 @@ func (bpp *basePreProcess) updateGasConsumedWithGasRefundedAndGasPenalized( gasInfo.totalGasConsumedInSelfShard -= gasToBeSubtracted } -func (bpp *basePreProcess) handleProcessTransactionInit(preProcessorExecutionInfoHandler process.PreProcessorExecutionInfoHandler, txHash []byte) int { +func (bpp *basePreProcess) handleProcessTransactionInit(preProcessorExecutionInfoHandler process.PreProcessorExecutionInfoHandler, txHash []byte, mbHash []byte) int { snapshot := bpp.accounts.JournalLen() - preProcessorExecutionInfoHandler.InitProcessedTxsResults(txHash) + preProcessorExecutionInfoHandler.InitProcessedTxsResults(txHash, mbHash) return snapshot } diff --git a/process/block/preprocess/basePreProcess_test.go b/process/block/preprocess/basePreProcess_test.go index fc17684ca08..221f69c28db 100644 --- a/process/block/preprocess/basePreProcess_test.go +++ b/process/block/preprocess/basePreProcess_test.go @@ -4,22 +4,26 @@ import ( "bytes" "testing" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/multiversx/mx-chain-go/testscommon" "github.com/multiversx/mx-chain-go/testscommon/state" - "github.com/stretchr/testify/assert" ) func TestBasePreProcess_handleProcessTransactionInit(t *testing.T) { t.Parallel() + mbHash := []byte("mb hash") txHash := []byte("tx hash") initProcessedTxsCalled := false preProcessorExecutionInfoHandler := &testscommon.PreProcessorExecutionInfoHandlerMock{ - InitProcessedTxsResultsCalled: func(key []byte) { + InitProcessedTxsResultsCalled: func(key []byte, parentKey []byte) { if !bytes.Equal(key, txHash) { return } + require.Equal(t, mbHash, parentKey) initProcessedTxsCalled = true }, @@ -41,7 +45,7 @@ func TestBasePreProcess_handleProcessTransactionInit(t *testing.T) { }, } - recoveredJournalLen := bp.handleProcessTransactionInit(preProcessorExecutionInfoHandler, txHash) + recoveredJournalLen := bp.handleProcessTransactionInit(preProcessorExecutionInfoHandler, txHash, mbHash) assert.Equal(t, journalLen, recoveredJournalLen) assert.True(t, initProcessedTxsCalled) } diff --git a/process/block/preprocess/gasComputation.go b/process/block/preprocess/gasComputation.go index 628c6de455f..9888917b7f3 100644 --- a/process/block/preprocess/gasComputation.go +++ b/process/block/preprocess/gasComputation.go @@ -426,7 +426,7 @@ func (gc *gasComputation) computeGasProvidedByTxV1( } func (gc *gasComputation) isRelayedTx(txType process.TransactionType) bool { - return txType == process.RelayedTx || txType == process.RelayedTxV2 + return txType == process.RelayedTx || txType == process.RelayedTxV2 || txType == process.RelayedTxV3 } // IsInterfaceNil returns true if there is no value under the interface diff --git a/process/block/preprocess/rewardTxPreProcessor.go b/process/block/preprocess/rewardTxPreProcessor.go index d80d8ffbb4c..e695d51e498 100644 --- a/process/block/preprocess/rewardTxPreProcessor.go +++ b/process/block/preprocess/rewardTxPreProcessor.go @@ -10,6 +10,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/rewardTx" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" @@ -494,6 +495,11 @@ func (rtp *rewardTxPreprocessor) ProcessMiniBlock( return nil, indexOfLastTxProcessed, false, process.ErrMaxBlockSizeReached } + miniBlockHash, err := core.CalculateHash(rtp.marshalizer, rtp.hasher, miniBlock) + if err != nil { + return nil, indexOfLastTxProcessed, false, err + } + processedTxHashes := make([][]byte, 0) for txIndex = indexOfFirstTxToBeProcessed; txIndex < len(miniBlockRewardTxs); txIndex++ { if !haveTime() { @@ -506,7 +512,7 @@ func (rtp *rewardTxPreprocessor) ProcessMiniBlock( break } - snapshot := rtp.handleProcessTransactionInit(preProcessorExecutionInfoHandler, miniBlockTxHashes[txIndex]) + snapshot := rtp.handleProcessTransactionInit(preProcessorExecutionInfoHandler, miniBlockTxHashes[txIndex], miniBlockHash) rtp.txExecutionOrderHandler.Add(miniBlockTxHashes[txIndex]) err = rtp.rewardsProcessor.ProcessRewardTransaction(miniBlockRewardTxs[txIndex]) diff --git a/process/block/preprocess/smartContractResults.go b/process/block/preprocess/smartContractResults.go index 471c94360bd..3ac910a1834 100644 --- a/process/block/preprocess/smartContractResults.go +++ b/process/block/preprocess/smartContractResults.go @@ -11,6 +11,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" @@ -571,6 +572,11 @@ func (scr *smartContractResults) ProcessMiniBlock( return nil, indexOfLastTxProcessed, false, process.ErrMaxBlockSizeReached } + miniBlockHash, err := core.CalculateHash(scr.marshalizer, scr.hasher, miniBlock) + if err != nil { + return nil, indexOfLastTxProcessed, false, err + } + gasInfo := gasConsumedInfo{ gasConsumedByMiniBlockInReceiverShard: uint64(0), gasConsumedByMiniBlocksInSenderShard: uint64(0), @@ -633,7 +639,7 @@ func (scr *smartContractResults) ProcessMiniBlock( break } - snapshot := scr.handleProcessTransactionInit(preProcessorExecutionInfoHandler, miniBlockTxHashes[txIndex]) + snapshot := scr.handleProcessTransactionInit(preProcessorExecutionInfoHandler, miniBlockTxHashes[txIndex], miniBlockHash) scr.txExecutionOrderHandler.Add(miniBlockTxHashes[txIndex]) _, err = scr.scrProcessor.ProcessSmartContractResult(miniBlockScrs[txIndex]) diff --git a/process/block/preprocess/transactions.go b/process/block/preprocess/transactions.go index fd53f95aad5..eb24585a55b 100644 --- a/process/block/preprocess/transactions.go +++ b/process/block/preprocess/transactions.go @@ -15,6 +15,9 @@ import ( "github.com/multiversx/mx-chain-core-go/data/transaction" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + logger "github.com/multiversx/mx-chain-logger-go" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" @@ -23,8 +26,6 @@ import ( "github.com/multiversx/mx-chain-go/state" "github.com/multiversx/mx-chain-go/storage" "github.com/multiversx/mx-chain-go/storage/txcache" - logger "github.com/multiversx/mx-chain-logger-go" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" ) var _ process.DataMarshalizer = (*transactions)(nil) @@ -1508,6 +1509,11 @@ func (txs *transactions) ProcessMiniBlock( return nil, indexOfLastTxProcessed, false, process.ErrMaxBlockSizeReached } + miniBlockHash, err := core.CalculateHash(txs.marshalizer, txs.hasher, miniBlock) + if err != nil { + return nil, indexOfLastTxProcessed, false, err + } + var totalGasConsumed uint64 if scheduledMode { totalGasConsumed = txs.gasHandler.TotalGasProvidedAsScheduled() @@ -1587,7 +1593,8 @@ func (txs *transactions) ProcessMiniBlock( miniBlockTxs[txIndex], miniBlockTxHashes[txIndex], &gasInfo, - gasProvidedByTxInSelfShard) + gasProvidedByTxInSelfShard, + miniBlockHash) if err != nil { break } @@ -1646,9 +1653,10 @@ func (txs *transactions) processInNormalMode( txHash []byte, gasInfo *gasConsumedInfo, gasProvidedByTxInSelfShard uint64, + mbHash []byte, ) error { - snapshot := txs.handleProcessTransactionInit(preProcessorExecutionInfoHandler, txHash) + snapshot := txs.handleProcessTransactionInit(preProcessorExecutionInfoHandler, txHash, mbHash) txs.txExecutionOrderHandler.Add(txHash) _, err := txs.txProcessor.ProcessTransaction(tx) diff --git a/process/common.go b/process/common.go index f06e0d00091..e8c9c7504ff 100644 --- a/process/common.go +++ b/process/common.go @@ -680,6 +680,10 @@ func DisplayProcessTxDetails( txHash []byte, addressPubkeyConverter core.PubkeyConverter, ) { + if log.GetLevel() > logger.LogTrace { + return + } + if !check.IfNil(accountHandler) { account, ok := accountHandler.(state.UserAccountHandler) if ok { diff --git a/process/constants.go b/process/constants.go index f75e7b882ee..44101f50b7c 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 v3 transaction + 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/process.go b/process/coordinator/process.go index fad1906ef00..8a50d9f0b21 100644 --- a/process/coordinator/process.go +++ b/process/coordinator/process.go @@ -15,6 +15,8 @@ import ( "github.com/multiversx/mx-chain-core-go/data/block" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + logger "github.com/multiversx/mx-chain-logger-go" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/preprocess" @@ -24,7 +26,6 @@ import ( "github.com/multiversx/mx-chain-go/state" "github.com/multiversx/mx-chain-go/storage" "github.com/multiversx/mx-chain-go/storage/cache" - logger "github.com/multiversx/mx-chain-logger-go" ) var _ process.TransactionCoordinator = (*transactionCoordinator)(nil) @@ -703,7 +704,7 @@ func (tc *transactionCoordinator) CreateMbsAndProcessCrossShardTransactionsDstMe oldIndexOfLastTxProcessed := processedMbInfo.IndexOfLastTxProcessed - errProc := tc.processCompleteMiniBlock(preproc, miniBlock, miniBlockInfo.Hash, haveTime, haveAdditionalTime, scheduledMode, processedMbInfo) + errProc := tc.processCompleteMiniBlock(preproc, miniBlock, miniBlockInfo.Hash, haveTime, haveAdditionalTime, scheduledMode, processedMbInfo, headerHash) tc.handleProcessMiniBlockExecution(oldIndexOfLastTxProcessed, miniBlock, processedMbInfo, createMBDestMeExecutionInfo) if errProc != nil { shouldSkipShard[miniBlockInfo.SenderShardID] = true @@ -810,7 +811,7 @@ func (tc *transactionCoordinator) handleCreateMiniBlocksDestMeInit(headerHash [] return } - tc.InitProcessedTxsResults(headerHash) + tc.InitProcessedTxsResults(headerHash, nil) tc.gasHandler.Reset(headerHash) } @@ -1190,9 +1191,10 @@ func (tc *transactionCoordinator) processCompleteMiniBlock( haveAdditionalTime func() bool, scheduledMode bool, processedMbInfo *processedMb.ProcessedMiniBlockInfo, + headerHash []byte, ) error { - snapshot := tc.handleProcessMiniBlockInit(miniBlockHash) + snapshot := tc.handleProcessMiniBlockInit(miniBlockHash, headerHash) log.Debug("transactionsCoordinator.processCompleteMiniBlock: before processing", "scheduled mode", scheduledMode, @@ -1259,9 +1261,9 @@ func (tc *transactionCoordinator) processCompleteMiniBlock( return nil } -func (tc *transactionCoordinator) handleProcessMiniBlockInit(miniBlockHash []byte) int { +func (tc *transactionCoordinator) handleProcessMiniBlockInit(miniBlockHash []byte, headerHash []byte) int { snapshot := tc.accounts.JournalLen() - tc.InitProcessedTxsResults(miniBlockHash) + tc.InitProcessedTxsResults(miniBlockHash, headerHash) tc.gasHandler.Reset(miniBlockHash) return snapshot @@ -1282,7 +1284,7 @@ func (tc *transactionCoordinator) handleProcessTransactionError(snapshot int, mi } // InitProcessedTxsResults inits processed txs results for the given key -func (tc *transactionCoordinator) InitProcessedTxsResults(key []byte) { +func (tc *transactionCoordinator) InitProcessedTxsResults(key []byte, parentKey []byte) { tc.mutInterimProcessors.RLock() defer tc.mutInterimProcessors.RUnlock() @@ -1291,7 +1293,7 @@ func (tc *transactionCoordinator) InitProcessedTxsResults(key []byte) { if !ok { continue } - interProc.InitProcessedResults(key) + interProc.InitProcessedResults(key, parentKey) } } @@ -1831,14 +1833,14 @@ func checkTransactionCoordinatorNilParameters(arguments ArgTransactionCoordinato } // AddIntermediateTransactions adds the given intermediate transactions -func (tc *transactionCoordinator) AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler) error { +func (tc *transactionCoordinator) AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler, key []byte) error { for blockType, scrs := range mapSCRs { interimProc := tc.getInterimProcessor(blockType) if check.IfNil(interimProc) { return process.ErrNilIntermediateProcessor } - err := interimProc.AddIntermediateTransactions(scrs) + err := interimProc.AddIntermediateTransactions(scrs, key) if err != nil { return err } diff --git a/process/coordinator/process_test.go b/process/coordinator/process_test.go index e23c8f8f1ec..d1dff667cb7 100644 --- a/process/coordinator/process_test.go +++ b/process/coordinator/process_test.go @@ -21,6 +21,10 @@ import ( "github.com/multiversx/mx-chain-core-go/data/scheduled" "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/transaction" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" @@ -40,9 +44,6 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" storageStubs "github.com/multiversx/mx-chain-go/testscommon/storage" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const MaxGasLimitPerBlock = uint64(100000) @@ -751,24 +752,25 @@ func TestTransactionCoordinator_CreateMarshalizedDataWithTxsAndScr(t *testing.T) scrs := make([]data.TransactionHandler, 0) body := &block.Body{} body.MiniBlocks = append(body.MiniBlocks, createMiniBlockWithOneTx(0, 1, block.TxBlock, txHash)) + genericTxHash := []byte("txHash") - scr := &smartContractResult.SmartContractResult{SndAddr: []byte("snd"), RcvAddr: []byte("rcv"), Value: big.NewInt(99), PrevTxHash: []byte("txHash")} + scr := &smartContractResult.SmartContractResult{SndAddr: []byte("snd"), RcvAddr: []byte("rcv"), Value: big.NewInt(99), PrevTxHash: genericTxHash} scrHash, _ := core.CalculateHash(&mock.MarshalizerMock{}, &hashingMocks.HasherMock{}, scr) scrs = append(scrs, scr) body.MiniBlocks = append(body.MiniBlocks, createMiniBlockWithOneTx(0, 1, block.SmartContractResultBlock, scrHash)) - scr = &smartContractResult.SmartContractResult{SndAddr: []byte("snd"), RcvAddr: []byte("rcv"), Value: big.NewInt(199), PrevTxHash: []byte("txHash")} + scr = &smartContractResult.SmartContractResult{SndAddr: []byte("snd"), RcvAddr: []byte("rcv"), Value: big.NewInt(199), PrevTxHash: genericTxHash} scrHash, _ = core.CalculateHash(&mock.MarshalizerMock{}, &hashingMocks.HasherMock{}, scr) scrs = append(scrs, scr) body.MiniBlocks = append(body.MiniBlocks, createMiniBlockWithOneTx(0, 1, block.SmartContractResultBlock, scrHash)) - scr = &smartContractResult.SmartContractResult{SndAddr: []byte("snd"), RcvAddr: []byte("rcv"), Value: big.NewInt(299), PrevTxHash: []byte("txHash")} + scr = &smartContractResult.SmartContractResult{SndAddr: []byte("snd"), RcvAddr: []byte("rcv"), Value: big.NewInt(299), PrevTxHash: genericTxHash} scrHash, _ = core.CalculateHash(&mock.MarshalizerMock{}, &hashingMocks.HasherMock{}, scr) scrs = append(scrs, scr) body.MiniBlocks = append(body.MiniBlocks, createMiniBlockWithOneTx(0, 1, block.SmartContractResultBlock, scrHash)) scrInterimProc, _ := interimContainer.Get(block.SmartContractResultBlock) - _ = scrInterimProc.AddIntermediateTransactions(scrs) + _ = scrInterimProc.AddIntermediateTransactions(scrs, genericTxHash) mrTxs := tc.CreateMarshalizedData(body) assert.Equal(t, 1, len(mrTxs)) @@ -1019,6 +1021,7 @@ func TestTransactionCoordinator_CreateMbsAndProcessCrossShardTransactionsWithSki } func TestTransactionCoordinator_HandleProcessMiniBlockInit(t *testing.T) { + headerHash := []byte("header hash") mbHash := []byte("miniblock hash") numResetGasHandler := 0 numInitInterimProc := 0 @@ -1034,7 +1037,8 @@ func TestTransactionCoordinator_HandleProcessMiniBlockInit(t *testing.T) { keysInterimProcs: []block.Type{block.SmartContractResultBlock}, interimProcessors: map[block.Type]process.IntermediateTransactionHandler{ block.SmartContractResultBlock: &mock.IntermediateTransactionHandlerStub{ - InitProcessedResultsCalled: func(key []byte) { + InitProcessedResultsCalled: func(key []byte, parentKey []byte) { + assert.Equal(t, headerHash, parentKey) assert.Equal(t, mbHash, key) numInitInterimProc++ }, @@ -1048,7 +1052,7 @@ func TestTransactionCoordinator_HandleProcessMiniBlockInit(t *testing.T) { numInitInterimProc = 0 shardCoord.CurrentShard = 0 - tc.handleProcessMiniBlockInit(mbHash) + tc.handleProcessMiniBlockInit(mbHash, headerHash) assert.Equal(t, 1, numResetGasHandler) assert.Equal(t, 1, numInitInterimProc) }) @@ -1057,7 +1061,7 @@ func TestTransactionCoordinator_HandleProcessMiniBlockInit(t *testing.T) { numInitInterimProc = 0 shardCoord.CurrentShard = core.MetachainShardId - tc.handleProcessMiniBlockInit(mbHash) + tc.handleProcessMiniBlockInit(mbHash, headerHash) assert.Equal(t, 1, numResetGasHandler) assert.Equal(t, 1, numInitInterimProc) }) @@ -1925,6 +1929,7 @@ func TestShardProcessor_ProcessMiniBlockCompleteWithOkTxsShouldExecuteThemAndNot // all txs will be in datapool and none of them will return err when processed // so, tx processor will return nil on processing tx + headerHash := []byte("header hash") txHash1 := []byte("tx hash 1") txHash2 := []byte("tx hash 2") txHash3 := []byte("tx hash 3") @@ -2053,7 +2058,7 @@ func TestShardProcessor_ProcessMiniBlockCompleteWithOkTxsShouldExecuteThemAndNot IndexOfLastTxProcessed: -1, FullyProcessed: false, } - err = tc.processCompleteMiniBlock(preproc, &miniBlock, []byte("hash"), haveTime, haveAdditionalTime, false, processedMbInfo) + err = tc.processCompleteMiniBlock(preproc, &miniBlock, []byte("hash"), haveTime, haveAdditionalTime, false, processedMbInfo, headerHash) assert.Nil(t, err) assert.Equal(t, tx1Nonce, tx1ExecutionResult) @@ -2085,6 +2090,7 @@ func TestShardProcessor_ProcessMiniBlockCompleteWithErrorWhileProcessShouldCallR TxHashes: [][]byte{txHash1, txHash2, txHash3}, } + headerHash := []byte("header hash") tx1Nonce := uint64(45) tx2Nonce := uint64(46) tx3Nonce := uint64(47) @@ -2198,7 +2204,7 @@ func TestShardProcessor_ProcessMiniBlockCompleteWithErrorWhileProcessShouldCallR IndexOfLastTxProcessed: -1, FullyProcessed: false, } - err = tc.processCompleteMiniBlock(preproc, &miniBlock, []byte("hash"), haveTime, haveAdditionalTime, false, processedMbInfo) + err = tc.processCompleteMiniBlock(preproc, &miniBlock, []byte("hash"), haveTime, haveAdditionalTime, false, processedMbInfo, headerHash) assert.Equal(t, process.ErrHigherNonceInTransaction, err) assert.True(t, revertAccntStateCalled) @@ -2342,7 +2348,8 @@ func TestTransactionCoordinator_VerifyCreatedBlockTransactionsOk(t *testing.T) { tx, _ := tdp.UnsignedTransactions().SearchFirstData(scrHash) txs := make([]data.TransactionHandler, 0) txs = append(txs, tx.(data.TransactionHandler)) - err = interProc.AddIntermediateTransactions(txs) + txHash, _ := core.CalculateHash(&mock.MarshalizerMock{}, &hashingMocks.HasherMock{}, tx) + err = interProc.AddIntermediateTransactions(txs, txHash) assert.Nil(t, err) body := &block.Body{MiniBlocks: []*block.MiniBlock{{Type: block.SmartContractResultBlock, ReceiverShardID: shardCoordinator.SelfId() + 1, TxHashes: [][]byte{scrHash}}}} @@ -4183,7 +4190,7 @@ func TestTransactionCoordinator_AddIntermediateTransactions(t *testing.T) { }, } - err := tc.AddIntermediateTransactions(mapSCRs) + err := tc.AddIntermediateTransactions(mapSCRs, nil) assert.Equal(t, process.ErrNilIntermediateProcessor, err) }) @@ -4195,7 +4202,7 @@ func TestTransactionCoordinator_AddIntermediateTransactions(t *testing.T) { expectedErr := errors.New("expected err") tc.keysInterimProcs = append(tc.keysInterimProcs, block.SmartContractResultBlock) tc.interimProcessors[block.SmartContractResultBlock] = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { return expectedErr }, } @@ -4208,7 +4215,7 @@ func TestTransactionCoordinator_AddIntermediateTransactions(t *testing.T) { }, } - err := tc.AddIntermediateTransactions(mapSCRs) + err := tc.AddIntermediateTransactions(mapSCRs, nil) assert.Equal(t, expectedErr, err) }) @@ -4225,7 +4232,7 @@ func TestTransactionCoordinator_AddIntermediateTransactions(t *testing.T) { tc.keysInterimProcs = append(tc.keysInterimProcs, block.SmartContractResultBlock) tc.interimProcessors[block.SmartContractResultBlock] = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { assert.Equal(t, expectedTxs, txs) return nil }, @@ -4239,7 +4246,7 @@ func TestTransactionCoordinator_AddIntermediateTransactions(t *testing.T) { }, } - err := tc.AddIntermediateTransactions(mapSCRs) + err := tc.AddIntermediateTransactions(mapSCRs, nil) assert.Nil(t, err) }) } diff --git a/process/coordinator/transactionType.go b/process/coordinator/transactionType.go index f1d47aff44c..d754da2c34d 100644 --- a/process/coordinator/transactionType.go +++ b/process/coordinator/transactionType.go @@ -91,6 +91,10 @@ func (tth *txTypeHandler) ComputeTransactionType(tx data.TransactionHandler) (pr return process.InvalidTransaction, process.InvalidTransaction } + if tth.isRelayedTransactionV3(tx) { + return process.RelayedTxV3, process.RelayedTxV3 + } + if len(tx.GetData()) == 0 { return process.MoveBalance, process.MoveBalance } @@ -191,6 +195,10 @@ func (tth *txTypeHandler) isRelayedTransactionV2(functionName string) bool { return functionName == core.RelayedTransactionV2 } +func (tth *txTypeHandler) isRelayedTransactionV3(tx data.TransactionHandler) bool { + return len(tx.GetUserTransactions()) != 0 +} + func (tth *txTypeHandler) isDestAddressEmpty(tx data.TransactionHandler) bool { isEmptyAddress := bytes.Equal(tx.GetRcvAddr(), make([]byte, tth.pubkeyConv.Len())) return isEmptyAddress diff --git a/process/coordinator/transactionType_test.go b/process/coordinator/transactionType_test.go index 918b6069212..9739075d847 100644 --- a/process/coordinator/transactionType_test.go +++ b/process/coordinator/transactionType_test.go @@ -466,6 +466,32 @@ 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.InnerTransactions = []*transaction.Transaction{{Nonce: 1}} + + 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/disabled/failedTxLogsAccumulator.go b/process/disabled/failedTxLogsAccumulator.go new file mode 100644 index 00000000000..3bd3f01cd69 --- /dev/null +++ b/process/disabled/failedTxLogsAccumulator.go @@ -0,0 +1,33 @@ +package disabled + +import ( + "github.com/multiversx/mx-chain-core-go/data" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" +) + +type failedTxLogsAccumulator struct { +} + +// NewFailedTxLogsAccumulator returns a new instance of disabled failedTxLogsAccumulator +func NewFailedTxLogsAccumulator() *failedTxLogsAccumulator { + return &failedTxLogsAccumulator{} +} + +// GetLogs returns false as it is disabled +func (accumulator *failedTxLogsAccumulator) GetLogs(_ []byte) (data.TransactionHandler, []*vmcommon.LogEntry, bool) { + return nil, nil, false +} + +// SaveLogs returns nil as it is disabled +func (accumulator *failedTxLogsAccumulator) SaveLogs(_ []byte, _ data.TransactionHandler, _ []*vmcommon.LogEntry) error { + return nil +} + +// Remove does nothing as it is disabled +func (accumulator *failedTxLogsAccumulator) Remove(_ []byte) { +} + +// IsInterfaceNil returns true if there is no value under the interface +func (accumulator *failedTxLogsAccumulator) IsInterfaceNil() bool { + return accumulator == nil +} diff --git a/process/disabled/relayedTxV3Processor.go b/process/disabled/relayedTxV3Processor.go new file mode 100644 index 00000000000..ddabd2753c8 --- /dev/null +++ b/process/disabled/relayedTxV3Processor.go @@ -0,0 +1,23 @@ +package disabled + +import ( + "github.com/multiversx/mx-chain-core-go/data/transaction" +) + +type relayedTxV3Processor struct { +} + +// NewRelayedTxV3Processor returns a new instance of disabled relayedTxV3Processor +func NewRelayedTxV3Processor() *relayedTxV3Processor { + return &relayedTxV3Processor{} +} + +// CheckRelayedTx returns nil as it is disabled +func (proc *relayedTxV3Processor) CheckRelayedTx(_ *transaction.Transaction) error { + return nil +} + +// IsInterfaceNil returns true if there is no value under the interface +func (proc *relayedTxV3Processor) IsInterfaceNil() bool { + return proc == nil +} diff --git a/process/disabled/txTypeHandler.go b/process/disabled/txTypeHandler.go new file mode 100644 index 00000000000..302e81af555 --- /dev/null +++ b/process/disabled/txTypeHandler.go @@ -0,0 +1,28 @@ +package disabled + +import ( + "github.com/multiversx/mx-chain-core-go/data" + "github.com/multiversx/mx-chain-go/process" + logger "github.com/multiversx/mx-chain-logger-go" +) + +var log = logger.GetOrCreate("disabledTxTypeHandler") + +type txTypeHandler struct { +} + +// NewTxTypeHandler returns a new instance of disabled txTypeHandler +func NewTxTypeHandler() *txTypeHandler { + return &txTypeHandler{} +} + +// ComputeTransactionType always returns invalid transaction as it is disabled +func (handler *txTypeHandler) ComputeTransactionType(_ data.TransactionHandler) (process.TransactionType, process.TransactionType) { + log.Warn("disabled txTypeHandler ComputeTransactionType always returns invalid transaction") + return process.InvalidTransaction, process.InvalidTransaction +} + +// IsInterfaceNil returns true if there is no value under the interface +func (handler *txTypeHandler) IsInterfaceNil() bool { + return handler == nil +} diff --git a/process/economics/economicsData.go b/process/economics/economicsData.go index 5b7ce045237..a510447dab2 100644 --- a/process/economics/economicsData.go +++ b/process/economics/economicsData.go @@ -13,6 +13,7 @@ import ( "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/config" "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/process/disabled" "github.com/multiversx/mx-chain-go/statusHandler" logger "github.com/multiversx/mx-chain-logger-go" ) @@ -34,6 +35,8 @@ type economicsData struct { statusHandler core.AppStatusHandler enableEpochsHandler common.EnableEpochsHandler txVersionHandler process.TxVersionCheckerHandler + txTypeHandler process.TxTypeHandler + mutTxTypeHandler sync.RWMutex mut sync.RWMutex } @@ -75,6 +78,7 @@ func NewEconomicsData(args ArgsNewEconomicsData) (*economicsData, error) { statusHandler: statusHandler.NewNilStatusHandler(), enableEpochsHandler: args.EnableEpochsHandler, txVersionHandler: args.TxVersionChecker, + txTypeHandler: disabled.NewTxTypeHandler(), } ed.yearSettings = make(map[uint32]*config.YearSetting) @@ -137,6 +141,19 @@ func (ed *economicsData) SetStatusHandler(statusHandler core.AppStatusHandler) e return ed.rewardsConfigHandler.setStatusHandler(statusHandler) } +// SetTxTypeHandler sets the provided tx type handler +func (ed *economicsData) SetTxTypeHandler(txTypeHandler process.TxTypeHandler) error { + if check.IfNil(txTypeHandler) { + return process.ErrNilTxTypeHandler + } + + ed.mutTxTypeHandler.Lock() + ed.txTypeHandler = txTypeHandler + ed.mutTxTypeHandler.Unlock() + + return nil +} + // LeaderPercentage returns leader reward percentage func (ed *economicsData) LeaderPercentage() float64 { currentEpoch := ed.enableEpochsHandler.GetCurrentEpoch() @@ -285,6 +302,11 @@ func (ed *economicsData) ComputeTxFee(tx data.TransactionWithFeeHandler) *big.In // ComputeTxFeeInEpoch computes the provided transaction's fee in a specific epoch func (ed *economicsData) ComputeTxFeeInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) *big.Int { + if len(tx.GetUserTransactions()) > 0 { + _, totalFee, _ := ed.ComputeRelayedTxFees(tx) + return totalFee + } + if ed.enableEpochsHandler.IsFlagEnabledInEpoch(common.GasPriceModifierFlag, epoch) { if isSmartContractResult(tx) { return ed.ComputeFeeForProcessingInEpoch(tx, tx.GetGasLimit(), epoch) @@ -308,6 +330,56 @@ func (ed *economicsData) ComputeTxFeeInEpoch(tx data.TransactionWithFeeHandler, return ed.ComputeMoveBalanceFeeInEpoch(tx, epoch) } +// ComputeRelayedTxFees returns the both the total fee for the entire relayed tx and the relayed only fee +func (ed *economicsData) ComputeRelayedTxFees(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) { + innerTxs := tx.GetUserTransactions() + if len(innerTxs) == 0 { + return big.NewInt(0), big.NewInt(0), process.ErrEmptyInnerTransactions + } + + feesForInnerTxs := ed.getTotalFeesRequiredForInnerTxs(innerTxs) + + relayerUnguardedMoveBalanceFee := core.SafeMul(ed.GasPriceForMove(tx), ed.MinGasLimit()) + relayerTotalMoveBalanceFee := ed.ComputeMoveBalanceFee(tx) + relayerMoveBalanceFeeDiff := big.NewInt(0).Sub(relayerTotalMoveBalanceFee, relayerUnguardedMoveBalanceFee) + + relayerFee := big.NewInt(0).Mul(relayerUnguardedMoveBalanceFee, big.NewInt(int64(len(innerTxs)))) + relayerFee.Add(relayerFee, relayerMoveBalanceFeeDiff) // add the difference in case of guarded relayed tx + + totalFee := big.NewInt(0).Add(relayerFee, feesForInnerTxs) + + return relayerFee, totalFee, nil +} + +func (ed *economicsData) getTotalFeesRequiredForInnerTxs(innerTxs []data.TransactionHandler) *big.Int { + totalFees := big.NewInt(0) + for _, innerTx := range innerTxs { + if ed.isMoveBalance(innerTx) { + innerTxFee := ed.ComputeMoveBalanceFee(innerTx) + totalFees.Add(totalFees, innerTxFee) + + continue + } + + gasToUse := innerTx.GetGasLimit() - ed.ComputeGasLimit(innerTx) + moveBalanceUserFee := ed.ComputeMoveBalanceFee(innerTx) + processingUserFee := ed.ComputeFeeForProcessing(innerTx, gasToUse) + innerTxFee := big.NewInt(0).Add(moveBalanceUserFee, processingUserFee) + + totalFees.Add(totalFees, innerTxFee) + } + + return totalFees +} + +func (ed *economicsData) isMoveBalance(tx data.TransactionHandler) bool { + ed.mutTxTypeHandler.RLock() + _, dstTxType := ed.txTypeHandler.ComputeTransactionType(tx) + ed.mutTxTypeHandler.RUnlock() + + return dstTxType == process.MoveBalance +} + // SplitTxGasInCategories returns the gas split per categories func (ed *economicsData) SplitTxGasInCategories(tx data.TransactionWithFeeHandler) (gasLimitMove, gasLimitProcess uint64) { currentEpoch := ed.enableEpochsHandler.GetCurrentEpoch() @@ -518,6 +590,11 @@ func (ed *economicsData) ComputeGasUsedAndFeeBasedOnRefundValueInEpoch(tx data.T txFee := ed.ComputeTxFeeInEpoch(tx, epoch) + if len(tx.GetUserTransactions()) > 0 { + gasUnitsUsed := big.NewInt(0).Div(txFee, big.NewInt(0).SetUint64(tx.GetGasPrice())) + return gasUnitsUsed.Uint64(), txFee + } + isPenalizedTooMuchGasFlagEnabled := ed.enableEpochsHandler.IsFlagEnabledInEpoch(common.PenalizedTooMuchGasFlag, epoch) isGasPriceModifierFlagEnabled := ed.enableEpochsHandler.IsFlagEnabledInEpoch(common.GasPriceModifierFlag, epoch) flagCorrectTxFee := !isPenalizedTooMuchGasFlagEnabled && !isGasPriceModifierFlagEnabled diff --git a/process/economics/economicsData_test.go b/process/economics/economicsData_test.go index 1f2c913a826..5fdb8c369c2 100644 --- a/process/economics/economicsData_test.go +++ b/process/economics/economicsData_test.go @@ -8,6 +8,7 @@ import ( "testing" "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-core-go/data/transaction" "github.com/multiversx/mx-chain-go/common" @@ -1621,3 +1622,102 @@ func TestEconomicsData_RewardsTopUpFactor(t *testing.T) { value := economicsData.RewardsTopUpFactor() assert.Equal(t, topUpFactor, value) } + +func TestEconomicsData_ComputeRelayedTxFees(t *testing.T) { + t.Parallel() + + args := createArgsForEconomicsData(1) + minGasLimit, _ := strconv.Atoi(args.Economics.FeeSettings.GasLimitSettings[0].MinGasLimit) + tx := &transaction.Transaction{ + Nonce: 0, + Value: big.NewInt(0), + RcvAddr: []byte("rel"), + SndAddr: []byte("rel"), + GasPrice: 1, + GasLimit: uint64(minGasLimit) * 4, + InnerTransactions: []*transaction.Transaction{ + { + Nonce: 0, + Value: big.NewInt(1), + RcvAddr: []byte("rcv1"), + SndAddr: []byte("snd1"), + GasPrice: 1, + GasLimit: uint64(minGasLimit), + RelayerAddr: []byte("rel"), + }, + { + Nonce: 0, + Value: big.NewInt(1), + RcvAddr: []byte("rcv1"), + SndAddr: []byte("snd2"), + GasPrice: 1, + GasLimit: uint64(minGasLimit), + RelayerAddr: []byte("rel"), + }, + }, + } + t.Run("empty inner txs should error", func(t *testing.T) { + t.Parallel() + + economicsData, _ := economics.NewEconomicsData(args) + + txCopy := *tx + txCopy.InnerTransactions = []*transaction.Transaction{} + relayerFee, totalFee, err := economicsData.ComputeRelayedTxFees(&txCopy) + require.Equal(t, process.ErrEmptyInnerTransactions, err) + require.Equal(t, big.NewInt(0), relayerFee) + require.Equal(t, big.NewInt(0), totalFee) + }) + t.Run("should work unguarded", func(t *testing.T) { + t.Parallel() + + economicsData, _ := economics.NewEconomicsData(args) + + _ = economicsData.SetTxTypeHandler(&testscommon.TxTypeHandlerMock{ + ComputeTransactionTypeCalled: func(tx data.TransactionHandler) (process.TransactionType, process.TransactionType) { + return process.MoveBalance, process.MoveBalance + }, + }) + + relayerFee, totalFee, err := economicsData.ComputeRelayedTxFees(tx) + require.NoError(t, err) + expectedRelayerFee := big.NewInt(int64(2 * uint64(minGasLimit) * tx.GetGasPrice())) // 2 move balance + require.Equal(t, expectedRelayerFee, relayerFee) + require.Equal(t, big.NewInt(int64(tx.GetGasLimit()*tx.GetGasPrice())), totalFee) + }) + t.Run("should work guarded", func(t *testing.T) { + t.Parallel() + + argsLocal := createArgsForEconomicsData(1) + argsLocal.TxVersionChecker = &testscommon.TxVersionCheckerStub{ + IsGuardedTransactionCalled: func(tx *transaction.Transaction) bool { + return len(tx.InnerTransactions) > 0 // only the relayed tx is guarded + }, + } + economicsData, _ := economics.NewEconomicsData(argsLocal) + + extraGasLimitGuardedTx, _ := strconv.Atoi(argsLocal.Economics.FeeSettings.GasLimitSettings[0].ExtraGasLimitGuardedTx) + + txCopy := *tx + txCopy.GasLimit += uint64(extraGasLimitGuardedTx) + relayerFee, totalFee, err := economicsData.ComputeRelayedTxFees(&txCopy) + require.NoError(t, err) + expectedRelayerFee := big.NewInt(int64(2*uint64(minGasLimit)*txCopy.GetGasPrice() + uint64(extraGasLimitGuardedTx)*txCopy.GetGasPrice())) // 2 move balance + require.Equal(t, expectedRelayerFee, relayerFee) + require.Equal(t, big.NewInt(int64(txCopy.GetGasLimit()*txCopy.GetGasPrice())), totalFee) + }) +} + +func TestEconomicsData_SetTxTypeHandler(t *testing.T) { + t.Parallel() + + args := createArgsForEconomicsData(1) + economicsData, _ := economics.NewEconomicsData(args) + assert.NotNil(t, economicsData) + + err := economicsData.SetTxTypeHandler(nil) + require.Equal(t, process.ErrNilTxTypeHandler, err) + + err = economicsData.SetTxTypeHandler(&testscommon.TxTypeHandlerMock{}) + require.NoError(t, err) +} diff --git a/process/errors.go b/process/errors.go index 83e8095dcb3..a4e426691bd 100644 --- a/process/errors.go +++ b/process/errors.go @@ -1229,3 +1229,48 @@ 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") + +// ErrRelayedV3GasPriceMismatch signals that relayed v3 gas price is not equal with inner tx +var ErrRelayedV3GasPriceMismatch = errors.New("relayed tx v3 gas price mismatch") + +// ErrRelayedTxV3SenderDoesNotMatchReceiver signals that the sender of relayed tx v3 does not match the receiver +var ErrRelayedTxV3SenderDoesNotMatchReceiver = errors.New("relayed tx v3 sender does not match receiver") + +// ErrRelayedTxV3Disabled signals that the v3 version of relayed tx is disabled +var ErrRelayedTxV3Disabled = errors.New("relayed tx v3 is disabled") + +// ErrRelayedTxV3ZeroVal signals that the v3 version of relayed tx should be created with 0 as value +var ErrRelayedTxV3ZeroVal = errors.New("relayed tx v3 value should be 0") + +// ErrRelayedTxV3RelayerMismatch signals that the relayer address of the inner tx does not match the real relayer +var ErrRelayedTxV3RelayerMismatch = errors.New("relayed tx v3 relayer mismatch") + +// ErrRelayedTxV3GasLimitMismatch signals that relayed tx v3 gas limit is higher than user tx gas limit +var ErrRelayedTxV3GasLimitMismatch = errors.New("relayed tx v3 gas limit mismatch") + +// ErrNilRelayedTxV3Processor signals that a nil relayed tx v3 processor has been provided +var ErrNilRelayedTxV3Processor = errors.New("nil relayed tx v3 processor") + +// ErrRelayedTxV3SenderShardMismatch signals that the sender from inner transaction is from a different shard than relayer +var ErrRelayedTxV3SenderShardMismatch = errors.New("sender shard mismatch") + +// ErrNilRelayerAccount signals that a nil relayer accouont has been provided +var ErrNilRelayerAccount = errors.New("nil relayer account") + +// ErrRelayedTxV3TooManyInnerTransactions signals that too many inner transactions were provided +var ErrRelayedTxV3TooManyInnerTransactions = errors.New("too many inner transactions") + +// ErrConsumedFeesMismatch signals that the fees consumed from relayer do not match the inner transactions fees +var ErrConsumedFeesMismatch = errors.New("consumed fees mismatch") + +// ErrRelayedTxV3InvalidDataField signals that the data field is invalid +var ErrRelayedTxV3InvalidDataField = errors.New("invalid data field") + +// ErrMultipleRelayedTxTypesIsNotAllowed signals that multiple types of relayed tx is not allowed +var ErrMultipleRelayedTxTypesIsNotAllowed = errors.New("multiple relayed tx types is not allowed") + +// ErrNilFailedTxLogsAccumulator signals that a nil failed transaction logs accumulator has been provided +var ErrNilFailedTxLogsAccumulator = errors.New("nil failed transaction logs accumulator") + +// ErrEmptyInnerTransactions signals that the inner transactions slice is empty +var ErrEmptyInnerTransactions = errors.New("empty inner transactions") diff --git a/process/factory/interceptorscontainer/args.go b/process/factory/interceptorscontainer/args.go index 294e66290b3..0d224b031ad 100644 --- a/process/factory/interceptorscontainer/args.go +++ b/process/factory/interceptorscontainer/args.go @@ -43,4 +43,5 @@ type CommonInterceptorsContainerFactoryArgs struct { FullArchivePeerShardMapper process.PeerShardMapper HardforkTrigger heartbeat.HardforkTrigger NodeOperationMode common.NodeOperation + RelayedTxV3Processor process.RelayedTxV3Processor } diff --git a/process/factory/interceptorscontainer/metaInterceptorsContainerFactory.go b/process/factory/interceptorscontainer/metaInterceptorsContainerFactory.go index 38d3e460bce..31a4344b771 100644 --- a/process/factory/interceptorscontainer/metaInterceptorsContainerFactory.go +++ b/process/factory/interceptorscontainer/metaInterceptorsContainerFactory.go @@ -99,6 +99,7 @@ func NewMetaInterceptorsContainerFactory( SignaturesHandler: args.SignaturesHandler, HeartbeatExpiryTimespanInSec: args.HeartbeatExpiryTimespanInSec, PeerID: args.MainMessenger.ID(), + RelayedTxV3Processor: args.RelayedTxV3Processor, } base := &baseInterceptorsContainerFactory{ diff --git a/process/factory/interceptorscontainer/metaInterceptorsContainerFactory_test.go b/process/factory/interceptorscontainer/metaInterceptorsContainerFactory_test.go index c8ed20b5fad..b9124001264 100644 --- a/process/factory/interceptorscontainer/metaInterceptorsContainerFactory_test.go +++ b/process/factory/interceptorscontainer/metaInterceptorsContainerFactory_test.go @@ -18,6 +18,7 @@ import ( dataRetrieverMock "github.com/multiversx/mx-chain-go/testscommon/dataRetriever" "github.com/multiversx/mx-chain-go/testscommon/economicsmocks" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" storageStubs "github.com/multiversx/mx-chain-go/testscommon/storage" @@ -697,7 +698,7 @@ func getArgumentsMeta( WhiteListHandler: &testscommon.WhiteListHandlerStub{}, WhiteListerVerifiedTxs: &testscommon.WhiteListHandlerStub{}, AntifloodHandler: &mock.P2PAntifloodHandlerStub{}, - ArgumentsParser: &mock.ArgumentParserMock{}, + ArgumentsParser: &testscommon.ArgumentParserMock{}, PreferredPeersHolder: &p2pmocks.PeersHolderStub{}, RequestHandler: &testscommon.RequestHandlerStub{}, PeerSignatureHandler: &mock.PeerSignatureHandlerStub{}, @@ -707,5 +708,6 @@ func getArgumentsMeta( FullArchivePeerShardMapper: &p2pmocks.NetworkShardingCollectorStub{}, HardforkTrigger: &testscommon.HardforkTriggerStub{}, NodeOperationMode: common.NormalOperation, + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, } } diff --git a/process/factory/interceptorscontainer/shardInterceptorsContainerFactory.go b/process/factory/interceptorscontainer/shardInterceptorsContainerFactory.go index beef288c54c..26224fbc152 100644 --- a/process/factory/interceptorscontainer/shardInterceptorsContainerFactory.go +++ b/process/factory/interceptorscontainer/shardInterceptorsContainerFactory.go @@ -98,6 +98,7 @@ func NewShardInterceptorsContainerFactory( SignaturesHandler: args.SignaturesHandler, HeartbeatExpiryTimespanInSec: args.HeartbeatExpiryTimespanInSec, PeerID: args.MainMessenger.ID(), + RelayedTxV3Processor: args.RelayedTxV3Processor, } base := &baseInterceptorsContainerFactory{ diff --git a/process/factory/interceptorscontainer/shardInterceptorsContainerFactory_test.go b/process/factory/interceptorscontainer/shardInterceptorsContainerFactory_test.go index 24472c24f32..f802562ae35 100644 --- a/process/factory/interceptorscontainer/shardInterceptorsContainerFactory_test.go +++ b/process/factory/interceptorscontainer/shardInterceptorsContainerFactory_test.go @@ -22,6 +22,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/epochNotifier" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" storageStubs "github.com/multiversx/mx-chain-go/testscommon/storage" @@ -723,7 +724,7 @@ func getArgumentsShard( AntifloodHandler: &mock.P2PAntifloodHandlerStub{}, WhiteListHandler: &testscommon.WhiteListHandlerStub{}, WhiteListerVerifiedTxs: &testscommon.WhiteListHandlerStub{}, - ArgumentsParser: &mock.ArgumentParserMock{}, + ArgumentsParser: &testscommon.ArgumentParserMock{}, PreferredPeersHolder: &p2pmocks.PeersHolderStub{}, RequestHandler: &testscommon.RequestHandlerStub{}, PeerSignatureHandler: &mock.PeerSignatureHandlerStub{}, @@ -732,5 +733,6 @@ func getArgumentsShard( MainPeerShardMapper: &p2pmocks.NetworkShardingCollectorStub{}, FullArchivePeerShardMapper: &p2pmocks.NetworkShardingCollectorStub{}, HardforkTrigger: &testscommon.HardforkTriggerStub{}, + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, } } diff --git a/process/interceptors/factory/argInterceptedDataFactory.go b/process/interceptors/factory/argInterceptedDataFactory.go index 37701a92f7a..36ab4968375 100644 --- a/process/interceptors/factory/argInterceptedDataFactory.go +++ b/process/interceptors/factory/argInterceptedDataFactory.go @@ -57,4 +57,5 @@ type ArgInterceptedDataFactory struct { SignaturesHandler process.SignaturesHandler HeartbeatExpiryTimespanInSec int64 PeerID core.PeerID + RelayedTxV3Processor process.RelayedTxV3Processor } diff --git a/process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go b/process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go index 0912de698c1..d2ecc63e59d 100644 --- a/process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go +++ b/process/interceptors/factory/interceptedMetaHeaderDataFactory_test.go @@ -20,6 +20,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/epochNotifier" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" + testProcessMocks "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" "github.com/stretchr/testify/assert" ) @@ -101,11 +102,12 @@ func createMockArgument( ValidityAttester: &mock.ValidityAttesterStub{}, HeaderIntegrityVerifier: &mock.HeaderIntegrityVerifierStub{}, EpochStartTrigger: &mock.EpochStartTriggerStub{}, - ArgsParser: &mock.ArgumentParserMock{}, + ArgsParser: &testscommon.ArgumentParserMock{}, PeerSignatureHandler: &processMocks.PeerSignatureHandlerStub{}, SignaturesHandler: &processMocks.SignaturesHandlerStub{}, HeartbeatExpiryTimespanInSec: 30, PeerID: "pid", + RelayedTxV3Processor: &testProcessMocks.RelayedTxV3ProcessorMock{}, } } diff --git a/process/interceptors/factory/interceptedTxDataFactory.go b/process/interceptors/factory/interceptedTxDataFactory.go index 563997c5066..e2dc86e599c 100644 --- a/process/interceptors/factory/interceptedTxDataFactory.go +++ b/process/interceptors/factory/interceptedTxDataFactory.go @@ -31,6 +31,7 @@ type interceptedTxDataFactory struct { txSignHasher hashing.Hasher txVersionChecker process.TxVersionCheckerHandler enableEpochsHandler common.EnableEpochsHandler + relayedTxV3Processor process.RelayedTxV3Processor } // NewInterceptedTxDataFactory creates an instance of interceptedTxDataFactory @@ -107,6 +108,7 @@ func NewInterceptedTxDataFactory(argument *ArgInterceptedDataFactory) (*intercep txSignHasher: argument.CoreComponents.TxSignHasher(), txVersionChecker: argument.CoreComponents.TxVersionChecker(), enableEpochsHandler: argument.CoreComponents.EnableEpochsHandler(), + relayedTxV3Processor: argument.RelayedTxV3Processor, } return itdf, nil @@ -130,6 +132,8 @@ func (itdf *interceptedTxDataFactory) Create(buff []byte) (process.InterceptedDa itdf.enableEpochsHandler.IsFlagEnabled(common.TransactionSignedWithTxHashFlag), itdf.txSignHasher, itdf.txVersionChecker, + itdf.enableEpochsHandler, + itdf.relayedTxV3Processor, ) } diff --git a/process/interface.go b/process/interface.go index 69b1b139e89..8e943d0a44e 100644 --- a/process/interface.go +++ b/process/interface.go @@ -20,6 +20,9 @@ import ( "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" crypto "github.com/multiversx/mx-chain-crypto-go" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-common-go/parsers" + "github.com/multiversx/mx-chain-go/common" cryptoCommon "github.com/multiversx/mx-chain-go/common/crypto" "github.com/multiversx/mx-chain-go/epochStart" @@ -30,8 +33,6 @@ import ( "github.com/multiversx/mx-chain-go/sharding/nodesCoordinator" "github.com/multiversx/mx-chain-go/state" "github.com/multiversx/mx-chain-go/storage" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "github.com/multiversx/mx-chain-vm-common-go/parsers" ) // TransactionProcessor is the main interface for transaction execution engine @@ -170,7 +171,7 @@ type TransactionCoordinator interface { VerifyCreatedBlockTransactions(hdr data.HeaderHandler, body *block.Body) error GetCreatedInShardMiniBlocks() []*block.MiniBlock VerifyCreatedMiniBlocks(hdr data.HeaderHandler, body *block.Body) error - AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler) error + AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler, key []byte) error GetAllIntermediateTxs() map[block.Type]map[string]data.TransactionHandler AddTxsFromMiniBlocks(miniBlocks block.MiniBlockSlice) AddTransactions(txHandlers []data.TransactionHandler, blockType block.Type) @@ -190,7 +191,7 @@ type SmartContractProcessor interface { // IntermediateTransactionHandler handles transactions which are not resolved in only one step type IntermediateTransactionHandler interface { - AddIntermediateTransactions(txs []data.TransactionHandler) error + AddIntermediateTransactions(txs []data.TransactionHandler, key []byte) error GetNumOfCrossInterMbsAndTxs() (int, int) CreateAllInterMiniBlocks() []*block.MiniBlock VerifyInterMiniBlocks(body *block.Body) error @@ -199,7 +200,7 @@ type IntermediateTransactionHandler interface { CreateBlockStarted() GetCreatedInShardMiniBlock() *block.MiniBlock RemoveProcessedResults(key []byte) [][]byte - InitProcessedResults(key []byte) + InitProcessedResults(key []byte, parentKey []byte) IsInterfaceNil() bool } @@ -698,6 +699,7 @@ type feeHandler interface { ComputeGasLimitInEpoch(tx data.TransactionWithFeeHandler, epoch uint32) uint64 ComputeGasUsedAndFeeBasedOnRefundValueInEpoch(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) (uint64, *big.Int) ComputeTxFeeBasedOnGasUsedInEpoch(tx data.TransactionWithFeeHandler, gasUsed uint64, epoch uint32) *big.Int + ComputeRelayedTxFees(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) } // TxGasHandler handles a transaction gas and gas cost @@ -724,6 +726,7 @@ type EconomicsDataHandler interface { rewardsHandler feeHandler SetStatusHandler(statusHandler core.AppStatusHandler) error + SetTxTypeHandler(txTypeHandler TxTypeHandler) error IsInterfaceNil() bool } @@ -1319,7 +1322,7 @@ type TxsSenderHandler interface { // PreProcessorExecutionInfoHandler handles pre processor execution info needed by the transactions preprocessors type PreProcessorExecutionInfoHandler interface { GetNumOfCrossInterMbsAndTxs() (int, int) - InitProcessedTxsResults(key []byte) + InitProcessedTxsResults(key []byte, parentKey []byte) RevertProcessedTxsResults(txHashes [][]byte, key []byte) } @@ -1358,3 +1361,17 @@ type SentSignaturesTracker interface { ResetCountersForManagedBlockSigner(signerPk []byte) IsInterfaceNil() bool } + +// RelayedTxV3Processor defines a component able to check and process relayed transactions v3 +type RelayedTxV3Processor interface { + CheckRelayedTx(tx *transaction.Transaction) error + IsInterfaceNil() bool +} + +// FailedTxLogsAccumulator defines a component able to accumulate logs during a relayed tx execution +type FailedTxLogsAccumulator interface { + GetLogs(txHash []byte) (data.TransactionHandler, []*vmcommon.LogEntry, bool) + SaveLogs(txHash []byte, tx data.TransactionHandler, logs []*vmcommon.LogEntry) error + Remove(txHash []byte) + IsInterfaceNil() bool +} diff --git a/process/mock/argumentsParserMock.go b/process/mock/argumentsParserMock.go deleted file mode 100644 index 02ce8f408ae..00000000000 --- a/process/mock/argumentsParserMock.go +++ /dev/null @@ -1,60 +0,0 @@ -package mock - -import ( - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "github.com/multiversx/mx-chain-vm-common-go/parsers" -) - -// ArgumentParserMock - -type ArgumentParserMock struct { - ParseCallDataCalled func(data string) (string, [][]byte, error) - ParseArgumentsCalled func(data string) ([][]byte, error) - ParseDeployDataCalled func(data string) (*parsers.DeployArgs, error) - CreateDataFromStorageUpdateCalled func(storageUpdates []*vmcommon.StorageUpdate) string - GetStorageUpdatesCalled func(data string) ([]*vmcommon.StorageUpdate, error) -} - -// ParseCallData - -func (ap *ArgumentParserMock) ParseCallData(data string) (string, [][]byte, error) { - if ap.ParseCallDataCalled == nil { - return "", nil, nil - } - return ap.ParseCallDataCalled(data) -} - -// ParseArguments - -func (ap *ArgumentParserMock) ParseArguments(data string) ([][]byte, error) { - if ap.ParseArgumentsCalled == nil { - return [][]byte{}, nil - } - return ap.ParseArgumentsCalled(data) -} - -// ParseDeployData - -func (ap *ArgumentParserMock) ParseDeployData(data string) (*parsers.DeployArgs, error) { - if ap.ParseDeployDataCalled == nil { - return nil, nil - } - return ap.ParseDeployDataCalled(data) -} - -// CreateDataFromStorageUpdate - -func (ap *ArgumentParserMock) CreateDataFromStorageUpdate(storageUpdates []*vmcommon.StorageUpdate) string { - if ap.CreateDataFromStorageUpdateCalled == nil { - return "" - } - return ap.CreateDataFromStorageUpdateCalled(storageUpdates) -} - -// GetStorageUpdates - -func (ap *ArgumentParserMock) GetStorageUpdates(data string) ([]*vmcommon.StorageUpdate, error) { - if ap.GetStorageUpdatesCalled == nil { - return nil, nil - } - return ap.GetStorageUpdatesCalled(data) -} - -// IsInterfaceNil returns true if there is no value under the interface -func (ap *ArgumentParserMock) IsInterfaceNil() bool { - return ap == nil -} diff --git a/process/mock/intermProcessorStub.go b/process/mock/intermProcessorStub.go index 3909bfd83fc..dde08776bd4 100644 --- a/process/mock/intermProcessorStub.go +++ b/process/mock/intermProcessorStub.go @@ -7,7 +7,7 @@ import ( // IntermediateTransactionHandlerStub - type IntermediateTransactionHandlerStub struct { - AddIntermediateTransactionsCalled func(txs []data.TransactionHandler) error + AddIntermediateTransactionsCalled func(txs []data.TransactionHandler, key []byte) error GetNumOfCrossInterMbsAndTxsCalled func() (int, int) CreateAllInterMiniBlocksCalled func() []*block.MiniBlock VerifyInterMiniBlocksCalled func(body *block.Body) error @@ -16,7 +16,7 @@ type IntermediateTransactionHandlerStub struct { CreateMarshalledDataCalled func(txHashes [][]byte) ([][]byte, error) GetAllCurrentFinishedTxsCalled func() map[string]data.TransactionHandler RemoveProcessedResultsCalled func(key []byte) [][]byte - InitProcessedResultsCalled func(key []byte) + InitProcessedResultsCalled func(key []byte, parentKey []byte) intermediateTransactions []data.TransactionHandler } @@ -29,9 +29,9 @@ func (ith *IntermediateTransactionHandlerStub) RemoveProcessedResults(key []byte } // InitProcessedResults - -func (ith *IntermediateTransactionHandlerStub) InitProcessedResults(key []byte) { +func (ith *IntermediateTransactionHandlerStub) InitProcessedResults(key []byte, parentKey []byte) { if ith.InitProcessedResultsCalled != nil { - ith.InitProcessedResultsCalled(key) + ith.InitProcessedResultsCalled(key, parentKey) } } @@ -44,12 +44,12 @@ func (ith *IntermediateTransactionHandlerStub) CreateMarshalledData(txHashes [][ } // AddIntermediateTransactions - -func (ith *IntermediateTransactionHandlerStub) AddIntermediateTransactions(txs []data.TransactionHandler) error { +func (ith *IntermediateTransactionHandlerStub) AddIntermediateTransactions(txs []data.TransactionHandler, key []byte) error { if ith.AddIntermediateTransactionsCalled == nil { ith.intermediateTransactions = append(ith.intermediateTransactions, txs...) return nil } - return ith.AddIntermediateTransactionsCalled(txs) + return ith.AddIntermediateTransactionsCalled(txs, key) } // GetIntermediateTransactions - diff --git a/process/mock/intermediateTransactionHandlerMock.go b/process/mock/intermediateTransactionHandlerMock.go index a7d0a5b3be6..7bd71c3475c 100644 --- a/process/mock/intermediateTransactionHandlerMock.go +++ b/process/mock/intermediateTransactionHandlerMock.go @@ -7,7 +7,7 @@ import ( // IntermediateTransactionHandlerMock - type IntermediateTransactionHandlerMock struct { - AddIntermediateTransactionsCalled func(txs []data.TransactionHandler) error + AddIntermediateTransactionsCalled func(txs []data.TransactionHandler, key []byte) error GetNumOfCrossInterMbsAndTxsCalled func() (int, int) CreateAllInterMiniBlocksCalled func() []*block.MiniBlock VerifyInterMiniBlocksCalled func(body *block.Body) error @@ -16,7 +16,7 @@ type IntermediateTransactionHandlerMock struct { CreateMarshalledDataCalled func(txHashes [][]byte) ([][]byte, error) GetAllCurrentFinishedTxsCalled func() map[string]data.TransactionHandler RemoveProcessedResultsCalled func(key []byte) [][]byte - InitProcessedResultsCalled func(key []byte) + InitProcessedResultsCalled func(key []byte, parentKey []byte) GetCreatedInShardMiniBlockCalled func() *block.MiniBlock intermediateTransactions []data.TransactionHandler } @@ -30,9 +30,9 @@ func (ith *IntermediateTransactionHandlerMock) RemoveProcessedResults(key []byte } // InitProcessedResults - -func (ith *IntermediateTransactionHandlerMock) InitProcessedResults(key []byte) { +func (ith *IntermediateTransactionHandlerMock) InitProcessedResults(key []byte, parentKey []byte) { if ith.InitProcessedResultsCalled != nil { - ith.InitProcessedResultsCalled(key) + ith.InitProcessedResultsCalled(key, parentKey) } } @@ -45,12 +45,12 @@ func (ith *IntermediateTransactionHandlerMock) CreateMarshalledData(txHashes [][ } // AddIntermediateTransactions - -func (ith *IntermediateTransactionHandlerMock) AddIntermediateTransactions(txs []data.TransactionHandler) error { +func (ith *IntermediateTransactionHandlerMock) AddIntermediateTransactions(txs []data.TransactionHandler, key []byte) error { if ith.AddIntermediateTransactionsCalled == nil { ith.intermediateTransactions = append(ith.intermediateTransactions, txs...) return nil } - return ith.AddIntermediateTransactionsCalled(txs) + return ith.AddIntermediateTransactionsCalled(txs, key) } // GetIntermediateTransactions - diff --git a/process/scToProtocol/stakingToPeer.go b/process/scToProtocol/stakingToPeer.go index e9b166b52ea..363a7975a7a 100644 --- a/process/scToProtocol/stakingToPeer.go +++ b/process/scToProtocol/stakingToPeer.go @@ -11,14 +11,15 @@ import ( "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + "github.com/multiversx/mx-chain-logger-go" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/dataRetriever" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/state" "github.com/multiversx/mx-chain-go/vm" "github.com/multiversx/mx-chain-go/vm/systemSmartContracts" - "github.com/multiversx/mx-chain-logger-go" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" ) var _ process.SmartContractToProtocolHandler = (*stakingToPeer)(nil) @@ -109,6 +110,7 @@ func checkIfNil(args ArgStakingToPeer) error { return core.CheckHandlerCompatibility(args.EnableEpochsHandler, []core.EnableEpochFlag{ common.StakeFlag, common.ValidatorToDelegationFlag, + common.UnJailCleanupFlag, }) } @@ -341,6 +343,9 @@ func (stp *stakingToPeer) updatePeerState( if account.GetTempRating() < stp.unJailRating { log.Debug("node is unJailed, setting temp rating to start rating", "blsKey", blsPubKey) account.SetTempRating(stp.unJailRating) + if stp.enableEpochsHandler.IsFlagEnabled(common.UnJailCleanupFlag) { + account.SetConsecutiveProposerMisses(0) + } } isNewValidator := !isValidator && stakingData.Staked diff --git a/process/scToProtocol/stakingToPeer_test.go b/process/scToProtocol/stakingToPeer_test.go index f53495e92c9..a6f0d80bc1b 100644 --- a/process/scToProtocol/stakingToPeer_test.go +++ b/process/scToProtocol/stakingToPeer_test.go @@ -40,7 +40,7 @@ func createMockArgumentsNewStakingToPeer() ArgStakingToPeer { Marshalizer: &mock.MarshalizerStub{}, PeerState: &stateMock.AccountsStub{}, BaseState: &stateMock.AccountsStub{}, - ArgParser: &mock.ArgumentParserMock{}, + ArgParser: &testscommon.ArgumentParserMock{}, CurrTxs: &mock.TxForCurrentBlockStub{}, RatingsData: &mock.RatingsInfoMock{}, EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.StakeFlag, common.ValidatorToDelegationFlag), @@ -227,7 +227,7 @@ func TestStakingToPeer_UpdateProtocolCannotGetStorageUpdatesShouldErr(t *testing }, nil } - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} argParser.GetStorageUpdatesCalled = func(data string) (updates []*vmcommon.StorageUpdate, e error) { return nil, testError } @@ -252,7 +252,7 @@ func TestStakingToPeer_UpdateProtocolRemoveAccountShouldReturnNil(t *testing.T) }, nil } - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} argParser.GetStorageUpdatesCalled = func(data string) (updates []*vmcommon.StorageUpdate, e error) { return []*vmcommon.StorageUpdate{ {Offset: []byte("aabbcc"), Data: []byte("data1")}, @@ -311,7 +311,7 @@ func TestStakingToPeer_UpdateProtocolCannotSetRewardAddressShouldErr(t *testing. offset = append(offset, 99) } - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} argParser.GetStorageUpdatesCalled = func(data string) (updates []*vmcommon.StorageUpdate, e error) { return []*vmcommon.StorageUpdate{ {Offset: offset, Data: []byte("data1")}, @@ -368,7 +368,7 @@ func TestStakingToPeer_UpdateProtocolEmptyDataShouldNotAddToTrie(t *testing.T) { offset = append(offset, 99) } - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} argParser.GetStorageUpdatesCalled = func(data string) (updates []*vmcommon.StorageUpdate, e error) { return []*vmcommon.StorageUpdate{ {Offset: offset, Data: []byte("data1")}, @@ -429,7 +429,7 @@ func TestStakingToPeer_UpdateProtocolCannotSaveAccountShouldErr(t *testing.T) { offset = append(offset, 99) } - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} argParser.GetStorageUpdatesCalled = func(data string) (updates []*vmcommon.StorageUpdate, e error) { return []*vmcommon.StorageUpdate{ {Offset: offset, Data: []byte("data1")}, @@ -492,7 +492,7 @@ func TestStakingToPeer_UpdateProtocolCannotSaveAccountNonceShouldErr(t *testing. offset = append(offset, 99) } - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} argParser.GetStorageUpdatesCalled = func(data string) (updates []*vmcommon.StorageUpdate, e error) { return []*vmcommon.StorageUpdate{ {Offset: offset, Data: []byte("data1")}, @@ -554,7 +554,7 @@ func TestStakingToPeer_UpdateProtocol(t *testing.T) { offset = append(offset, 99) } - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} argParser.GetStorageUpdatesCalled = func(data string) (updates []*vmcommon.StorageUpdate, e error) { return []*vmcommon.StorageUpdate{ {Offset: offset, Data: []byte("data1")}, @@ -617,7 +617,7 @@ func TestStakingToPeer_UpdateProtocolCannotSaveUnStakedNonceShouldErr(t *testing offset = append(offset, 99) } - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} argParser.GetStorageUpdatesCalled = func(data string) (updates []*vmcommon.StorageUpdate, e error) { return []*vmcommon.StorageUpdate{ {Offset: offset, Data: []byte("data1")}, diff --git a/process/smartContract/process.go b/process/smartContract/process.go index 7bd0c9a2f52..25031dcbf4a 100644 --- a/process/smartContract/process.go +++ b/process/smartContract/process.go @@ -18,6 +18,10 @@ import ( vmData "github.com/multiversx/mx-chain-core-go/data/vm" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + logger "github.com/multiversx/mx-chain-logger-go" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-common-go/parsers" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/smartContract/scrCommon" @@ -25,9 +29,6 @@ import ( "github.com/multiversx/mx-chain-go/state" "github.com/multiversx/mx-chain-go/storage" "github.com/multiversx/mx-chain-go/vm" - logger "github.com/multiversx/mx-chain-logger-go" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "github.com/multiversx/mx-chain-vm-common-go/parsers" ) var _ process.SmartContractResultProcessor = (*scProcessor)(nil) @@ -535,7 +536,7 @@ func (sc *scProcessor) finishSCExecution( return 0, err } - err = sc.scrForwarder.AddIntermediateTransactions(finalResults) + err = sc.scrForwarder.AddIntermediateTransactions(finalResults, txHash) if err != nil { log.Error("AddIntermediateTransactions error", "error", err.Error()) return 0, err @@ -868,7 +869,7 @@ func (sc *scProcessor) resolveFailedTransaction( } if _, ok := tx.(*transaction.Transaction); ok { - err = sc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}) + err = sc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}, txHash) if err != nil { return err } @@ -1436,7 +1437,7 @@ func (sc *scProcessor) processIfErrorWithAddedLogs( userErrorLog := createNewLogFromSCRIfError(scrIfError) if !sc.enableEpochsHandler.IsFlagEnabled(common.CleanUpInformativeSCRsFlag) || !sc.isInformativeTxHandler(scrIfError) { - err = sc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrIfError}) + err = sc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrIfError}, txHash) if err != nil { return err } @@ -1575,7 +1576,7 @@ func (sc *scProcessor) processForRelayerWhenError( } if !sc.enableEpochsHandler.IsFlagEnabled(common.CleanUpInformativeSCRsFlag) || scrForRelayer.Value.Cmp(zero) > 0 { - err = sc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrForRelayer}) + err = sc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrForRelayer}, txHash) if err != nil { return nil, err } @@ -1813,7 +1814,7 @@ func (sc *scProcessor) doDeploySmartContract( return 0, err } - err = sc.scrForwarder.AddIntermediateTransactions(finalResults) + err = sc.scrForwarder.AddIntermediateTransactions(finalResults, txHash) if err != nil { log.Debug("AddIntermediate Transaction error", "error", err.Error()) return 0, err diff --git a/process/smartContract/processProxy/processProxy.go b/process/smartContract/processProxy/processProxy.go index c64db4791a4..a36a5fbd4f4 100644 --- a/process/smartContract/processProxy/processProxy.go +++ b/process/smartContract/processProxy/processProxy.go @@ -50,29 +50,30 @@ func NewSmartContractProcessorProxy(args scrCommon.ArgsNewSmartContractProcessor proxy := &scProcessorProxy{ args: scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: args.VmContainer, - ArgsParser: args.ArgsParser, - Hasher: args.Hasher, - Marshalizer: args.Marshalizer, - AccountsDB: args.AccountsDB, - BlockChainHook: args.BlockChainHook, - BuiltInFunctions: args.BuiltInFunctions, - PubkeyConv: args.PubkeyConv, - ShardCoordinator: args.ShardCoordinator, - ScrForwarder: args.ScrForwarder, - TxFeeHandler: args.TxFeeHandler, - EconomicsFee: args.EconomicsFee, - TxTypeHandler: args.TxTypeHandler, - GasHandler: args.GasHandler, - GasSchedule: args.GasSchedule, - TxLogsProcessor: args.TxLogsProcessor, - BadTxForwarder: args.BadTxForwarder, - EnableRoundsHandler: args.EnableRoundsHandler, - EnableEpochsHandler: args.EnableEpochsHandler, - EnableEpochs: args.EnableEpochs, - VMOutputCacher: args.VMOutputCacher, - WasmVMChangeLocker: args.WasmVMChangeLocker, - IsGenesisProcessing: args.IsGenesisProcessing, + VmContainer: args.VmContainer, + ArgsParser: args.ArgsParser, + Hasher: args.Hasher, + Marshalizer: args.Marshalizer, + AccountsDB: args.AccountsDB, + BlockChainHook: args.BlockChainHook, + BuiltInFunctions: args.BuiltInFunctions, + PubkeyConv: args.PubkeyConv, + ShardCoordinator: args.ShardCoordinator, + ScrForwarder: args.ScrForwarder, + TxFeeHandler: args.TxFeeHandler, + EconomicsFee: args.EconomicsFee, + TxTypeHandler: args.TxTypeHandler, + GasHandler: args.GasHandler, + GasSchedule: args.GasSchedule, + TxLogsProcessor: args.TxLogsProcessor, + BadTxForwarder: args.BadTxForwarder, + EnableRoundsHandler: args.EnableRoundsHandler, + EnableEpochsHandler: args.EnableEpochsHandler, + EnableEpochs: args.EnableEpochs, + VMOutputCacher: args.VMOutputCacher, + WasmVMChangeLocker: args.WasmVMChangeLocker, + IsGenesisProcessing: args.IsGenesisProcessing, + FailedTxLogsAccumulator: args.FailedTxLogsAccumulator, }, } if check.IfNil(epochNotifier) { diff --git a/process/smartContract/processProxy/processProxy_test.go b/process/smartContract/processProxy/processProxy_test.go index 0b5695386a8..98a56fd0f30 100644 --- a/process/smartContract/processProxy/processProxy_test.go +++ b/process/smartContract/processProxy/processProxy_test.go @@ -23,6 +23,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" epochNotifierMock "github.com/multiversx/mx-chain-go/testscommon/epochNotifier" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" vmcommon "github.com/multiversx/mx-chain-vm-common-go" "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" @@ -39,7 +40,7 @@ func createMockSmartContractProcessorArguments() scrCommon.ArgsNewSmartContractP return scrCommon.ArgsNewSmartContractProcessor{ VmContainer: &mock.VMContainerMock{}, - ArgsParser: &mock.ArgumentParserMock{}, + ArgsParser: &testscommon.ArgumentParserMock{}, Hasher: &hashingMocks.HasherMock{}, Marshalizer: &mock.MarshalizerMock{}, AccountsDB: &stateMock.AccountsStub{ @@ -76,9 +77,10 @@ func createMockSmartContractProcessorArguments() scrCommon.ArgsNewSmartContractP return flag == common.SCDeployFlag }, }, - EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, - WasmVMChangeLocker: &sync.RWMutex{}, - VMOutputCacher: txcache.NewDisabledCache(), + EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, + WasmVMChangeLocker: &sync.RWMutex{}, + VMOutputCacher: txcache.NewDisabledCache(), + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } } diff --git a/process/smartContract/processProxy/testProcessProxy.go b/process/smartContract/processProxy/testProcessProxy.go index 5d5d96ee0d2..65e5d525565 100644 --- a/process/smartContract/processProxy/testProcessProxy.go +++ b/process/smartContract/processProxy/testProcessProxy.go @@ -28,29 +28,30 @@ type scProcessorTestProxy struct { func NewTestSmartContractProcessorProxy(args scrCommon.ArgsNewSmartContractProcessor, epochNotifier vmcommon.EpochNotifier) (*scProcessorTestProxy, error) { scProcessorTestProxy := &scProcessorTestProxy{ args: scrCommon.ArgsNewSmartContractProcessor{ - VmContainer: args.VmContainer, - ArgsParser: args.ArgsParser, - Hasher: args.Hasher, - Marshalizer: args.Marshalizer, - AccountsDB: args.AccountsDB, - BlockChainHook: args.BlockChainHook, - BuiltInFunctions: args.BuiltInFunctions, - PubkeyConv: args.PubkeyConv, - ShardCoordinator: args.ShardCoordinator, - ScrForwarder: args.ScrForwarder, - TxFeeHandler: args.TxFeeHandler, - EconomicsFee: args.EconomicsFee, - TxTypeHandler: args.TxTypeHandler, - GasHandler: args.GasHandler, - GasSchedule: args.GasSchedule, - TxLogsProcessor: args.TxLogsProcessor, - BadTxForwarder: args.BadTxForwarder, - EnableRoundsHandler: args.EnableRoundsHandler, - EnableEpochsHandler: args.EnableEpochsHandler, - EnableEpochs: args.EnableEpochs, - VMOutputCacher: args.VMOutputCacher, - WasmVMChangeLocker: args.WasmVMChangeLocker, - IsGenesisProcessing: args.IsGenesisProcessing, + VmContainer: args.VmContainer, + ArgsParser: args.ArgsParser, + Hasher: args.Hasher, + Marshalizer: args.Marshalizer, + AccountsDB: args.AccountsDB, + BlockChainHook: args.BlockChainHook, + BuiltInFunctions: args.BuiltInFunctions, + PubkeyConv: args.PubkeyConv, + ShardCoordinator: args.ShardCoordinator, + ScrForwarder: args.ScrForwarder, + TxFeeHandler: args.TxFeeHandler, + EconomicsFee: args.EconomicsFee, + TxTypeHandler: args.TxTypeHandler, + GasHandler: args.GasHandler, + GasSchedule: args.GasSchedule, + TxLogsProcessor: args.TxLogsProcessor, + BadTxForwarder: args.BadTxForwarder, + EnableRoundsHandler: args.EnableRoundsHandler, + EnableEpochsHandler: args.EnableEpochsHandler, + EnableEpochs: args.EnableEpochs, + VMOutputCacher: args.VMOutputCacher, + WasmVMChangeLocker: args.WasmVMChangeLocker, + IsGenesisProcessing: args.IsGenesisProcessing, + FailedTxLogsAccumulator: args.FailedTxLogsAccumulator, }, } diff --git a/process/smartContract/process_test.go b/process/smartContract/process_test.go index c53c7ef83c9..29c1e082be3 100644 --- a/process/smartContract/process_test.go +++ b/process/smartContract/process_test.go @@ -13,6 +13,13 @@ import ( "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/transaction" vmData "github.com/multiversx/mx-chain-core-go/data/vm" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" + "github.com/multiversx/mx-chain-vm-common-go/parsers" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/common/enablers" "github.com/multiversx/mx-chain-go/common/forking" @@ -32,15 +39,10 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/epochNotifier" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" "github.com/multiversx/mx-chain-go/testscommon/trie" "github.com/multiversx/mx-chain-go/testscommon/vmcommonMocks" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" - "github.com/multiversx/mx-chain-vm-common-go/parsers" - "github.com/pkg/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const setGuardianCost = 250000 @@ -83,7 +85,7 @@ func createMockSmartContractProcessorArguments() scrCommon.ArgsNewSmartContractP return scrCommon.ArgsNewSmartContractProcessor{ VmContainer: &mock.VMContainerMock{}, - ArgsParser: &mock.ArgumentParserMock{}, + ArgsParser: &testscommon.ArgumentParserMock{}, Hasher: &hashingMocks.HasherMock{}, Marshalizer: &mock.MarshalizerMock{}, AccountsDB: &stateMock.AccountsStub{ @@ -114,11 +116,12 @@ func createMockSmartContractProcessorArguments() scrCommon.ArgsNewSmartContractP GasHandler: &testscommon.GasHandlerStub{ SetGasRefundedCalled: func(gasRefunded uint64, hash []byte) {}, }, - GasSchedule: testscommon.NewGasScheduleNotifierMock(gasSchedule), - EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, - EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.SCDeployFlag), - WasmVMChangeLocker: &sync.RWMutex{}, - VMOutputCacher: txcache.NewDisabledCache(), + GasSchedule: testscommon.NewGasScheduleNotifierMock(gasSchedule), + EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.SCDeployFlag), + WasmVMChangeLocker: &sync.RWMutex{}, + VMOutputCacher: txcache.NewDisabledCache(), + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } } @@ -457,7 +460,7 @@ func TestGasScheduleChangeShouldWork(t *testing.T) { func TestScProcessor_DeploySmartContractBadParse(t *testing.T) { t.Parallel() - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = &mock.VMContainerMock{} arguments.ArgsParser = argParser @@ -631,13 +634,13 @@ func TestScProcessor_BuiltInCallSmartContractSenderFailed(t *testing.T) { scrAdded := false badTxAdded := false arguments.BadTxForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { badTxAdded = true return nil }, } arguments.ScrForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { scrAdded = true return nil }, @@ -887,7 +890,7 @@ func TestScProcessor_DeploySmartContractWrongTx(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -909,7 +912,7 @@ func TestScProcessor_DeploySmartContractNilTx(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -931,7 +934,7 @@ func TestScProcessor_DeploySmartContractNotEmptyDestinationAddress(t *testing.T) t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -954,7 +957,7 @@ func TestScProcessor_DeploySmartContractCalculateHashFails(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -986,7 +989,7 @@ func TestScProcessor_DeploySmartContractEconomicsFeeValidateFails(t *testing.T) expectedError := errors.New("expected error") vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1017,7 +1020,7 @@ func TestScProcessor_DeploySmartContractEconomicsFeeSaveAccountsFails(t *testing expectedError := errors.New("expected error") vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1380,7 +1383,7 @@ func TestScProcessor_DeploySmartContractAddIntermediateTxFails(t *testing.T) { arguments := createMockSmartContractProcessorArguments() arguments.ArgsParser = argParser arguments.ScrForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { return expectedError }, } @@ -1415,7 +1418,7 @@ func TestScProcessor_DeploySmartContractComputeRewardsFails(t *testing.T) { arguments := createMockSmartContractProcessorArguments() arguments.ArgsParser = argParser arguments.ScrForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { return expectedError }, } @@ -1476,7 +1479,7 @@ func TestScProcessor_ExecuteSmartContractTransactionNilTx(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1500,7 +1503,7 @@ func TestScProcessor_ExecuteSmartContractTransactionNilAccount(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1533,7 +1536,7 @@ func TestScProcessor_ExecuteSmartContractTransactionBadParser(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1565,7 +1568,7 @@ func TestScProcessor_ExecuteSmartContractTransactionVMRunError(t *testing.T) { t.Parallel() vmContainer := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vmContainer arguments.ArgsParser = argParser @@ -1702,7 +1705,7 @@ func TestScProcessor_ExecuteSmartContractTransaction(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} accntState := &stateMock.AccountsStub{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm @@ -1735,7 +1738,7 @@ func TestScProcessor_ExecuteSmartContractTransactionSaveLogCalled(t *testing.T) slCalled := false vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} accntState := &stateMock.AccountsStub{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm @@ -1772,7 +1775,7 @@ func TestScProcessor_CreateVMCallInputWrongCode(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1800,7 +1803,7 @@ func TestScProcessor_CreateVMCallInput(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1824,7 +1827,7 @@ func TestScProcessor_CreateVMDeployBadCode(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1851,7 +1854,7 @@ func TestScProcessor_CreateVMDeployInput(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1915,7 +1918,7 @@ func TestScProcessor_CreateVMDeployInputWrongArgument(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1944,7 +1947,7 @@ func TestScProcessor_InitializeVMInputFromTx_ShouldErrNotEnoughGas(t *testing.T) t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1974,7 +1977,7 @@ func TestScProcessor_InitializeVMInputFromTx(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2011,7 +2014,7 @@ func TestScProcessor_processVMOutputNilSndAcc(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2040,7 +2043,7 @@ func TestScProcessor_processVMOutputNilDstAcc(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} accntState := &stateMock.AccountsStub{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm @@ -2084,7 +2087,7 @@ func TestScProcessor_GetAccountFromAddressAccNotFound(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2115,7 +2118,7 @@ func TestScProcessor_GetAccountFromAddrFailedGetExistingAccount(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2147,7 +2150,7 @@ func TestScProcessor_GetAccountFromAddrAccNotInShard(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2180,7 +2183,7 @@ func TestScProcessor_GetAccountFromAddr(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2215,7 +2218,7 @@ func TestScProcessor_DeleteAccountsFailedAtRemove(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2250,7 +2253,7 @@ func TestScProcessor_DeleteAccountsNotInShard(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2289,7 +2292,7 @@ func TestScProcessor_DeleteAccountsInShard(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -4395,7 +4398,7 @@ func TestScProcessor_CheckBuiltinFunctionIsExecutable(t *testing.T) { }) t.Run("", func(t *testing.T) { argsCopy := arguments - argsCopy.ArgsParser = &mock.ArgumentParserMock{ + argsCopy.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return "", nil, expectedErr }, @@ -4406,7 +4409,7 @@ func TestScProcessor_CheckBuiltinFunctionIsExecutable(t *testing.T) { }) t.Run("expected builtin function different than the parsed function name should return error", func(t *testing.T) { argsCopy := arguments - argsCopy.ArgsParser = &mock.ArgumentParserMock{ + argsCopy.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return "differentFunction", nil, nil }, @@ -4417,7 +4420,7 @@ func TestScProcessor_CheckBuiltinFunctionIsExecutable(t *testing.T) { }) t.Run("prepare gas provided with error should error", func(t *testing.T) { argsCopy := arguments - argsCopy.ArgsParser = &mock.ArgumentParserMock{ + argsCopy.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return "SetGuardian", nil, nil }, @@ -4435,7 +4438,7 @@ func TestScProcessor_CheckBuiltinFunctionIsExecutable(t *testing.T) { }) t.Run("builtin function not found should error", func(t *testing.T) { argsCopy := arguments - argsCopy.ArgsParser = &mock.ArgumentParserMock{ + argsCopy.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return "SetGuardian", nil, nil }, @@ -4456,7 +4459,7 @@ func TestScProcessor_CheckBuiltinFunctionIsExecutable(t *testing.T) { }) t.Run("builtin function not supporting executable check should error", func(t *testing.T) { argsCopy := arguments - argsCopy.ArgsParser = &mock.ArgumentParserMock{ + argsCopy.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return "SetGuardian", nil, nil }, @@ -4476,7 +4479,7 @@ func TestScProcessor_CheckBuiltinFunctionIsExecutable(t *testing.T) { }) t.Run("OK", func(t *testing.T) { argsCopy := arguments - argsCopy.ArgsParser = &mock.ArgumentParserMock{ + argsCopy.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return "SetGuardian", nil, nil }, diff --git a/process/smartContract/processorV2/processV2.go b/process/smartContract/processorV2/processV2.go index 126433c6dee..dafa4f9712f 100644 --- a/process/smartContract/processorV2/processV2.go +++ b/process/smartContract/processorV2/processV2.go @@ -18,6 +18,12 @@ import ( vmData "github.com/multiversx/mx-chain-core-go/data/vm" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + logger "github.com/multiversx/mx-chain-logger-go" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-common-go/parsers" + "github.com/multiversx/mx-chain-vm-go/vmhost" + "github.com/multiversx/mx-chain-vm-go/vmhost/contexts" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/smartContract/hooks" @@ -27,11 +33,6 @@ import ( "github.com/multiversx/mx-chain-go/storage" "github.com/multiversx/mx-chain-go/testscommon/txDataBuilder" "github.com/multiversx/mx-chain-go/vm" - logger "github.com/multiversx/mx-chain-logger-go" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "github.com/multiversx/mx-chain-vm-common-go/parsers" - "github.com/multiversx/mx-chain-vm-go/vmhost" - "github.com/multiversx/mx-chain-vm-go/vmhost/contexts" ) var _ process.SmartContractResultProcessor = (*scProcessor)(nil) @@ -80,13 +81,14 @@ type scProcessor struct { txTypeHandler process.TxTypeHandler gasHandler process.GasHandler - builtInGasCosts map[string]uint64 - persistPerByte uint64 - storePerByte uint64 - mutGasLock sync.RWMutex - txLogsProcessor process.TransactionLogProcessor - vmOutputCacher storage.Cacher - isGenesisProcessing bool + builtInGasCosts map[string]uint64 + persistPerByte uint64 + storePerByte uint64 + mutGasLock sync.RWMutex + txLogsProcessor process.TransactionLogProcessor + failedTxLogsAccumulator process.FailedTxLogsAccumulator + vmOutputCacher storage.Cacher + isGenesisProcessing bool executableCheckers map[string]scrCommon.ExecutableChecker mutExecutableCheckers sync.RWMutex @@ -160,6 +162,9 @@ func NewSmartContractProcessorV2(args scrCommon.ArgsNewSmartContractProcessor) ( if check.IfNil(args.TxLogsProcessor) { return nil, process.ErrNilTxLogsProcessor } + if check.IfNil(args.FailedTxLogsAccumulator) { + return nil, process.ErrNilFailedTxLogsAccumulator + } if check.IfNil(args.EnableEpochsHandler) { return nil, process.ErrNilEnableEpochsHandler } @@ -183,30 +188,31 @@ func NewSmartContractProcessorV2(args scrCommon.ArgsNewSmartContractProcessor) ( builtInFuncCost := args.GasSchedule.LatestGasSchedule()[common.BuiltInCost] baseOperationCost := args.GasSchedule.LatestGasSchedule()[common.BaseOperationCost] sc := &scProcessor{ - vmContainer: args.VmContainer, - argsParser: args.ArgsParser, - hasher: args.Hasher, - marshalizer: args.Marshalizer, - accounts: args.AccountsDB, - blockChainHook: args.BlockChainHook, - pubkeyConv: args.PubkeyConv, - shardCoordinator: args.ShardCoordinator, - scrForwarder: args.ScrForwarder, - txFeeHandler: args.TxFeeHandler, - economicsFee: args.EconomicsFee, - txTypeHandler: args.TxTypeHandler, - gasHandler: args.GasHandler, - builtInGasCosts: builtInFuncCost, - txLogsProcessor: args.TxLogsProcessor, - badTxForwarder: args.BadTxForwarder, - builtInFunctions: args.BuiltInFunctions, - isGenesisProcessing: args.IsGenesisProcessing, - arwenChangeLocker: args.WasmVMChangeLocker, - vmOutputCacher: args.VMOutputCacher, - enableEpochsHandler: args.EnableEpochsHandler, - storePerByte: baseOperationCost["StorePerByte"], - persistPerByte: baseOperationCost["PersistPerByte"], - executableCheckers: scrCommon.CreateExecutableCheckersMap(args.BuiltInFunctions), + vmContainer: args.VmContainer, + argsParser: args.ArgsParser, + hasher: args.Hasher, + marshalizer: args.Marshalizer, + accounts: args.AccountsDB, + blockChainHook: args.BlockChainHook, + pubkeyConv: args.PubkeyConv, + shardCoordinator: args.ShardCoordinator, + scrForwarder: args.ScrForwarder, + txFeeHandler: args.TxFeeHandler, + economicsFee: args.EconomicsFee, + txTypeHandler: args.TxTypeHandler, + gasHandler: args.GasHandler, + builtInGasCosts: builtInFuncCost, + txLogsProcessor: args.TxLogsProcessor, + failedTxLogsAccumulator: args.FailedTxLogsAccumulator, + badTxForwarder: args.BadTxForwarder, + builtInFunctions: args.BuiltInFunctions, + isGenesisProcessing: args.IsGenesisProcessing, + arwenChangeLocker: args.WasmVMChangeLocker, + vmOutputCacher: args.VMOutputCacher, + enableEpochsHandler: args.EnableEpochsHandler, + storePerByte: baseOperationCost["StorePerByte"], + persistPerByte: baseOperationCost["PersistPerByte"], + executableCheckers: scrCommon.CreateExecutableCheckersMap(args.BuiltInFunctions), } sc.esdtTransferParser, err = parsers.NewESDTTransferParser(args.Marshalizer) @@ -526,7 +532,7 @@ func (sc *scProcessor) finishSCExecution( return 0, err } - err = sc.scrForwarder.AddIntermediateTransactions(finalResults) + err = sc.scrForwarder.AddIntermediateTransactions(finalResults, txHash) if err != nil { log.Error("AddIntermediateTransactions error", "error", err.Error()) return 0, err @@ -824,10 +830,10 @@ func (sc *scProcessor) saveAccounts(acntSnd, acntDst vmcommon.AccountHandler) er func (sc *scProcessor) resolveFailedTransaction( _ state.UserAccountHandler, tx data.TransactionHandler, - _ []byte, + txHash []byte, ) error { if _, ok := tx.(*transaction.Transaction); ok { - err := sc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}) + err := sc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}, txHash) if err != nil { return err } @@ -1405,19 +1411,20 @@ func (sc *scProcessor) isCrossShardESDTTransfer(sender []byte, receiver []byte, func (sc *scProcessor) getOriginalTxHashIfIntraShardRelayedSCR( tx data.TransactionHandler, - txHash []byte) []byte { + txHash []byte, +) ([]byte, bool) { relayedSCR, isRelayed := isRelayedTx(tx) if !isRelayed { - return txHash + return txHash, isRelayed } sndShardID := sc.shardCoordinator.ComputeId(relayedSCR.SndAddr) rcvShardID := sc.shardCoordinator.ComputeId(relayedSCR.RcvAddr) if sndShardID != rcvShardID { - return txHash + return txHash, isRelayed } - return relayedSCR.OriginalTxHash + return relayedSCR.OriginalTxHash, isRelayed } // ProcessIfError creates a smart contract result, consumes the gas and returns the value to the user @@ -1487,7 +1494,7 @@ func (sc *scProcessor) processIfErrorWithAddedLogs(acntSnd state.UserAccountHand isRecvSelfShard := sc.shardCoordinator.SelfId() == sc.shardCoordinator.ComputeId(scrIfError.RcvAddr) if !isRecvSelfShard && !sc.isInformativeTxHandler(scrIfError) { - err = sc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrIfError}) + err = sc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrIfError}, failureContext.txHash) if err != nil { return err } @@ -1507,10 +1514,15 @@ func (sc *scProcessor) processIfErrorWithAddedLogs(acntSnd state.UserAccountHand processIfErrorLogs = append(processIfErrorLogs, failureContext.logs...) } - logsTxHash := sc.getOriginalTxHashIfIntraShardRelayedSCR(tx, failureContext.txHash) - ignorableError := sc.txLogsProcessor.SaveLog(logsTxHash, tx, processIfErrorLogs) + logsTxHash, isRelayed := sc.getOriginalTxHashIfIntraShardRelayedSCR(tx, failureContext.txHash) + var ignorableError error + if isRelayed { + ignorableError = sc.failedTxLogsAccumulator.SaveLogs(logsTxHash, tx, processIfErrorLogs) + } else { + ignorableError = sc.txLogsProcessor.SaveLog(logsTxHash, tx, processIfErrorLogs) + } if ignorableError != nil { - log.Debug("scProcessor.ProcessIfError() txLogsProcessor.SaveLog()", "error", ignorableError.Error()) + log.Debug("scProcessor.ProcessIfError() save log", "error", ignorableError.Error(), "isRelayed", isRelayed) } txType, _ := sc.txTypeHandler.ComputeTransactionType(tx) @@ -1613,7 +1625,7 @@ func (sc *scProcessor) processForRelayerWhenError( } if scrForRelayer.Value.Cmp(zero) > 0 { - err = sc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrForRelayer}) + err = sc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrForRelayer}, txHash) if err != nil { return nil, err } @@ -1865,7 +1877,7 @@ func (sc *scProcessor) doDeploySmartContract( return 0, err } - err = sc.scrForwarder.AddIntermediateTransactions(finalResults) + err = sc.scrForwarder.AddIntermediateTransactions(finalResults, txHash) if err != nil { log.Debug("AddIntermediate Transaction error", "error", err.Error()) return 0, err diff --git a/process/smartContract/processorV2/process_test.go b/process/smartContract/processorV2/process_test.go index eedea17f1ad..8722991d0a7 100644 --- a/process/smartContract/processorV2/process_test.go +++ b/process/smartContract/processorV2/process_test.go @@ -15,6 +15,14 @@ import ( "github.com/multiversx/mx-chain-core-go/data/smartContractResult" "github.com/multiversx/mx-chain-core-go/data/transaction" vmData "github.com/multiversx/mx-chain-core-go/data/vm" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" + "github.com/multiversx/mx-chain-vm-common-go/parsers" + "github.com/multiversx/mx-chain-vm-go/vmhost" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/config" "github.com/multiversx/mx-chain-go/process" @@ -35,16 +43,10 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/epochNotifier" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" testsCommonStorage "github.com/multiversx/mx-chain-go/testscommon/storage" "github.com/multiversx/mx-chain-go/testscommon/vmcommonMocks" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" - "github.com/multiversx/mx-chain-vm-common-go/parsers" - "github.com/multiversx/mx-chain-vm-go/vmhost" - "github.com/pkg/errors" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) const maxEpoch = math.MaxUint32 @@ -93,7 +95,7 @@ func createMockSmartContractProcessorArguments() scrCommon.ArgsNewSmartContractP return scrCommon.ArgsNewSmartContractProcessor{ VmContainer: &mock.VMContainerMock{}, - ArgsParser: &mock.ArgumentParserMock{}, + ArgsParser: &testscommon.ArgumentParserMock{}, Hasher: &hashingMocks.HasherMock{}, Marshalizer: &mock.MarshalizerMock{}, AccountsDB: &stateMock.AccountsStub{ @@ -129,9 +131,10 @@ func createMockSmartContractProcessorArguments() scrCommon.ArgsNewSmartContractP return flag == common.SCDeployFlag }, }, - GasSchedule: testscommon.NewGasScheduleNotifierMock(gasSchedule), - WasmVMChangeLocker: &sync.RWMutex{}, - VMOutputCacher: txcache.NewDisabledCache(), + GasSchedule: testscommon.NewGasScheduleNotifierMock(gasSchedule), + WasmVMChangeLocker: &sync.RWMutex{}, + VMOutputCacher: txcache.NewDisabledCache(), + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } } @@ -334,6 +337,17 @@ func TestNewSmartContractProcessor_NilTxLogsProcessorShouldErr(t *testing.T) { require.Equal(t, process.ErrNilTxLogsProcessor, err) } +func TestNewSmartContractProcessor_NilFailedTxLogsAccumulatorShouldErr(t *testing.T) { + t.Parallel() + + arguments := createMockSmartContractProcessorArguments() + arguments.FailedTxLogsAccumulator = nil + sc, err := NewSmartContractProcessorV2(arguments) + + require.Nil(t, sc) + require.Equal(t, process.ErrNilFailedTxLogsAccumulator, err) +} + func TestNewSmartContractProcessor_NilBadTxForwarderShouldErr(t *testing.T) { t.Parallel() @@ -438,7 +452,7 @@ func createTxLogsProcessor() process.TransactionLogProcessor { func TestScProcessor_DeploySmartContractBadParse(t *testing.T) { t.Parallel() - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = &mock.VMContainerMock{} arguments.ArgsParser = argParser @@ -553,13 +567,13 @@ func TestScProcessor_BuiltInCallSmartContractSenderFailed(t *testing.T) { scrAdded := false badTxAdded := false arguments.BadTxForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { badTxAdded = true return nil }, } arguments.ScrForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { scrAdded = true return nil }, @@ -908,7 +922,7 @@ func TestScProcessor_DeploySmartContractWrongTx(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -930,7 +944,7 @@ func TestScProcessor_DeploySmartContractNilTx(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -952,7 +966,7 @@ func TestScProcessor_DeploySmartContractNotEmptyDestinationAddress(t *testing.T) t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -975,7 +989,7 @@ func TestScProcessor_DeploySmartContractCalculateHashFails(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1007,7 +1021,7 @@ func TestScProcessor_DeploySmartContractEconomicsFeeValidateFails(t *testing.T) expectedError := errors.New("expected error") vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1038,7 +1052,7 @@ func TestScProcessor_DeploySmartContractEconomicsFeeSaveAccountsFails(t *testing expectedError := errors.New("expected error") vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1401,7 +1415,7 @@ func TestScProcessor_DeploySmartContractAddIntermediateTxFails(t *testing.T) { arguments := createMockSmartContractProcessorArguments() arguments.ArgsParser = argParser arguments.ScrForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { return expectedError }, } @@ -1436,7 +1450,7 @@ func TestScProcessor_DeploySmartContractComputeRewardsFails(t *testing.T) { arguments := createMockSmartContractProcessorArguments() arguments.ArgsParser = argParser arguments.ScrForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { return expectedError }, } @@ -1497,7 +1511,7 @@ func TestScProcessor_ExecuteSmartContractTransactionNilTx(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1521,7 +1535,7 @@ func TestScProcessor_ExecuteSmartContractTransactionNilAccount(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1554,7 +1568,7 @@ func TestScProcessor_ExecuteSmartContractTransactionBadParser(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1586,7 +1600,7 @@ func TestScProcessor_ExecuteSmartContractTransactionVMRunError(t *testing.T) { t.Parallel() vmContainer := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vmContainer arguments.ArgsParser = argParser @@ -1723,7 +1737,7 @@ func TestScProcessor_ExecuteSmartContractTransaction(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} accntState := &stateMock.AccountsStub{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm @@ -1756,7 +1770,7 @@ func TestScProcessor_ExecuteSmartContractTransactionSaveLogCalled(t *testing.T) slCalled := false vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} accntState := &stateMock.AccountsStub{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm @@ -1793,7 +1807,7 @@ func TestScProcessor_CreateVMCallInputWrongCode(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1821,7 +1835,7 @@ func TestScProcessor_CreateVMCallInput(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1845,7 +1859,7 @@ func TestScProcessor_CreateVMDeployBadCode(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1872,7 +1886,7 @@ func TestScProcessor_CreateVMCallInputBadAsync(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1902,7 +1916,7 @@ func TestScProcessor_CreateVMDeployInput(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1966,7 +1980,7 @@ func TestScProcessor_CreateVMDeployInputWrongArgument(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -1995,7 +2009,7 @@ func TestScProcessor_InitializeVMInputFromTx_ShouldErrNotEnoughGas(t *testing.T) t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2025,7 +2039,7 @@ func TestScProcessor_InitializeVMInputFromTx(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2062,7 +2076,7 @@ func TestScProcessor_processVMOutputNilSndAcc(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2091,7 +2105,7 @@ func TestScProcessor_processVMOutputNilDstAcc(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} accntState := &stateMock.AccountsStub{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm @@ -2135,7 +2149,7 @@ func TestScProcessor_GetAccountFromAddressAccNotFound(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2166,7 +2180,7 @@ func TestScProcessor_GetAccountFromAddrFailedGetExistingAccount(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2198,7 +2212,7 @@ func TestScProcessor_GetAccountFromAddrAccNotInShard(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2231,7 +2245,7 @@ func TestScProcessor_GetAccountFromAddr(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2266,7 +2280,7 @@ func TestScProcessor_DeleteAccountsFailedAtRemove(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2301,7 +2315,7 @@ func TestScProcessor_DeleteAccountsNotInShard(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -2341,7 +2355,7 @@ func TestScProcessor_DeleteAccountsInShard(t *testing.T) { } vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm arguments.ArgsParser = argParser @@ -3330,6 +3344,13 @@ func TestScProcessor_ProcessRelayedSCRValueBackToRelayer(t *testing.T) { return process.SCInvoking, process.SCInvoking }, } + wasSaveLogsCalled := false + arguments.FailedTxLogsAccumulator = &processMocks.FailedTxLogsAccumulatorMock{ + SaveLogsCalled: func(txHash []byte, tx data.TransactionHandler, logs []*vmcommon.LogEntry) error { + wasSaveLogsCalled = true + return nil + }, + } sc, err := NewSmartContractProcessorV2(arguments) require.NotNil(t, sc) require.Nil(t, err) @@ -3352,6 +3373,7 @@ func TestScProcessor_ProcessRelayedSCRValueBackToRelayer(t *testing.T) { userFinalValue := baseValue.Sub(baseValue, scr.Value) userFinalValue.Add(userFinalValue, userReturnValue) require.True(t, userAcc.GetBalance().Cmp(userFinalValue) == 0) + require.True(t, wasSaveLogsCalled) } func TestScProcessor_checkUpgradePermission(t *testing.T) { @@ -4061,18 +4083,20 @@ func TestProcessGetOriginalTxHashForRelayedIntraShard(t *testing.T) { scr := &smartContractResult.SmartContractResult{Value: big.NewInt(1), SndAddr: bytes.Repeat([]byte{1}, 32)} scrHash := []byte("hash") - logHash := sc.getOriginalTxHashIfIntraShardRelayedSCR(scr, scrHash) + logHash, isRelayed := sc.getOriginalTxHashIfIntraShardRelayedSCR(scr, scrHash) assert.Equal(t, scrHash, logHash) + assert.False(t, isRelayed) scr.OriginalTxHash = []byte("originalHash") scr.RelayerAddr = bytes.Repeat([]byte{1}, 32) scr.SndAddr = bytes.Repeat([]byte{1}, 32) scr.RcvAddr = bytes.Repeat([]byte{1}, 32) - logHash = sc.getOriginalTxHashIfIntraShardRelayedSCR(scr, scrHash) + logHash, isRelayed = sc.getOriginalTxHashIfIntraShardRelayedSCR(scr, scrHash) assert.Equal(t, scr.OriginalTxHash, logHash) + assert.True(t, isRelayed) scr.RcvAddr = bytes.Repeat([]byte{2}, 32) - logHash = sc.getOriginalTxHashIfIntraShardRelayedSCR(scr, scrHash) + logHash, _ = sc.getOriginalTxHashIfIntraShardRelayedSCR(scr, scrHash) assert.Equal(t, scrHash, logHash) } @@ -4343,7 +4367,7 @@ func TestSCProcessor_PrependAsyncParamsToData(t *testing.T) { func TestScProcessor_ForbidMultiLevelAsync(t *testing.T) { t.Parallel() vm := &mock.VMContainerMock{} - argParser := &mock.ArgumentParserMock{} + argParser := &testscommon.ArgumentParserMock{} accntState := &stateMock.AccountsStub{} arguments := createMockSmartContractProcessorArguments() arguments.VmContainer = vm diff --git a/process/smartContract/processorV2/vmInputV2.go b/process/smartContract/processorV2/vmInputV2.go index 35e68776907..06c4c3f0ad2 100644 --- a/process/smartContract/processorV2/vmInputV2.go +++ b/process/smartContract/processorV2/vmInputV2.go @@ -39,6 +39,12 @@ func (sc *scProcessor) initializeVMInputFromTx(vmInput *vmcommon.VMInput, tx dat vmInput.CallerAddr = tx.GetSndAddr() vmInput.CallValue = new(big.Int).Set(tx.GetValue()) vmInput.GasPrice = tx.GetGasPrice() + + relayedTx, isRelayed := isRelayedTx(tx) + if isRelayed { + vmInput.RelayerAddr = relayedTx.RelayerAddr + } + vmInput.GasProvided, err = sc.prepareGasProvided(tx) if err != nil { return err diff --git a/process/smartContract/scrCommon/common.go b/process/smartContract/scrCommon/common.go index 957abe5800b..07efc6cfd59 100644 --- a/process/smartContract/scrCommon/common.go +++ b/process/smartContract/scrCommon/common.go @@ -1,6 +1,8 @@ package scrCommon import ( + "math/big" + "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/hashing" @@ -12,7 +14,6 @@ import ( "github.com/multiversx/mx-chain-go/state" "github.com/multiversx/mx-chain-go/storage" vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "math/big" ) // TestSmartContractProcessor is a SmartContractProcessor used in integration tests @@ -31,29 +32,30 @@ type ExecutableChecker interface { // ArgsNewSmartContractProcessor defines the arguments needed for new smart contract processor type ArgsNewSmartContractProcessor struct { - VmContainer process.VirtualMachinesContainer - ArgsParser process.ArgumentsParser - Hasher hashing.Hasher - Marshalizer marshal.Marshalizer - AccountsDB state.AccountsAdapter - BlockChainHook process.BlockChainHookHandler - BuiltInFunctions vmcommon.BuiltInFunctionContainer - PubkeyConv core.PubkeyConverter - ShardCoordinator sharding.Coordinator - ScrForwarder process.IntermediateTransactionHandler - TxFeeHandler process.TransactionFeeHandler - EconomicsFee process.FeeHandler - TxTypeHandler process.TxTypeHandler - GasHandler process.GasHandler - GasSchedule core.GasScheduleNotifier - TxLogsProcessor process.TransactionLogProcessor - BadTxForwarder process.IntermediateTransactionHandler - EnableRoundsHandler process.EnableRoundsHandler - EnableEpochsHandler common.EnableEpochsHandler - EnableEpochs config.EnableEpochs - VMOutputCacher storage.Cacher - WasmVMChangeLocker common.Locker - IsGenesisProcessing bool + VmContainer process.VirtualMachinesContainer + ArgsParser process.ArgumentsParser + Hasher hashing.Hasher + Marshalizer marshal.Marshalizer + AccountsDB state.AccountsAdapter + BlockChainHook process.BlockChainHookHandler + BuiltInFunctions vmcommon.BuiltInFunctionContainer + PubkeyConv core.PubkeyConverter + ShardCoordinator sharding.Coordinator + ScrForwarder process.IntermediateTransactionHandler + TxFeeHandler process.TransactionFeeHandler + EconomicsFee process.FeeHandler + TxTypeHandler process.TxTypeHandler + GasHandler process.GasHandler + GasSchedule core.GasScheduleNotifier + TxLogsProcessor process.TransactionLogProcessor + FailedTxLogsAccumulator process.FailedTxLogsAccumulator + BadTxForwarder process.IntermediateTransactionHandler + EnableRoundsHandler process.EnableRoundsHandler + EnableEpochsHandler common.EnableEpochsHandler + EnableEpochs config.EnableEpochs + VMOutputCacher storage.Cacher + WasmVMChangeLocker common.Locker + IsGenesisProcessing bool } // FindVMByScAddress is exported for use in all version of scr processors diff --git a/process/transaction/baseProcess.go b/process/transaction/baseProcess.go index 45e9f2aac13..b1e95a71339 100644 --- a/process/transaction/baseProcess.go +++ b/process/transaction/baseProcess.go @@ -29,6 +29,7 @@ type baseTxProcessor struct { enableEpochsHandler common.EnableEpochsHandler txVersionChecker process.TxVersionCheckerHandler guardianChecker process.GuardianChecker + txTypeHandler process.TxTypeHandler } func (txProc *baseTxProcessor) getAccounts( @@ -145,7 +146,8 @@ func (txProc *baseTxProcessor) checkTxValues( if tx.GasLimit < txProc.economicsFee.ComputeGasLimit(tx) { return process.ErrNotEnoughGasInUserTx } - txFee = txProc.economicsFee.ComputeFeeForProcessing(tx, tx.GasLimit) + + txFee = txProc.computeInnerTxFee(tx) } else { txFee = txProc.economicsFee.ComputeTxFee(tx) } @@ -172,6 +174,29 @@ func (txProc *baseTxProcessor) checkTxValues( return nil } +func (txProc *baseTxProcessor) computeInnerTxFee(tx *transaction.Transaction) *big.Int { + if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedBaseCostFlag) { + return txProc.computeInnerTxFeeAfterBaseCostFix(tx) + } + + return txProc.economicsFee.ComputeFeeForProcessing(tx, tx.GasLimit) +} + +func (txProc *baseTxProcessor) computeInnerTxFeeAfterBaseCostFix(tx *transaction.Transaction) *big.Int { + _, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(tx) + if dstShardTxType == process.MoveBalance { + return txProc.economicsFee.ComputeMoveBalanceFee(tx) + } + + moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(tx) + gasToUse := tx.GetGasLimit() - moveBalanceGasLimit + moveBalanceUserFee := txProc.economicsFee.ComputeMoveBalanceFee(tx) + processingUserFee := txProc.economicsFee.ComputeFeeForProcessing(tx, gasToUse) + txFee := big.NewInt(0).Add(moveBalanceUserFee, processingUserFee) + + return txFee +} + func (txProc *baseTxProcessor) checkUserNames(tx *transaction.Transaction, acntSnd, acntDst state.UserAccountHandler) error { isUserNameWrong := len(tx.SndUserName) > 0 && !check.IfNil(acntSnd) && !bytes.Equal(tx.SndUserName, acntSnd.GetUserName()) diff --git a/process/transaction/baseProcess_test.go b/process/transaction/baseProcess_test.go index 3527748a72e..7795c1a0f6a 100644 --- a/process/transaction/baseProcess_test.go +++ b/process/transaction/baseProcess_test.go @@ -44,6 +44,7 @@ func createMockBaseTxProcessor() *baseTxProcessor { enableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.PenalizedTooMuchGasFlag), txVersionChecker: &testscommon.TxVersionCheckerStub{}, guardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, + txTypeHandler: &testscommon.TxTypeHandlerMock{}, } return &baseProc @@ -212,6 +213,7 @@ func TestBaseTxProcessor_VerifyGuardian(t *testing.T) { enableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.PenalizedTooMuchGasFlag), txVersionChecker: &testscommon.TxVersionCheckerStub{}, guardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, + txTypeHandler: &testscommon.TxTypeHandlerMock{}, } notGuardedAccount := &stateMock.UserAccountStub{} diff --git a/process/transaction/export_test.go b/process/transaction/export_test.go index a10b1e2e50c..07ed7a91896 100644 --- a/process/transaction/export_test.go +++ b/process/transaction/export_test.go @@ -13,19 +13,23 @@ import ( type TxProcessor *txProcessor +// GetAccounts calls the un-exported method getAccounts func (txProc *txProcessor) GetAccounts(adrSrc, adrDst []byte, ) (acntSrc, acntDst state.UserAccountHandler, err error) { return txProc.getAccounts(adrSrc, adrDst) } +// CheckTxValues calls the un-exported method checkTxValues func (txProc *txProcessor) CheckTxValues(tx *transaction.Transaction, acntSnd, acntDst state.UserAccountHandler, isUserTxOfRelayed bool) error { return txProc.checkTxValues(tx, acntSnd, acntDst, isUserTxOfRelayed) } +// IncreaseNonce calls IncreaseNonce on the provided account func (txProc *txProcessor) IncreaseNonce(acntSrc state.UserAccountHandler) { acntSrc.IncreaseNonce(1) } +// ProcessTxFee calls the un-exported method processTxFee func (txProc *txProcessor) ProcessTxFee( tx *transaction.Transaction, acntSnd, acntDst state.UserAccountHandler, @@ -35,24 +39,28 @@ func (txProc *txProcessor) ProcessTxFee( return txProc.processTxFee(tx, acntSnd, acntDst, txType, isUserTxOfRelayed) } +// SetWhitelistHandler sets the un-exported field whiteListerVerifiedTxs func (inTx *InterceptedTransaction) SetWhitelistHandler(handler process.WhiteListHandler) { inTx.whiteListerVerifiedTxs = handler } +// IsCrossTxFromMe calls the un-exported method isCrossTxFromMe func (txProc *baseTxProcessor) IsCrossTxFromMe(adrSrc, adrDst []byte) bool { return txProc.isCrossTxFromMe(adrSrc, adrDst) } +// ProcessUserTx calls the un-exported method processUserTx func (txProc *txProcessor) ProcessUserTx( originalTx *transaction.Transaction, userTx *transaction.Transaction, relayedTxValue *big.Int, relayedNonce uint64, - txHash []byte, + originalTxHash []byte, ) (vmcommon.ReturnCode, error) { - return txProc.processUserTx(originalTx, userTx, relayedTxValue, relayedNonce, txHash) + return txProc.processUserTx(originalTx, userTx, relayedTxValue, relayedNonce, originalTxHash) } +// ProcessMoveBalanceCostRelayedUserTx calls the un-exported method processMoveBalanceCostRelayedUserTx func (txProc *txProcessor) ProcessMoveBalanceCostRelayedUserTx( userTx *transaction.Transaction, userScr *smartContractResult.SmartContractResult, @@ -62,6 +70,7 @@ func (txProc *txProcessor) ProcessMoveBalanceCostRelayedUserTx( return txProc.processMoveBalanceCostRelayedUserTx(userTx, userScr, userAcc, originalTxHash) } +// ExecuteFailedRelayedTransaction calls the un-exported method executeFailedRelayedUserTx func (txProc *txProcessor) ExecuteFailedRelayedTransaction( userTx *transaction.Transaction, relayerAdr []byte, @@ -81,20 +90,22 @@ func (txProc *txProcessor) ExecuteFailedRelayedTransaction( errorMsg) } +// CheckMaxGasPrice calls the un-exported method checkMaxGasPrice func (inTx *InterceptedTransaction) CheckMaxGasPrice() error { return inTx.checkMaxGasPrice() } +// VerifyGuardian calls the un-exported method verifyGuardian func (txProc *txProcessor) VerifyGuardian(tx *transaction.Transaction, account state.UserAccountHandler) error { return txProc.verifyGuardian(tx, account) } -// ShouldIncreaseNonce - +// ShouldIncreaseNonce calls the un-exported method shouldIncreaseNonce func (txProc *txProcessor) ShouldIncreaseNonce(executionErr error) bool { return txProc.shouldIncreaseNonce(executionErr) } -// AddNonExecutableLog - +// AddNonExecutableLog calls the un-exported method addNonExecutableLog func (txProc *txProcessor) AddNonExecutableLog(executionErr error, originalTxHash []byte, originalTx data.TransactionHandler) error { return txProc.addNonExecutableLog(executionErr, originalTxHash, originalTx) } diff --git a/process/transaction/interceptedTransaction.go b/process/transaction/interceptedTransaction.go index 0aedf837d09..831afdcbcbc 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" @@ -42,6 +43,8 @@ type InterceptedTransaction struct { sndShard uint32 isForCurrentShard bool enableSignedTxWithHash bool + enableEpochsHandler common.EnableEpochsHandler + relayedTxV3Processor process.RelayedTxV3Processor } // NewInterceptedTransaction returns a new instance of InterceptedTransaction @@ -61,6 +64,8 @@ func NewInterceptedTransaction( enableSignedTxWithHash bool, txSignHasher hashing.Hasher, txVersionChecker process.TxVersionCheckerHandler, + enableEpochsHandler common.EnableEpochsHandler, + relayedTxV3Processor process.RelayedTxV3Processor, ) (*InterceptedTransaction, error) { if txBuff == nil { @@ -105,6 +110,12 @@ func NewInterceptedTransaction( if check.IfNil(txVersionChecker) { return nil, process.ErrNilTransactionVersionChecker } + if check.IfNil(enableEpochsHandler) { + return nil, process.ErrNilEnableEpochsHandler + } + if check.IfNil(relayedTxV3Processor) { + return nil, process.ErrNilRelayedTxV3Processor + } tx, err := createTx(protoMarshalizer, txBuff) if err != nil { @@ -127,6 +138,8 @@ func NewInterceptedTransaction( enableSignedTxWithHash: enableSignedTxWithHash, txVersionChecker: txVersionChecker, txSignHasher: txSignHasher, + enableEpochsHandler: enableEpochsHandler, + relayedTxV3Processor: relayedTxV3Processor, } err = inTx.processFields(txBuff) @@ -199,51 +212,102 @@ func (inTx *InterceptedTransaction) CheckValidity() error { return err } + err = inTx.verifyIfRelayedTxV3(inTx.tx) + if err != nil { + return err + } + + if len(inTx.tx.RelayerAddr) > 0 { + return fmt.Errorf("%w, relayer address found on transaction", process.ErrWrongTransaction) + } + inTx.whiteListerVerifiedTxs.Add([][]byte{inTx.Hash()}) } return nil } -func isRelayedTx(funcName string) bool { - return core.RelayedTransaction == funcName || core.RelayedTransactionV2 == funcName -} +func (inTx *InterceptedTransaction) checkRecursiveRelayed(userTxData []byte, innerTxs []*transaction.Transaction) error { + if isRelayedV3(innerTxs) { + return process.ErrRecursiveRelayedTxIsNotAllowed + } -func (inTx *InterceptedTransaction) verifyIfRelayedTxV2(tx *transaction.Transaction) error { - funcName, userTxArgs, err := inTx.argsParser.ParseCallData(string(tx.Data)) + funcName, _, err := inTx.argsParser.ParseCallData(string(userTxData)) if err != nil { return nil } - if core.RelayedTransactionV2 != funcName { - return nil + + if isRelayedTx(funcName) { + return process.ErrRecursiveRelayedTxIsNotAllowed } - userTx, err := createRelayedV2(tx, userTxArgs) + return nil +} + +func isRelayedTx(funcName string) bool { + return core.RelayedTransaction == funcName || + core.RelayedTransactionV2 == funcName +} + +func isRelayedV3(innerTxs []*transaction.Transaction) bool { + return len(innerTxs) > 0 +} + +func (inTx *InterceptedTransaction) verifyIfRelayedTxV3(tx *transaction.Transaction) error { + if len(tx.InnerTransactions) == 0 { + return nil + } + if !inTx.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsV3Flag) { + return process.ErrRelayedTxV3Disabled + } + err := inTx.relayedTxV3Processor.CheckRelayedTx(tx) if err != nil { return err } - err = inTx.verifySig(userTx) - if err != nil { - return fmt.Errorf("inner transaction: %w", err) + funcName, _, err := inTx.argsParser.ParseCallData(string(tx.Data)) + if err == nil && isRelayedTx(funcName) { + return process.ErrMultipleRelayedTxTypesIsNotAllowed } - err = inTx.VerifyGuardianSig(userTx) - if err != nil { - return fmt.Errorf("inner transaction: %w", err) + return inTx.verifyInnerTransactions(tx) +} + +func (inTx *InterceptedTransaction) verifyInnerTransactions(tx *transaction.Transaction) error { + for _, innerTx := range tx.InnerTransactions { + err := inTx.integrity(innerTx) + if err != nil { + return fmt.Errorf("inner transaction: %w", err) + } + + err = inTx.verifyUserTx(innerTx) + if err != nil { + return fmt.Errorf("inner transaction: %w", err) + } } - funcName, _, err = inTx.argsParser.ParseCallData(string(userTx.Data)) + return nil +} + +func (inTx *InterceptedTransaction) verifyIfRelayedTxV2(tx *transaction.Transaction) error { + funcName, userTxArgs, err := inTx.argsParser.ParseCallData(string(tx.Data)) if err != nil { return nil } + if core.RelayedTransactionV2 != funcName { + return nil + } - // recursive relayed transactions are not allowed - if isRelayedTx(funcName) { - return process.ErrRecursiveRelayedTxIsNotAllowed + if len(tx.InnerTransactions) > 0 { + return process.ErrMultipleRelayedTxTypesIsNotAllowed } - return nil + userTx, err := createRelayedV2(tx, userTxArgs) + if err != nil { + return err + } + + return inTx.verifyUserTx(userTx) } func (inTx *InterceptedTransaction) verifyIfRelayedTx(tx *transaction.Transaction) error { @@ -259,6 +323,10 @@ func (inTx *InterceptedTransaction) verifyIfRelayedTx(tx *transaction.Transactio return process.ErrInvalidArguments } + if len(tx.InnerTransactions) > 0 { + return process.ErrMultipleRelayedTxTypesIsNotAllowed + } + userTx, err := createTx(inTx.signMarshalizer, userTxArgs[0]) if err != nil { return fmt.Errorf("inner transaction: %w", err) @@ -273,28 +341,23 @@ func (inTx *InterceptedTransaction) verifyIfRelayedTx(tx *transaction.Transactio return fmt.Errorf("inner transaction: %w", err) } - err = inTx.verifySig(userTx) + return inTx.verifyUserTx(userTx) +} + +func (inTx *InterceptedTransaction) verifyUserTx(userTx *transaction.Transaction) error { + // recursive relayed transactions are not allowed + err := inTx.checkRecursiveRelayed(userTx.Data, userTx.InnerTransactions) if err != nil { return fmt.Errorf("inner transaction: %w", err) } - - err = inTx.VerifyGuardianSig(userTx) + err = inTx.verifySig(userTx) if err != nil { return fmt.Errorf("inner transaction: %w", err) } - if len(userTx.Data) == 0 { - return nil - } - - funcName, _, err = inTx.argsParser.ParseCallData(string(userTx.Data)) + err = inTx.VerifyGuardianSig(userTx) if err != nil { - return nil - } - - // recursive relayed transactions are not allowed - if isRelayedTx(funcName) { - return process.ErrRecursiveRelayedTxIsNotAllowed + return fmt.Errorf("inner transaction: %w", err) } return nil @@ -474,6 +537,11 @@ func (inTx *InterceptedTransaction) Fee() *big.Int { return inTx.feeHandler.ComputeTxFee(inTx.tx) } +// RelayerAddress returns the relayer address from transaction +func (inTx *InterceptedTransaction) RelayerAddress() []byte { + return inTx.tx.RelayerAddr +} + // Type returns the type of this intercepted data func (inTx *InterceptedTransaction) Type() string { return "intercepted tx" diff --git a/process/transaction/interceptedTransaction_test.go b/process/transaction/interceptedTransaction_test.go index b2aa2e81526..44d416194ab 100644 --- a/process/transaction/interceptedTransaction_test.go +++ b/process/transaction/interceptedTransaction_test.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "math/big" + "strings" "testing" "github.com/multiversx/mx-chain-core-go/core" @@ -14,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" @@ -21,8 +23,10 @@ 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" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" logger "github.com/multiversx/mx-chain-logger-go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -33,8 +37,10 @@ var errSignerMockVerifySigFails = errors.New("errSignerMockVerifySigFails") var senderShard = uint32(2) var recvShard = uint32(3) +var relayerShard = senderShard var senderAddress = []byte("12345678901234567890123456789012") var recvAddress = []byte("23456789012345678901234567890123") +var relayerAddress = []byte("34567890123456789012345678901234") var sigBad = []byte("bad-signature") var sigOk = []byte("signature") @@ -89,6 +95,9 @@ func createInterceptedTxWithTxFeeHandlerAndVersionChecker(tx *dataTransaction.Tr if bytes.Equal(address, recvAddress) { return recvShard } + if bytes.Equal(address, relayerAddress) { + return relayerShard + } return shardCoordinator.CurrentShard } @@ -108,11 +117,13 @@ func createInterceptedTxWithTxFeeHandlerAndVersionChecker(tx *dataTransaction.Tr shardCoordinator, txFeeHandler, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("T"), false, &hashingMocks.HasherMock{}, txVerChecker, + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) } @@ -132,6 +143,9 @@ func createInterceptedTxFromPlainTx(tx *dataTransaction.Transaction, txFeeHandle if bytes.Equal(address, recvAddress) { return recvShard } + if bytes.Equal(address, relayerAddress) { + return relayerShard + } return shardCoordinator.CurrentShard } @@ -151,11 +165,13 @@ func createInterceptedTxFromPlainTx(tx *dataTransaction.Transaction, txFeeHandle shardCoordinator, txFeeHandler, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, chainID, false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) } @@ -175,10 +191,23 @@ func createInterceptedTxFromPlainTxWithArgParser(tx *dataTransaction.Transaction if bytes.Equal(address, recvAddress) { return recvShard } + if bytes.Equal(address, relayerAddress) { + return relayerShard + } return shardCoordinator.CurrentShard } + txFeeHandler := createFreeTxFeeHandler() + relayedTxV3Processor, err := transaction.NewRelayedTxV3Processor(transaction.ArgRelayedTxV3Processor{ + EconomicsFee: txFeeHandler, + ShardCoordinator: shardCoordinator, + MaxTransactionsAllowed: 10, + }) + if err != nil { + return nil, err + } + return transaction.NewInterceptedTransaction( txBuff, marshalizer, @@ -192,13 +221,15 @@ func createInterceptedTxFromPlainTxWithArgParser(tx *dataTransaction.Transaction }, }, shardCoordinator, - createFreeTxFeeHandler(), + txFeeHandler, &testscommon.WhiteListHandlerStub{}, smartContract.NewArgumentParser(), tx.ChainID, false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(tx.Version), + enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.RelayedTransactionsV3Flag), + relayedTxV3Processor, ) } @@ -218,11 +249,13 @@ func TestNewInterceptedTransaction_NilBufferShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -248,6 +281,8 @@ func TestNewInterceptedTransaction_NilArgsParser(t *testing.T) { false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -268,11 +303,13 @@ func TestNewInterceptedTransaction_NilVersionChecker(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, nil, + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -293,11 +330,13 @@ func TestNewInterceptedTransaction_NilMarshalizerShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -318,11 +357,13 @@ func TestNewInterceptedTransaction_NilSignMarshalizerShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -343,11 +384,13 @@ func TestNewInterceptedTransaction_NilHasherShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -368,11 +411,13 @@ func TestNewInterceptedTransaction_NilKeyGenShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -393,11 +438,13 @@ func TestNewInterceptedTransaction_NilSignerShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -418,11 +465,13 @@ func TestNewInterceptedTransaction_NilPubkeyConverterShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -443,11 +492,13 @@ func TestNewInterceptedTransaction_NilCoordinatorShouldErr(t *testing.T) { nil, &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -468,11 +519,13 @@ func TestNewInterceptedTransaction_NilFeeHandlerShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), nil, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -493,11 +546,13 @@ func TestNewInterceptedTransaction_NilWhiteListerVerifiedTxsShouldErr(t *testing mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, nil, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -518,11 +573,13 @@ func TestNewInterceptedTransaction_InvalidChainIDShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, nil, false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -543,17 +600,73 @@ func TestNewInterceptedTransaction_NilTxSignHasherShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, nil, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) 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, + &processMocks.RelayedTxV3ProcessorMock{}, + ) + + assert.Nil(t, txi) + assert.Equal(t, process.ErrNilEnableEpochsHandler, err) +} + +func TestNewInterceptedTransaction_NilRelayedV3ProcessorShouldErr(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), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + nil, + ) + + assert.Nil(t, txi) + assert.Equal(t, process.ErrNilRelayedTxV3Processor, err) +} + func TestNewInterceptedTransaction_UnmarshalingTxFailsShouldErr(t *testing.T) { t.Parallel() @@ -574,11 +687,13 @@ func TestNewInterceptedTransaction_UnmarshalingTxFailsShouldErr(t *testing.T) { mock.NewOneShardCoordinatorMock(), &economicsmocks.EconomicsHandlerStub{}, &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("chainID"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(1), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, txi) @@ -995,6 +1110,32 @@ func TestInterceptedTransaction_CheckValidityOkValsShouldWork(t *testing.T) { assert.Nil(t, err) } +func TestInterceptedTransaction_CheckValidityRelayerAddressShouldError(t *testing.T) { + t.Parallel() + + minTxVersion := uint32(1) + chainID := []byte("chain") + tx := &dataTransaction.Transaction{ + Nonce: 1, + Value: big.NewInt(2), + Data: []byte("data"), + GasLimit: 3, + GasPrice: 4, + RcvAddr: recvAddress, + SndAddr: senderAddress, + Signature: sigOk, + ChainID: chainID, + Version: minTxVersion, + RelayerAddr: []byte("45678901234567890123456789012345"), + } + txi, _ := createInterceptedTxFromPlainTx(tx, createFreeTxFeeHandler(), chainID, minTxVersion) + + err := txi.CheckValidity() + + assert.True(t, errors.Is(err, process.ErrWrongTransaction)) + assert.True(t, strings.Contains(err.Error(), "relayer address found on transaction")) +} + func TestInterceptedTransaction_CheckValiditySignedWithHashButNotEnabled(t *testing.T) { t.Parallel() @@ -1044,11 +1185,13 @@ func TestInterceptedTransaction_CheckValiditySignedWithHashButNotEnabled(t *test shardCoordinator, createFreeTxFeeHandler(), &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, chainID, false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) err := txi.CheckValidity() @@ -1104,11 +1247,13 @@ func TestInterceptedTransaction_CheckValiditySignedWithHashShouldWork(t *testing shardCoordinator, createFreeTxFeeHandler(), &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, chainID, true, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) err := txi.CheckValidity() @@ -1189,11 +1334,13 @@ func TestInterceptedTransaction_ScTxDeployRecvShardIdShouldBeSendersShardId(t *t shardCoordinator, createFreeTxFeeHandler(), &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, chainID, false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Nil(t, err) @@ -1274,6 +1421,31 @@ func TestInterceptedTransaction_GetSenderAddress(t *testing.T) { assert.NotNil(t, result) } +func TestInterceptedTransaction_GetRelayerAddress(t *testing.T) { + t.Parallel() + + relayerAddr := []byte("34567890123456789012345678901234") + minTxVersion := uint32(1) + chainID := []byte("chain") + tx := &dataTransaction.Transaction{ + Nonce: 0, + Value: big.NewInt(2), + Data: []byte("data"), + GasLimit: 3, + GasPrice: 4, + RcvAddr: recvAddress, + SndAddr: senderAddress, + Signature: sigOk, + ChainID: chainID, + Version: minTxVersion, + RelayerAddr: relayerAddr, + } + + txi, _ := createInterceptedTxFromPlainTx(tx, createFreeTxFeeHandler(), chainID, minTxVersion) + result := txi.RelayerAddress() + assert.Equal(t, relayerAddr, result) +} + func TestInterceptedTransaction_CheckValiditySecondTimeDoesNotVerifySig(t *testing.T) { t.Parallel() @@ -1328,11 +1500,13 @@ func TestInterceptedTransaction_CheckValiditySecondTimeDoesNotVerifySig(t *testi shardCoordinator, createFreeTxFeeHandler(), whiteListerVerifiedTxs, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, chainID, false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(minTxVersion), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) require.Nil(t, err) @@ -1426,7 +1600,16 @@ func TestInterceptedTransaction_CheckValidityOfRelayedTx(t *testing.T) { tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxData)) txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) err = txi.CheckValidity() - assert.Equal(t, process.ErrRecursiveRelayedTxIsNotAllowed, err) + assert.True(t, strings.Contains(err.Error(), process.ErrRecursiveRelayedTxIsNotAllowed.Error())) + assert.Contains(t, err.Error(), "inner transaction") + + userTx.Data = []byte("") + userTxData, _ = marshalizer.Marshal(userTx) + tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxData)) + tx.InnerTransactions = []*dataTransaction.Transaction{{Nonce: 100}} + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + err = txi.CheckValidity() + assert.True(t, strings.Contains(err.Error(), process.ErrMultipleRelayedTxTypesIsNotAllowed.Error())) } func TestInterceptedTransaction_CheckValidityOfRelayedTxV2(t *testing.T) { @@ -1487,8 +1670,19 @@ func TestInterceptedTransaction_CheckValidityOfRelayedTxV2(t *testing.T) { tx.Data = []byte(core.RelayedTransactionV2 + "@" + hex.EncodeToString(userTx.RcvAddr) + "@" + hex.EncodeToString(big.NewInt(0).SetUint64(userTx.Nonce).Bytes()) + "@" + hex.EncodeToString([]byte(core.RelayedTransaction)) + "@" + hex.EncodeToString(userTx.Signature)) txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) err = txi.CheckValidity() - assert.Equal(t, process.ErrRecursiveRelayedTxIsNotAllowed, err) + assert.True(t, strings.Contains(err.Error(), process.ErrRecursiveRelayedTxIsNotAllowed.Error())) + assert.Contains(t, err.Error(), "inner transaction") + + userTx.Data = []byte("") + marshalizer := &mock.MarshalizerMock{} + userTxData, _ := marshalizer.Marshal(userTx) + tx.Data = []byte(core.RelayedTransactionV2 + "@" + hex.EncodeToString(userTxData)) + tx.InnerTransactions = []*dataTransaction.Transaction{{Nonce: 100}} + txi, _ = createInterceptedTxFromPlainTxWithArgParser(tx) + err = txi.CheckValidity() + assert.True(t, strings.Contains(err.Error(), process.ErrMultipleRelayedTxTypesIsNotAllowed.Error())) + tx.InnerTransactions = nil userTx.Signature = sigOk userTx.SndAddr = []byte("otherAddress") tx.Data = []byte(core.RelayedTransactionV2 + "@" + hex.EncodeToString(userTx.RcvAddr) + "@" + hex.EncodeToString(big.NewInt(0).SetUint64(userTx.Nonce).Bytes()) + "@" + hex.EncodeToString(userTx.Data) + "@" + hex.EncodeToString(userTx.Signature)) @@ -1497,6 +1691,177 @@ func TestInterceptedTransaction_CheckValidityOfRelayedTxV2(t *testing.T) { assert.Nil(t, err) } +func TestInterceptedTransaction_CheckValidityOfRelayedTxV3(t *testing.T) { + t.Parallel() + + minTxVersion := uint32(1) + chainID := []byte("chain") + innerTx := &dataTransaction.Transaction{ + Nonce: 1, + Value: big.NewInt(2), + Data: []byte("data inner tx 1"), + GasLimit: 3, + GasPrice: 4, + RcvAddr: recvAddress, + SndAddr: senderAddress, + Signature: sigOk, + ChainID: chainID, + Version: minTxVersion, + RelayerAddr: relayerAddress, + } + + tx := &dataTransaction.Transaction{ + Nonce: 1, + Value: big.NewInt(0), + GasLimit: 10, + GasPrice: 4, + RcvAddr: relayerAddress, + SndAddr: relayerAddress, + Signature: sigOk, + ChainID: chainID, + Version: minTxVersion, + InnerTransactions: []*dataTransaction.Transaction{innerTx}, + } + + t.Run("should work", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + txi, _ := createInterceptedTxFromPlainTxWithArgParser(&txCopy) + err := txi.CheckValidity() + assert.Nil(t, err) + }) + t.Run("inner txs on inner tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + innerTxCopy := *innerTx + innerTxCopy.InnerTransactions = []*dataTransaction.Transaction{{}} + txCopy.InnerTransactions = []*dataTransaction.Transaction{&innerTxCopy} + + txi, _ := createInterceptedTxFromPlainTxWithArgParser(&txCopy) + err := txi.CheckValidity() + assert.Equal(t, process.ErrRecursiveRelayedTxIsNotAllowed, err) + }) + t.Run("different relayer on inner tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + innerTxCopy := *innerTx + innerTxCopy.RelayerAddr = recvAddress + txCopy.InnerTransactions = []*dataTransaction.Transaction{&innerTxCopy} + + txi, _ := createInterceptedTxFromPlainTxWithArgParser(&txCopy) + err := txi.CheckValidity() + assert.Equal(t, process.ErrRelayedTxV3RelayerMismatch, err) + }) + t.Run("different sender than receiver should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + innerTxCopy := *innerTx + txCopy.RcvAddr = recvAddress + txCopy.InnerTransactions = []*dataTransaction.Transaction{&innerTxCopy} + txi, _ := createInterceptedTxFromPlainTxWithArgParser(&txCopy) + err := txi.CheckValidity() + assert.Equal(t, process.ErrRelayedTxV3SenderDoesNotMatchReceiver, err) + }) + t.Run("empty signature on inner tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + innerTxCopy := *innerTx + innerTxCopy.Signature = nil + txCopy.InnerTransactions = []*dataTransaction.Transaction{&innerTxCopy} + txi, _ := createInterceptedTxFromPlainTxWithArgParser(&txCopy) + err := txi.CheckValidity() + assert.NotNil(t, err) + }) + t.Run("bad signature on inner tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + innerTxCopy := *innerTx + innerTxCopy.Signature = sigBad + txCopy.InnerTransactions = []*dataTransaction.Transaction{&innerTxCopy} + txi, _ := createInterceptedTxFromPlainTxWithArgParser(&txCopy) + err := txi.CheckValidity() + assert.NotNil(t, err) + }) + t.Run("inner tx on inner tx(recursive) should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + innerTxCopy := *innerTx + txCopy.InnerTransactions = []*dataTransaction.Transaction{&innerTxCopy} + innerTx2 := &dataTransaction.Transaction{ + Nonce: 2, + Value: big.NewInt(3), + Data: []byte(""), + GasLimit: 3, + GasPrice: 4, + RcvAddr: recvAddress, + SndAddr: senderAddress, + Signature: sigOk, + ChainID: chainID, + Version: minTxVersion, + } + innerTxCopy.InnerTransactions = []*dataTransaction.Transaction{innerTx2} + txi, _ := createInterceptedTxFromPlainTxWithArgParser(&txCopy) + err := txi.CheckValidity() + assert.NotNil(t, err) + }) + t.Run("relayed v3 not enabled yet should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + innerTxCopy := *innerTx + txCopy.InnerTransactions = []*dataTransaction.Transaction{&innerTxCopy} + marshalizer := &mock.MarshalizerMock{} + txBuff, _ := marshalizer.Marshal(&txCopy) + txi, _ := transaction.NewInterceptedTransaction( + txBuff, + marshalizer, + marshalizer, + &hashingMocks.HasherMock{}, + createKeyGenMock(), + createDummySigner(), + &testscommon.PubkeyConverterStub{ + LenCalled: func() int { + return 32 + }, + }, + mock.NewMultipleShardsCoordinatorMock(), + createFreeTxFeeHandler(), + &testscommon.WhiteListHandlerStub{}, + &testscommon.ArgumentParserMock{}, + txCopy.ChainID, + false, + &hashingMocks.HasherMock{}, + versioning.NewTxVersionChecker(0), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, + ) + + assert.NotNil(t, txi) + err := txi.CheckValidity() + assert.Equal(t, process.ErrRelayedTxV3Disabled, err) + }) + t.Run("inner txs + relayed v2 should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + innerTxCopy := *innerTx + txCopy.InnerTransactions = []*dataTransaction.Transaction{&innerTxCopy} + marshaller := &marshallerMock.MarshalizerMock{} + userTxData, _ := marshaller.Marshal(innerTxCopy) + txCopy.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxData)) + txi, _ := createInterceptedTxFromPlainTxWithArgParser(&txCopy) + err := txi.CheckValidity() + assert.Equal(t, process.ErrMultipleRelayedTxTypesIsNotAllowed, err) + }) +} + // ------- IsInterfaceNil func TestInterceptedTransaction_IsInterfaceNil(t *testing.T) { t.Parallel() @@ -1621,11 +1986,13 @@ func TestInterceptedTransaction_Fee(t *testing.T) { shardCoordinator, createFreeTxFeeHandler(), &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("T"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(0), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) assert.Equal(t, big.NewInt(0), txin.Fee()) @@ -1664,11 +2031,13 @@ func TestInterceptedTransaction_String(t *testing.T) { shardCoordinator, createFreeTxFeeHandler(), &testscommon.WhiteListHandlerStub{}, - &mock.ArgumentParserMock{}, + &testscommon.ArgumentParserMock{}, []byte("T"), false, &hashingMocks.HasherMock{}, versioning.NewTxVersionChecker(0), + &enableEpochsHandlerMock.EnableEpochsHandlerStub{}, + &processMocks.RelayedTxV3ProcessorMock{}, ) expectedFormat := fmt.Sprintf( diff --git a/process/transaction/metaProcess.go b/process/transaction/metaProcess.go index d1b88a012d4..13d6fd4715b 100644 --- a/process/transaction/metaProcess.go +++ b/process/transaction/metaProcess.go @@ -20,7 +20,6 @@ var _ process.TransactionProcessor = (*metaTxProcessor)(nil) // txProcessor implements TransactionProcessor interface and can modify account states according to a transaction type metaTxProcessor struct { *baseTxProcessor - txTypeHandler process.TxTypeHandler enableEpochsHandler common.EnableEpochsHandler } @@ -66,6 +65,7 @@ func NewMetaTxProcessor(args ArgsNewMetaTxProcessor) (*metaTxProcessor, error) { err := core.CheckHandlerCompatibility(args.EnableEpochsHandler, []core.EnableEpochFlag{ common.PenalizedTooMuchGasFlag, common.ESDTFlag, + common.FixRelayedBaseCostFlag, }) if err != nil { return nil, err @@ -88,11 +88,11 @@ func NewMetaTxProcessor(args ArgsNewMetaTxProcessor) (*metaTxProcessor, error) { enableEpochsHandler: args.EnableEpochsHandler, txVersionChecker: args.TxVersionChecker, guardianChecker: args.GuardianChecker, + txTypeHandler: args.TxTypeHandler, } txProc := &metaTxProcessor{ baseTxProcessor: baseTxProcess, - txTypeHandler: args.TxTypeHandler, enableEpochsHandler: args.EnableEpochsHandler, } diff --git a/process/transaction/relayedTxV3Processor.go b/process/transaction/relayedTxV3Processor.go new file mode 100644 index 00000000000..1c25ad46214 --- /dev/null +++ b/process/transaction/relayedTxV3Processor.go @@ -0,0 +1,112 @@ +package transaction + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/multiversx/mx-chain-core-go/core/check" + "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-go/process" + "github.com/multiversx/mx-chain-go/sharding" +) + +const minTransactionsAllowed = 1 + +// ArgRelayedTxV3Processor is the DTO used to create a new instance of relayedTxV3Processor +type ArgRelayedTxV3Processor struct { + EconomicsFee process.FeeHandler + ShardCoordinator sharding.Coordinator + MaxTransactionsAllowed int +} + +type relayedTxV3Processor struct { + economicsFee process.FeeHandler + shardCoordinator sharding.Coordinator + maxTransactionsAllowed int +} + +// NewRelayedTxV3Processor returns a new instance of relayedTxV3Processor +func NewRelayedTxV3Processor(args ArgRelayedTxV3Processor) (*relayedTxV3Processor, error) { + err := checkArgs(args) + if err != nil { + return nil, err + } + return &relayedTxV3Processor{ + economicsFee: args.EconomicsFee, + shardCoordinator: args.ShardCoordinator, + maxTransactionsAllowed: args.MaxTransactionsAllowed, + }, nil +} + +func checkArgs(args ArgRelayedTxV3Processor) error { + if check.IfNil(args.EconomicsFee) { + return process.ErrNilEconomicsFeeHandler + } + if check.IfNil(args.ShardCoordinator) { + return process.ErrNilShardCoordinator + } + if args.MaxTransactionsAllowed < minTransactionsAllowed { + return fmt.Errorf("%w for MaxTransactionsAllowed, provided %d, min expected %d", process.ErrInvalidValue, args.MaxTransactionsAllowed, minTransactionsAllowed) + } + + return nil +} + +// CheckRelayedTx checks the relayed transaction and its inner transactions +func (proc *relayedTxV3Processor) CheckRelayedTx(tx *transaction.Transaction) error { + if len(tx.InnerTransactions) > proc.maxTransactionsAllowed { + return process.ErrRelayedTxV3TooManyInnerTransactions + } + if tx.GetValue().Cmp(big.NewInt(0)) != 0 { + return process.ErrRelayedTxV3ZeroVal + } + if !bytes.Equal(tx.RcvAddr, tx.SndAddr) { + return process.ErrRelayedTxV3SenderDoesNotMatchReceiver + } + if tx.GasLimit < proc.computeRelayedTxMinGasLimit(tx) { + return process.ErrRelayedTxV3GasLimitMismatch + } + if len(tx.Data) > 0 { + return process.ErrRelayedTxV3InvalidDataField + } + + innerTxs := tx.InnerTransactions + for _, innerTx := range innerTxs { + if !bytes.Equal(innerTx.RelayerAddr, tx.SndAddr) { + return process.ErrRelayedTxV3RelayerMismatch + } + if tx.GasPrice != innerTx.GasPrice { + return process.ErrRelayedV3GasPriceMismatch + } + if len(innerTx.InnerTransactions) > 0 { + return process.ErrRecursiveRelayedTxIsNotAllowed + } + + senderShard := proc.shardCoordinator.ComputeId(innerTx.SndAddr) + relayerShard := proc.shardCoordinator.ComputeId(innerTx.RelayerAddr) + if senderShard != relayerShard { + return process.ErrRelayedTxV3SenderShardMismatch + } + } + + return nil +} + +func (proc *relayedTxV3Processor) computeRelayedTxMinGasLimit(tx *transaction.Transaction) uint64 { + relayedTxGasLimit := proc.economicsFee.ComputeGasLimit(tx) + relayedTxMinGasLimit := proc.economicsFee.MinGasLimit() + relayedTxGasLimitDiff := relayedTxGasLimit - relayedTxMinGasLimit // this may be positive if the relayed tx is guarded + + totalGasLimit := relayedTxGasLimitDiff + relayedTxMinGasLimit*uint64(len(tx.InnerTransactions)) + for _, innerTx := range tx.InnerTransactions { + totalGasLimit += innerTx.GasLimit + } + + return totalGasLimit +} + +// IsInterfaceNil returns true if there is no value under the interface +func (proc *relayedTxV3Processor) IsInterfaceNil() bool { + return proc == nil +} diff --git a/process/transaction/relayedTxV3Processor_test.go b/process/transaction/relayedTxV3Processor_test.go new file mode 100644 index 00000000000..7f6495ebd92 --- /dev/null +++ b/process/transaction/relayedTxV3Processor_test.go @@ -0,0 +1,249 @@ +package transaction_test + +import ( + "bytes" + "errors" + "math/big" + "strings" + "testing" + + "github.com/multiversx/mx-chain-core-go/data" + coreTransaction "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-go/process" + "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/stretchr/testify/require" +) + +const minGasLimit = uint64(1) + +func getDefaultTx() *coreTransaction.Transaction { + return &coreTransaction.Transaction{ + Nonce: 0, + Value: big.NewInt(0), + RcvAddr: []byte("rel"), + SndAddr: []byte("rel"), + GasPrice: 1, + GasLimit: minGasLimit * 4, + InnerTransactions: []*coreTransaction.Transaction{ + { + Nonce: 0, + Value: big.NewInt(1), + RcvAddr: []byte("rcv1"), + SndAddr: []byte("snd1"), + GasPrice: 1, + GasLimit: minGasLimit, + RelayerAddr: []byte("rel"), + }, + { + Nonce: 0, + Value: big.NewInt(1), + RcvAddr: []byte("rcv1"), + SndAddr: []byte("snd2"), + GasPrice: 1, + GasLimit: minGasLimit, + RelayerAddr: []byte("rel"), + }, + }, + } +} + +func createMockArgRelayedTxV3Processor() transaction.ArgRelayedTxV3Processor { + return transaction.ArgRelayedTxV3Processor{ + EconomicsFee: &economicsmocks.EconomicsHandlerStub{}, + ShardCoordinator: &testscommon.ShardsCoordinatorMock{}, + MaxTransactionsAllowed: 10, + } +} + +func TestNewRelayedTxV3Processor(t *testing.T) { + t.Parallel() + + t.Run("nil economics fee should error", func(t *testing.T) { + t.Parallel() + + args := createMockArgRelayedTxV3Processor() + args.EconomicsFee = nil + proc, err := transaction.NewRelayedTxV3Processor(args) + require.Nil(t, proc) + require.Equal(t, process.ErrNilEconomicsFeeHandler, err) + }) + t.Run("nil shard coordinator should error", func(t *testing.T) { + t.Parallel() + + args := createMockArgRelayedTxV3Processor() + args.ShardCoordinator = nil + proc, err := transaction.NewRelayedTxV3Processor(args) + require.Nil(t, proc) + require.Equal(t, process.ErrNilShardCoordinator, err) + }) + t.Run("invalid max transactions allowed should error", func(t *testing.T) { + t.Parallel() + + args := createMockArgRelayedTxV3Processor() + args.MaxTransactionsAllowed = 0 + proc, err := transaction.NewRelayedTxV3Processor(args) + require.Nil(t, proc) + require.True(t, errors.Is(err, process.ErrInvalidValue)) + require.True(t, strings.Contains(err.Error(), "MaxTransactionsAllowed")) + }) + t.Run("should work", func(t *testing.T) { + t.Parallel() + + proc, err := transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.NoError(t, err) + require.NotNil(t, proc) + }) +} + +func TestRelayedTxV3Processor_IsInterfaceNil(t *testing.T) { + t.Parallel() + + args := createMockArgRelayedTxV3Processor() + args.EconomicsFee = nil + proc, _ := transaction.NewRelayedTxV3Processor(args) + require.True(t, proc.IsInterfaceNil()) + + proc, _ = transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.False(t, proc.IsInterfaceNil()) +} + +func TestRelayedTxV3Processor_CheckRelayedTx(t *testing.T) { + t.Parallel() + + t.Run("invalid num of inner txs should error", func(t *testing.T) { + t.Parallel() + + tx := getDefaultTx() + args := createMockArgRelayedTxV3Processor() + args.MaxTransactionsAllowed = len(tx.InnerTransactions) - 1 + proc, err := transaction.NewRelayedTxV3Processor(args) + require.NoError(t, err) + + tx.Value = big.NewInt(1) + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRelayedTxV3TooManyInnerTransactions, err) + }) + t.Run("value on relayed tx should error", func(t *testing.T) { + t.Parallel() + + proc, err := transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.NoError(t, err) + + tx := getDefaultTx() + tx.Value = big.NewInt(1) + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRelayedTxV3ZeroVal, err) + }) + t.Run("relayed tx not to self should error", func(t *testing.T) { + t.Parallel() + + proc, err := transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.NoError(t, err) + + tx := getDefaultTx() + tx.RcvAddr = []byte("another rcv") + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRelayedTxV3SenderDoesNotMatchReceiver, err) + }) + t.Run("invalid gas limit should error", func(t *testing.T) { + t.Parallel() + + args := createMockArgRelayedTxV3Processor() + args.EconomicsFee = &economicsmocks.EconomicsHandlerStub{ + ComputeGasLimitCalled: func(tx data.TransactionWithFeeHandler) uint64 { + return minGasLimit + }, + } + proc, err := transaction.NewRelayedTxV3Processor(args) + require.NoError(t, err) + + tx := getDefaultTx() + tx.GasLimit = minGasLimit + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRelayedTxV3GasLimitMismatch, err) + }) + t.Run("data field not empty should error", func(t *testing.T) { + t.Parallel() + + proc, err := transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.NoError(t, err) + + tx := getDefaultTx() + tx.Data = []byte("dummy") + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRelayedTxV3InvalidDataField, err) + }) + t.Run("inner txs on inner should error", func(t *testing.T) { + t.Parallel() + + proc, err := transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.NoError(t, err) + + tx := getDefaultTx() + tx.InnerTransactions[0].InnerTransactions = []*coreTransaction.Transaction{{}} + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRecursiveRelayedTxIsNotAllowed, err) + }) + t.Run("relayer mismatch on inner should error", func(t *testing.T) { + t.Parallel() + + proc, err := transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.NoError(t, err) + + tx := getDefaultTx() + tx.InnerTransactions[0].RelayerAddr = []byte("another relayer") + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRelayedTxV3RelayerMismatch, err) + }) + t.Run("gas price mismatch on inner should error", func(t *testing.T) { + t.Parallel() + + proc, err := transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.NoError(t, err) + + tx := getDefaultTx() + tx.InnerTransactions[0].GasPrice = tx.GasPrice + 1 + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRelayedV3GasPriceMismatch, err) + }) + t.Run("shard mismatch on inner should error", func(t *testing.T) { + t.Parallel() + + tx := getDefaultTx() + args := createMockArgRelayedTxV3Processor() + args.ShardCoordinator = &testscommon.ShardsCoordinatorMock{ + ComputeIdCalled: func(address []byte) uint32 { + if bytes.Equal(address, tx.SndAddr) { + return 0 + } + + return 1 + }, + } + proc, err := transaction.NewRelayedTxV3Processor(args) + require.NoError(t, err) + + err = proc.CheckRelayedTx(tx) + require.Equal(t, process.ErrRelayedTxV3SenderShardMismatch, err) + }) + t.Run("should work", func(t *testing.T) { + t.Parallel() + + proc, err := transaction.NewRelayedTxV3Processor(createMockArgRelayedTxV3Processor()) + require.NoError(t, err) + + tx := getDefaultTx() + err = proc.CheckRelayedTx(tx) + require.NoError(t, err) + }) +} diff --git a/process/transaction/shardProcess.go b/process/transaction/shardProcess.go index 89b3572397b..129ad2c5db8 100644 --- a/process/transaction/shardProcess.go +++ b/process/transaction/shardProcess.go @@ -15,12 +15,13 @@ import ( "github.com/multiversx/mx-chain-core-go/data/vm" "github.com/multiversx/mx-chain-core-go/hashing" "github.com/multiversx/mx-chain-core-go/marshal" + logger "github.com/multiversx/mx-chain-logger-go" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "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" - logger "github.com/multiversx/mx-chain-logger-go" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" ) var log = logger.GetOrCreate("process/transaction") @@ -37,38 +38,41 @@ type relayedFees struct { // txProcessor implements TransactionProcessor interface and can modify account states according to a transaction type txProcessor struct { *baseTxProcessor - txFeeHandler process.TransactionFeeHandler - txTypeHandler process.TxTypeHandler - receiptForwarder process.IntermediateTransactionHandler - badTxForwarder process.IntermediateTransactionHandler - argsParser process.ArgumentsParser - scrForwarder process.IntermediateTransactionHandler - signMarshalizer marshal.Marshalizer - enableEpochsHandler common.EnableEpochsHandler - txLogsProcessor process.TransactionLogProcessor + txFeeHandler process.TransactionFeeHandler + receiptForwarder process.IntermediateTransactionHandler + badTxForwarder process.IntermediateTransactionHandler + argsParser process.ArgumentsParser + scrForwarder process.IntermediateTransactionHandler + signMarshalizer marshal.Marshalizer + enableEpochsHandler common.EnableEpochsHandler + txLogsProcessor process.TransactionLogProcessor + relayedTxV3Processor process.RelayedTxV3Processor + failedTxLogsAccumulator process.FailedTxLogsAccumulator } // ArgsNewTxProcessor defines the arguments needed for new tx processor type ArgsNewTxProcessor struct { - Accounts state.AccountsAdapter - Hasher hashing.Hasher - PubkeyConv core.PubkeyConverter - Marshalizer marshal.Marshalizer - SignMarshalizer marshal.Marshalizer - ShardCoordinator sharding.Coordinator - ScProcessor process.SmartContractProcessor - TxFeeHandler process.TransactionFeeHandler - TxTypeHandler process.TxTypeHandler - EconomicsFee process.FeeHandler - ReceiptForwarder process.IntermediateTransactionHandler - BadTxForwarder process.IntermediateTransactionHandler - ArgsParser process.ArgumentsParser - ScrForwarder process.IntermediateTransactionHandler - EnableRoundsHandler process.EnableRoundsHandler - EnableEpochsHandler common.EnableEpochsHandler - TxVersionChecker process.TxVersionCheckerHandler - GuardianChecker process.GuardianChecker - TxLogsProcessor process.TransactionLogProcessor + Accounts state.AccountsAdapter + Hasher hashing.Hasher + PubkeyConv core.PubkeyConverter + Marshalizer marshal.Marshalizer + SignMarshalizer marshal.Marshalizer + ShardCoordinator sharding.Coordinator + ScProcessor process.SmartContractProcessor + TxFeeHandler process.TransactionFeeHandler + TxTypeHandler process.TxTypeHandler + EconomicsFee process.FeeHandler + ReceiptForwarder process.IntermediateTransactionHandler + BadTxForwarder process.IntermediateTransactionHandler + ArgsParser process.ArgumentsParser + ScrForwarder process.IntermediateTransactionHandler + EnableRoundsHandler process.EnableRoundsHandler + EnableEpochsHandler common.EnableEpochsHandler + TxVersionChecker process.TxVersionCheckerHandler + GuardianChecker process.GuardianChecker + TxLogsProcessor process.TransactionLogProcessor + RelayedTxV3Processor process.RelayedTxV3Processor + FailedTxLogsAccumulator process.FailedTxLogsAccumulator } // NewTxProcessor creates a new txProcessor engine @@ -128,6 +132,8 @@ func NewTxProcessor(args ArgsNewTxProcessor) (*txProcessor, error) { common.RelayedTransactionsFlag, common.RelayedTransactionsV2Flag, common.RelayedNonceFixFlag, + common.RelayedTransactionsV3Flag, + common.FixRelayedBaseCostFlag, }) if err != nil { return nil, err @@ -141,6 +147,12 @@ func NewTxProcessor(args ArgsNewTxProcessor) (*txProcessor, error) { if check.IfNil(args.TxLogsProcessor) { return nil, process.ErrNilTxLogsProcessor } + if check.IfNil(args.RelayedTxV3Processor) { + return nil, process.ErrNilRelayedTxV3Processor + } + if check.IfNil(args.FailedTxLogsAccumulator) { + return nil, process.ErrNilFailedTxLogsAccumulator + } baseTxProcess := &baseTxProcessor{ accounts: args.Accounts, @@ -153,19 +165,21 @@ func NewTxProcessor(args ArgsNewTxProcessor) (*txProcessor, error) { enableEpochsHandler: args.EnableEpochsHandler, txVersionChecker: args.TxVersionChecker, guardianChecker: args.GuardianChecker, + txTypeHandler: args.TxTypeHandler, } txProc := &txProcessor{ - baseTxProcessor: baseTxProcess, - txFeeHandler: args.TxFeeHandler, - txTypeHandler: args.TxTypeHandler, - receiptForwarder: args.ReceiptForwarder, - badTxForwarder: args.BadTxForwarder, - argsParser: args.ArgsParser, - scrForwarder: args.ScrForwarder, - signMarshalizer: args.SignMarshalizer, - enableEpochsHandler: args.EnableEpochsHandler, - txLogsProcessor: args.TxLogsProcessor, + baseTxProcessor: baseTxProcess, + txFeeHandler: args.TxFeeHandler, + receiptForwarder: args.ReceiptForwarder, + badTxForwarder: args.BadTxForwarder, + argsParser: args.ArgsParser, + scrForwarder: args.ScrForwarder, + signMarshalizer: args.SignMarshalizer, + enableEpochsHandler: args.EnableEpochsHandler, + txLogsProcessor: args.TxLogsProcessor, + relayedTxV3Processor: args.RelayedTxV3Processor, + failedTxLogsAccumulator: args.FailedTxLogsAccumulator, } return txProc, nil @@ -239,6 +253,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, acntSnd) } return vmcommon.UserError, txProc.executingFailedTransaction(tx, acntSnd, process.ErrWrongTransaction) @@ -274,7 +290,7 @@ func (txProc *txProcessor) executeAfterFailedMoveBalanceTransaction( return nil } - err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}) + err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}, txHash) if err != nil { return err } @@ -300,13 +316,13 @@ func (txProc *txProcessor) executingFailedTransaction( return err } - acntSnd.IncreaseNonce(1) - err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}) + txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) if err != nil { return err } - txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) + acntSnd.IncreaseNonce(1) + err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{tx}, txHash) if err != nil { return err } @@ -320,7 +336,7 @@ func (txProc *txProcessor) executingFailedTransaction( TxHash: txHash, } - err = txProc.receiptForwarder.AddIntermediateTransactions([]data.TransactionHandler{rpt}) + err = txProc.receiptForwarder.AddIntermediateTransactions([]data.TransactionHandler{rpt}, txHash) if err != nil { return err } @@ -366,7 +382,7 @@ func (txProc *txProcessor) createReceiptWithReturnedGas( TxHash: txHash, } - err := txProc.receiptForwarder.AddIntermediateTransactions([]data.TransactionHandler{rpt}) + err := txProc.receiptForwarder.AddIntermediateTransactions([]data.TransactionHandler{rpt}, txHash) if err != nil { return err } @@ -385,7 +401,8 @@ func (txProc *txProcessor) processTxFee( } if isUserTxOfRelayed { - totalCost := txProc.economicsFee.ComputeFeeForProcessing(tx, tx.GasLimit) + totalCost := txProc.computeInnerTxFee(tx) + err := acntSnd.SubFromBalance(totalCost) if err != nil { return nil, nil, err @@ -397,6 +414,10 @@ func (txProc *txProcessor) processTxFee( moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(tx) currentShardFee := txProc.economicsFee.ComputeFeeForProcessing(tx, moveBalanceGasLimit) + if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedBaseCostFlag) { + currentShardFee = txProc.economicsFee.ComputeMoveBalanceFee(tx) + } + return currentShardFee, totalCost, nil } @@ -558,8 +579,8 @@ func (txProc *txProcessor) finishExecutionOfRelayedTx( tx *transaction.Transaction, userTx *transaction.Transaction, ) (vmcommon.ReturnCode, error) { - computedFees := txProc.computeRelayedTxFees(tx) - txHash, err := txProc.processTxAtRelayer(relayerAcnt, computedFees.totalFee, computedFees.relayerFee, tx) + computedFees := txProc.computeRelayedTxFees(tx, userTx) + err := txProc.processTxAtRelayer(relayerAcnt, computedFees.totalFee, computedFees.relayerFee, tx) if err != nil { return 0, err } @@ -568,12 +589,31 @@ func (txProc *txProcessor) finishExecutionOfRelayedTx( return vmcommon.Ok, nil } - err = txProc.addFeeAndValueToDest(acntDst, tx, computedFees.remainingFee) + err = txProc.addFeeAndValueToDest(acntDst, tx.Value, computedFees.remainingFee) if err != nil { return 0, err } - return txProc.processUserTx(tx, userTx, tx.Value, tx.Nonce, txHash) + originalTxHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) + if err != nil { + errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, tx.Value, originalTxHash, tx, err) + if errRemove != nil { + return vmcommon.UserError, errRemove + } + + return vmcommon.UserError, txProc.executeFailedRelayedUserTx( + userTx, + tx.SndAddr, + tx.Value, + tx.Nonce, + tx, + originalTxHash, + err.Error()) + } + + defer txProc.saveFailedLogsIfNeeded(originalTxHash) + + return txProc.processUserTx(tx, userTx, tx.Value, tx.Nonce, originalTxHash) } func (txProc *txProcessor) processTxAtRelayer( @@ -581,37 +621,37 @@ func (txProc *txProcessor) processTxAtRelayer( totalFee *big.Int, relayerFee *big.Int, tx *transaction.Transaction, -) ([]byte, error) { - txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) - if err != nil { - return nil, err - } - +) error { if !check.IfNil(relayerAcnt) { - err = relayerAcnt.SubFromBalance(tx.GetValue()) + err := relayerAcnt.SubFromBalance(tx.GetValue()) if err != nil { - return nil, err + return err } err = relayerAcnt.SubFromBalance(totalFee) if err != nil { - return nil, err + return err } relayerAcnt.IncreaseNonce(1) err = txProc.accounts.SaveAccount(relayerAcnt) if err != nil { - return nil, err + return err + } + + txHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) + if err != nil { + return err } txProc.txFeeHandler.ProcessTransactionFee(relayerFee, big.NewInt(0), txHash) } - return txHash, nil + return nil } -func (txProc *txProcessor) addFeeAndValueToDest(acntDst state.UserAccountHandler, tx *transaction.Transaction, remainingFee *big.Int) error { - err := acntDst.AddToBalance(tx.GetValue()) +func (txProc *txProcessor) addFeeAndValueToDest(acntDst state.UserAccountHandler, txValue *big.Int, remainingFee *big.Int) error { + err := acntDst.AddToBalance(txValue) if err != nil { return err } @@ -624,6 +664,128 @@ func (txProc *txProcessor) addFeeAndValueToDest(acntDst state.UserAccountHandler return txProc.accounts.SaveAccount(acntDst) } +func (txProc *txProcessor) processRelayedTxV3( + tx *transaction.Transaction, + relayerAcnt state.UserAccountHandler, +) (vmcommon.ReturnCode, error) { + if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsV3Flag) { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxV3Disabled) + } + if check.IfNil(relayerAcnt) { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrNilRelayerAccount) + } + err := txProc.relayedTxV3Processor.CheckRelayedTx(tx) + if err != nil { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, err) + } + + snapshot := txProc.accounts.JournalLen() + + // process fees on both relayer and sender + relayerFee, totalFee, err := txProc.economicsFee.ComputeRelayedTxFees(tx) + if err != nil { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, err) + } + + err = txProc.processTxAtRelayer(relayerAcnt, totalFee, relayerFee, tx) + if err != nil { + return 0, err + } + + innerTxs := tx.GetInnerTransactions() + + originalTxHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, tx) + if err != nil { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, err) + } + + var innerTxRetCode vmcommon.ReturnCode + var innerTxErr error + var innerTxFee *big.Int + innerTxsTotalFees := big.NewInt(0) + executedUserTxs := make([]*transaction.Transaction, 0) + for _, innerTx := range innerTxs { + innerTxFee, innerTxRetCode, innerTxErr = txProc.processInnerTx(tx, innerTx, originalTxHash) + innerTxsTotalFees.Add(innerTxsTotalFees, innerTxFee) + if innerTxErr != nil || innerTxRetCode != vmcommon.Ok { + continue + } + + executedUserTxs = append(executedUserTxs, innerTx) + } + + allUserTxsSucceeded := len(executedUserTxs) == len(innerTxs) && innerTxErr == nil && innerTxRetCode == vmcommon.Ok + if !allUserTxsSucceeded { + log.Trace("failed to execute all inner transactions", "total", len(innerTxs), "executed transactions", len(executedUserTxs)) + + txProc.saveFailedLogsIfNeeded(originalTxHash) + } + + expectedMaxInnerTxsTotalFees := big.NewInt(0).Sub(totalFee, relayerFee) + if innerTxsTotalFees.Cmp(expectedMaxInnerTxsTotalFees) > 0 { + log.Debug("reverting relayed transaction, total inner transactions fees mismatch", + "computed max fees at relayer", expectedMaxInnerTxsTotalFees.Uint64(), + "total inner fees consumed", innerTxsTotalFees.Uint64()) + + errRevert := txProc.accounts.RevertToSnapshot(snapshot) + if errRevert != nil { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, errRevert) + } + + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrConsumedFeesMismatch) + } + + return vmcommon.Ok, nil +} + +func (txProc *txProcessor) processInnerTx( + tx *transaction.Transaction, + innerTx *transaction.Transaction, + originalTxHash []byte, +) (*big.Int, vmcommon.ReturnCode, error) { + + txFee := txProc.computeInnerTxFee(innerTx) + + acntSnd, err := txProc.getAccountFromAddress(innerTx.SndAddr) + if err != nil { + return txFee, vmcommon.UserError, txProc.executeFailedRelayedUserTx( + innerTx, + innerTx.RelayerAddr, + big.NewInt(0), + tx.Nonce, + tx, + originalTxHash, + err.Error()) + } + + if check.IfNil(acntSnd) { + return txFee, vmcommon.UserError, txProc.executeFailedRelayedUserTx( + innerTx, + innerTx.RelayerAddr, + big.NewInt(0), + tx.Nonce, + tx, + originalTxHash, + process.ErrRelayedTxV3SenderShardMismatch.Error()) + } + + // TODO: remove adding and then removing the fee at the sender + err = txProc.addFeeAndValueToDest(acntSnd, big.NewInt(0), txFee) + if err != nil { + return txFee, vmcommon.UserError, txProc.executeFailedRelayedUserTx( + innerTx, + innerTx.RelayerAddr, + big.NewInt(0), + tx.Nonce, + tx, + originalTxHash, + err.Error()) + } + + result, err := txProc.processUserTx(tx, innerTx, tx.Value, tx.Nonce, originalTxHash) + return txFee, result, err +} + func (txProc *txProcessor) processRelayedTxV2( tx *transaction.Transaction, relayerAcnt, acntDst state.UserAccountHandler, @@ -643,6 +805,10 @@ func (txProc *txProcessor) processRelayedTxV2( return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrInvalidArguments) } + if len(tx.InnerTransactions) > 0 { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrMultipleRelayedTxTypesIsNotAllowed) + } + userTx := makeUserTxFromRelayedTxV2Args(args) userTx.GasPrice = tx.GasPrice userTx.GasLimit = tx.GasLimit - txProc.economicsFee.ComputeGasLimit(tx) @@ -666,6 +832,9 @@ func (txProc *txProcessor) processRelayedTx( if !txProc.enableEpochsHandler.IsFlagEnabled(common.RelayedTransactionsFlag) { return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrRelayedTxDisabled) } + if len(tx.InnerTransactions) > 0 { + return vmcommon.UserError, txProc.executingFailedTransaction(tx, relayerAcnt, process.ErrMultipleRelayedTxTypesIsNotAllowed) + } userTx := &transaction.Transaction{} err = txProc.signMarshalizer.Unmarshal(userTx, args[0]) @@ -691,9 +860,14 @@ func (txProc *txProcessor) processRelayedTx( return txProc.finishExecutionOfRelayedTx(relayerAcnt, acntDst, tx, userTx) } -func (txProc *txProcessor) computeRelayedTxFees(tx *transaction.Transaction) 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) + + totalFee = totalFee.Add(relayerFee, userFee) + } remainingFee := big.NewInt(0).Sub(totalFee, relayerFee) computedFees := relayedFees{ @@ -724,7 +898,8 @@ func (txProc *txProcessor) removeValueAndConsumedFeeFromUser( return err } - consumedFee := txProc.economicsFee.ComputeFeeForProcessing(userTx, userTx.GasLimit) + consumedFee := txProc.computeInnerTxFee(userTx) + err = userAcnt.SubFromBalance(consumedFee) if err != nil { return err @@ -757,7 +932,8 @@ func (txProc *txProcessor) addNonExecutableLog(executionErr error, originalTxHas Address: originalTx.GetRcvAddr(), } - return txProc.txLogsProcessor.SaveLog(originalTxHash, originalTx, []*vmcommon.LogEntry{logEntry}) + return txProc.failedTxLogsAccumulator.SaveLogs(originalTxHash, originalTx, []*vmcommon.LogEntry{logEntry}) + } func (txProc *txProcessor) processMoveBalanceCostRelayedUserTx( @@ -768,6 +944,9 @@ func (txProc *txProcessor) processMoveBalanceCostRelayedUserTx( ) error { moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(userTx) moveBalanceUserFee := txProc.economicsFee.ComputeFeeForProcessing(userTx, moveBalanceGasLimit) + if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedBaseCostFlag) { + moveBalanceUserFee = txProc.economicsFee.ComputeMoveBalanceFee(userTx) + } userScrHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, userScr) if err != nil { @@ -783,21 +962,26 @@ func (txProc *txProcessor) processUserTx( userTx *transaction.Transaction, relayedTxValue *big.Int, relayedNonce uint64, - txHash []byte, + originalTxHash []byte, ) (vmcommon.ReturnCode, error) { + relayerAdr := originalTx.SndAddr acntSnd, acntDst, err := txProc.getAccounts(userTx.SndAddr, userTx.RcvAddr) if err != nil { - return 0, err - } - - var originalTxHash []byte - originalTxHash, err = core.CalculateHash(txProc.marshalizer, txProc.hasher, originalTx) - if err != nil { - return 0, err + errRemove := txProc.removeValueAndConsumedFeeFromUser(userTx, relayedTxValue, originalTxHash, originalTx, err) + if errRemove != nil { + return vmcommon.UserError, errRemove + } + return vmcommon.UserError, txProc.executeFailedRelayedUserTx( + userTx, + relayerAdr, + relayedTxValue, + relayedNonce, + originalTx, + originalTxHash, + err.Error()) } - relayerAdr := originalTx.SndAddr txType, dstShardTxType := txProc.txTypeHandler.ComputeTransactionType(userTx) err = txProc.checkTxValues(userTx, acntSnd, acntDst, true) if err != nil { @@ -811,11 +995,11 @@ func (txProc *txProcessor) processUserTx( relayedTxValue, relayedNonce, originalTx, - txHash, + originalTxHash, err.Error()) } - scrFromTx, err := txProc.makeSCRFromUserTx(userTx, relayerAdr, relayedTxValue, txHash) + scrFromTx, err := txProc.makeSCRFromUserTx(userTx, relayerAdr, relayedTxValue, originalTxHash) if err != nil { return 0, err } @@ -824,6 +1008,10 @@ func (txProc *txProcessor) processUserTx( switch txType { case process.MoveBalance: err = txProc.processMoveBalance(userTx, acntSnd, acntDst, dstShardTxType, originalTxHash, true) + intraShard := txProc.shardCoordinator.SameShard(userTx.SndAddr, userTx.RcvAddr) + if err == nil && intraShard { + txProc.createCompleteEventLog(scrFromTx, originalTxHash) + } case process.SCDeployment: err = txProc.processMoveBalanceCostRelayedUserTx(userTx, scrFromTx, acntSnd, originalTxHash) if err != nil { @@ -857,7 +1045,7 @@ func (txProc *txProcessor) processUserTx( relayedTxValue, relayedNonce, originalTx, - txHash, + originalTxHash, err.Error()) } @@ -868,7 +1056,7 @@ func (txProc *txProcessor) processUserTx( relayedTxValue, relayedNonce, originalTx, - txHash, + originalTxHash, err.Error()) } @@ -890,7 +1078,7 @@ func (txProc *txProcessor) processUserTx( return returnCode, nil } - err = txProc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrFromTx}) + err = txProc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrFromTx}, originalTxHash) if err != nil { return 0, err } @@ -963,17 +1151,28 @@ func (txProc *txProcessor) executeFailedRelayedUserTx( return err } - err = txProc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrForRelayer}) + err = txProc.scrForwarder.AddIntermediateTransactions([]data.TransactionHandler{scrForRelayer}, originalTxHash) if err != nil { return err } totalFee := txProc.economicsFee.ComputeFeeForProcessing(userTx, userTx.GasLimit) + moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(userTx) + gasToUse := userTx.GetGasLimit() - moveBalanceGasLimit + processingUserFee := txProc.economicsFee.ComputeFeeForProcessing(userTx, gasToUse) + if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedBaseCostFlag) { + moveBalanceUserFee := txProc.economicsFee.ComputeMoveBalanceFee(userTx) + totalFee = big.NewInt(0).Add(moveBalanceUserFee, processingUserFee) + } + senderShardID := txProc.shardCoordinator.ComputeId(userTx.SndAddr) if senderShardID != txProc.shardCoordinator.SelfId() { - moveBalanceGasLimit := txProc.economicsFee.ComputeGasLimit(userTx) - moveBalanceUserFee := txProc.economicsFee.ComputeFeeForProcessing(userTx, moveBalanceGasLimit) - totalFee.Sub(totalFee, moveBalanceUserFee) + if txProc.enableEpochsHandler.IsFlagEnabled(common.FixRelayedBaseCostFlag) { + totalFee.Sub(totalFee, processingUserFee) + } else { + moveBalanceUserFee := txProc.economicsFee.ComputeFeeForProcessing(userTx, moveBalanceGasLimit) + totalFee.Sub(totalFee, moveBalanceUserFee) + } } txProc.txFeeHandler.ProcessTransactionFee(totalFee, big.NewInt(0), originalTxHash) @@ -984,8 +1183,8 @@ func (txProc *txProcessor) executeFailedRelayedUserTx( return err } - if txProc.enableEpochsHandler.IsFlagEnabled(common.AddFailedRelayedTxToInvalidMBsFlag) { - err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{originalTx}) + if txProc.enableEpochsHandler.IsFlagEnabled(common.AddFailedRelayedTxToInvalidMBsFlag) && !isRelayedV3(originalTx.InnerTransactions) { + err = txProc.badTxForwarder.AddIntermediateTransactions([]data.TransactionHandler{originalTx}, originalTxHash) if err != nil { return err } @@ -1018,6 +1217,36 @@ func isNonExecutableError(executionErr error) bool { errors.Is(executionErr, process.ErrTransactionNotExecutable) } +func (txProc *txProcessor) createCompleteEventLog(scr data.TransactionHandler, originalTxHash []byte) { + scrHash, err := core.CalculateHash(txProc.marshalizer, txProc.hasher, scr) + if err != nil { + scrHash = originalTxHash + } + + completedTxLog := &vmcommon.LogEntry{ + Identifier: []byte(core.CompletedTxEventIdentifier), + Address: scr.GetRcvAddr(), + Topics: [][]byte{scrHash}, + } + + ignorableError := txProc.txLogsProcessor.SaveLog(scrHash, scr, []*vmcommon.LogEntry{completedTxLog}) + if ignorableError != nil { + log.Debug("txProcessor.createCompleteEventLog txLogsProcessor.SaveLog()", "error", ignorableError.Error()) + } +} + +func (txProc *txProcessor) saveFailedLogsIfNeeded(originalTxHash []byte) { + logsTx, logs, ok := txProc.failedTxLogsAccumulator.GetLogs(originalTxHash) + if ok { + ignorableErr := txProc.txLogsProcessor.SaveLog(originalTxHash, logsTx, logs) + if ignorableErr != nil { + log.Debug("txLogsProcessor.SaveLog failed", "error", ignorableErr.Error()) + } + } + + txProc.failedTxLogsAccumulator.Remove(originalTxHash) +} + // IsInterfaceNil returns true if there is no value under the interface func (txProc *txProcessor) IsInterfaceNil() bool { return txProc == nil diff --git a/process/transaction/shardProcess_test.go b/process/transaction/shardProcess_test.go index b79b8b21ffc..1f077525ae2 100644 --- a/process/transaction/shardProcess_test.go +++ b/process/transaction/shardProcess_test.go @@ -13,6 +13,12 @@ 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" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" + "github.com/multiversx/mx-chain-vm-common-go/parsers" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/multiversx/mx-chain-go/common" "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/coordinator" @@ -26,14 +32,13 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/enableEpochsHandlerMock" "github.com/multiversx/mx-chain-go/testscommon/guardianMocks" "github.com/multiversx/mx-chain-go/testscommon/hashingMocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" "github.com/multiversx/mx-chain-go/vm" - vmcommon "github.com/multiversx/mx-chain-vm-common-go" - "github.com/multiversx/mx-chain-vm-common-go/builtInFunctions" - "github.com/multiversx/mx-chain-vm-common-go/parsers" - "github.com/stretchr/testify/assert" ) +var txHash = []byte("hash") + func generateRandomByteSlice(size int) []byte { buff := make([]byte, size) _, _ = rand.Reader.Read(buff) @@ -74,25 +79,27 @@ func createAccountStub(sndAddr, rcvAddr []byte, func createArgsForTxProcessor() txproc.ArgsNewTxProcessor { args := txproc.ArgsNewTxProcessor{ - Accounts: &stateMock.AccountsStub{}, - Hasher: &hashingMocks.HasherMock{}, - PubkeyConv: createMockPubKeyConverter(), - Marshalizer: &mock.MarshalizerMock{}, - SignMarshalizer: &mock.MarshalizerMock{}, - ShardCoordinator: mock.NewOneShardCoordinatorMock(), - ScProcessor: &testscommon.SCProcessorMock{}, - TxFeeHandler: &mock.FeeAccumulatorStub{}, - TxTypeHandler: &testscommon.TxTypeHandlerMock{}, - EconomicsFee: feeHandlerMock(), - ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, - BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, - ArgsParser: &mock.ArgumentParserMock{}, - ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, - EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.PenalizedTooMuchGasFlag), - GuardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, - TxVersionChecker: &testscommon.TxVersionCheckerStub{}, - TxLogsProcessor: &mock.TxLogsProcessorStub{}, - EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, + Accounts: &stateMock.AccountsStub{}, + Hasher: &hashingMocks.HasherMock{}, + PubkeyConv: createMockPubKeyConverter(), + Marshalizer: &mock.MarshalizerMock{}, + SignMarshalizer: &mock.MarshalizerMock{}, + ShardCoordinator: mock.NewOneShardCoordinatorMock(), + ScProcessor: &testscommon.SCProcessorMock{}, + TxFeeHandler: &mock.FeeAccumulatorStub{}, + TxTypeHandler: &testscommon.TxTypeHandlerMock{}, + EconomicsFee: feeHandlerMock(), + ReceiptForwarder: &mock.IntermediateTransactionHandlerMock{}, + BadTxForwarder: &mock.IntermediateTransactionHandlerMock{}, + ArgsParser: &testscommon.ArgumentParserMock{}, + ScrForwarder: &mock.IntermediateTransactionHandlerMock{}, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.PenalizedTooMuchGasFlag, common.FixRelayedBaseCostFlag), + GuardianChecker: &guardianMocks.GuardedAccountHandlerStub{}, + TxVersionChecker: &testscommon.TxVersionCheckerStub{}, + TxLogsProcessor: &mock.TxLogsProcessorStub{}, + EnableRoundsHandler: &testscommon.EnableRoundsHandlerStub{}, + RelayedTxV3Processor: &processMocks.RelayedTxV3ProcessorMock{}, + FailedTxLogsAccumulator: &processMocks.FailedTxLogsAccumulatorMock{}, } return args } @@ -102,7 +109,7 @@ func createTxProcessor() txproc.TxProcessor { return txProc } -//------- NewTxProcessor +// ------- NewTxProcessor func TestNewTxProcessor_NilAccountsShouldErr(t *testing.T) { t.Parallel() @@ -302,6 +309,50 @@ func TestNewTxProcessor_NilEnableRoundsHandlerShouldErr(t *testing.T) { assert.Nil(t, txProc) } +func TestNewTxProcessor_NilTxVersionCheckerShouldErr(t *testing.T) { + t.Parallel() + + args := createArgsForTxProcessor() + args.TxVersionChecker = nil + txProc, err := txproc.NewTxProcessor(args) + + assert.Equal(t, process.ErrNilTransactionVersionChecker, err) + assert.Nil(t, txProc) +} + +func TestNewTxProcessor_NilGuardianCheckerShouldErr(t *testing.T) { + t.Parallel() + + args := createArgsForTxProcessor() + args.GuardianChecker = nil + txProc, err := txproc.NewTxProcessor(args) + + assert.Equal(t, process.ErrNilGuardianChecker, err) + assert.Nil(t, txProc) +} + +func TestNewTxProcessor_NilRelayedTxV3ProcessorShouldErr(t *testing.T) { + t.Parallel() + + args := createArgsForTxProcessor() + args.RelayedTxV3Processor = nil + txProc, err := txproc.NewTxProcessor(args) + + assert.Equal(t, process.ErrNilRelayedTxV3Processor, err) + assert.Nil(t, txProc) +} + +func TestNewTxProcessor_NilFailedTxLogsAccumulatorShouldErr(t *testing.T) { + t.Parallel() + + args := createArgsForTxProcessor() + args.FailedTxLogsAccumulator = nil + txProc, err := txproc.NewTxProcessor(args) + + assert.Equal(t, process.ErrNilFailedTxLogsAccumulator, err) + assert.Nil(t, txProc) +} + func TestNewTxProcessor_OkValsShouldWork(t *testing.T) { t.Parallel() @@ -312,7 +363,7 @@ func TestNewTxProcessor_OkValsShouldWork(t *testing.T) { assert.NotNil(t, txProc) } -//------- getAccounts +// ------- getAccounts func TestTxProcessor_GetAccountsShouldErrNilAddressContainer(t *testing.T) { t.Parallel() @@ -479,7 +530,7 @@ func TestTxProcessor_GetSameAccountShouldWork(t *testing.T) { assert.True(t, a1 == a2) } -//------- checkTxValues +// ------- checkTxValues func TestTxProcessor_CheckTxValuesHigherNonceShouldErr(t *testing.T) { t.Parallel() @@ -602,7 +653,7 @@ func TestTxProcessor_CheckTxValuesOkValsShouldErr(t *testing.T) { assert.Nil(t, err) } -//------- increaseNonce +// ------- increaseNonce func TestTxProcessor_IncreaseNonceOkValsShouldWork(t *testing.T) { t.Parallel() @@ -618,7 +669,7 @@ func TestTxProcessor_IncreaseNonceOkValsShouldWork(t *testing.T) { assert.Equal(t, uint64(46), acntSrc.GetNonce()) } -//------- ProcessTransaction +// ------- ProcessTransaction func TestTxProcessor_ProcessTransactionNilTxShouldErr(t *testing.T) { t.Parallel() @@ -651,7 +702,7 @@ func TestTxProcessor_ProcessTransactionMalfunctionAccountsShouldErr(t *testing.T func TestTxProcessor_ProcessCheckNotPassShouldErr(t *testing.T) { t.Parallel() - //these values will trigger ErrHigherNonceInTransaction + // these values will trigger ErrHigherNonceInTransaction tx := transaction.Transaction{} tx.Nonce = 1 tx.SndAddr = []byte("SRC") @@ -1464,8 +1515,8 @@ func TestTxProcessor_ProcessTxFeeMoveBalanceUserTx(t *testing.T) { cost, totalCost, err := execTx.ProcessTxFee(tx, acntSnd, nil, process.MoveBalance, true) assert.Nil(t, err) - assert.True(t, cost.Cmp(processingFee) == 0) - assert.True(t, totalCost.Cmp(processingFee) == 0) + assert.True(t, cost.Cmp(moveBalanceFee) == 0) + assert.True(t, totalCost.Cmp(moveBalanceFee) == 0) } func TestTxProcessor_ProcessTxFeeSCInvokeUserTx(t *testing.T) { @@ -1476,6 +1527,7 @@ func TestTxProcessor_ProcessTxFeeSCInvokeUserTx(t *testing.T) { negMoveBalanceFee := big.NewInt(0).Neg(moveBalanceFee) gasPerByte := uint64(1) args := createArgsForTxProcessor() + args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.PenalizedTooMuchGasFlag) args.EconomicsFee = &economicsmocks.EconomicsHandlerStub{ ComputeMoveBalanceFeeCalled: func(tx data.TransactionWithFeeHandler) *big.Int { return moveBalanceFee @@ -1834,7 +1886,7 @@ func TestTxProcessor_ProcessRelayedTransactionV2ArgsParserShouldErr(t *testing.T parseError := errors.New("parse error") args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return "", nil, parseError }} @@ -2013,6 +2065,530 @@ func TestTxProcessor_ProcessRelayedTransactionV2(t *testing.T) { assert.Equal(t, vmcommon.Ok, returnCode) } +func TestTxProcessor_ProcessRelayedTransactionV3(t *testing.T) { + t.Parallel() + + marshaller := &mock.MarshalizerMock{} + + userAddr := []byte("user") + tx := &transaction.Transaction{} + tx.Nonce = 0 + tx.SndAddr = []byte("sSRC") + tx.RcvAddr = []byte("sSRC") + tx.Value = big.NewInt(0) + tx.GasPrice = 1 + tx.GasLimit = 8 + + userTx := &transaction.Transaction{} + userTx.Nonce = 0 + userTx.SndAddr = userAddr + userTx.RcvAddr = []byte("sDST") + userTx.Value = big.NewInt(0) + userTx.Data = []byte("execute@param1") + userTx.GasPrice = 1 + userTx.GasLimit = 4 + userTx.RelayerAddr = tx.SndAddr + + tx.InnerTransactions = []*transaction.Transaction{userTx} + + t.Run("flag not active should error", func(t *testing.T) { + t.Parallel() + + pubKeyConverter := testscommon.NewPubkeyConverterMock(4) + acntSrc := createUserAcc(tx.SndAddr) + _ = acntSrc.AddToBalance(big.NewInt(100)) + acntDst := createUserAcc(tx.RcvAddr) + _ = acntDst.AddToBalance(big.NewInt(10)) + + acntFinal := createUserAcc(userTx.RcvAddr) + _ = acntFinal.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, userTx.RcvAddr) { + return acntFinal, nil + } + + return nil, errors.New("failure") + } + + scProcessorMock := &testscommon.SCProcessorMock{} + shardC, _ := sharding.NewMultiShardCoordinator(1, 0) + esdtTransferParser, _ := parsers.NewESDTTransferParser(marshaller) + argTxTypeHandler := coordinator.ArgNewTxTypeHandler{ + PubkeyConverter: pubKeyConverter, + ShardCoordinator: shardC, + BuiltInFunctions: builtInFunctions.NewBuiltInFunctionContainer(), + ArgumentParser: parsers.NewCallArgsParser(), + ESDTTransferParser: esdtTransferParser, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.ESDTMetadataContinuousCleanupFlag), + } + 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.EnableEpochsHandlerStub{} + execTx, _ := txproc.NewTxProcessor(args) + + returnCode, err := execTx.ProcessTransaction(tx) + assert.Equal(t, process.ErrFailedTransaction, err) + assert.Equal(t, vmcommon.UserError, returnCode) + }) + t.Run("value on parent tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + txCopy.Value = big.NewInt(1) + testProcessRelayedTransactionV3(t, &txCopy, userTx.SndAddr, userTx.RcvAddr, process.ErrFailedTransaction, vmcommon.UserError) + }) + t.Run("different receiver on tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + txCopy.RcvAddr = userTx.SndAddr + testProcessRelayedTransactionV3(t, &txCopy, userTx.SndAddr, userTx.RcvAddr, process.ErrFailedTransaction, vmcommon.UserError) + }) + t.Run("empty relayer on inner tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + userTxCopy := *userTx + userTxCopy.RelayerAddr = nil + txCopy.InnerTransactions = []*transaction.Transaction{&userTxCopy} + testProcessRelayedTransactionV3(t, &txCopy, userTx.SndAddr, userTx.RcvAddr, process.ErrFailedTransaction, vmcommon.UserError) + }) + t.Run("different relayer on inner tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + userTxCopy := *userTx + userTxCopy.RelayerAddr = []byte("other") + txCopy.InnerTransactions = []*transaction.Transaction{&userTxCopy} + testProcessRelayedTransactionV3(t, &txCopy, userTx.SndAddr, userTx.RcvAddr, process.ErrFailedTransaction, vmcommon.UserError) + }) + t.Run("different gas price on inner tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + txCopy.GasPrice = userTx.GasPrice + 1 + testProcessRelayedTransactionV3(t, &txCopy, userTx.SndAddr, userTx.RcvAddr, process.ErrFailedTransaction, vmcommon.UserError) + }) + t.Run("higher gas limit on inner tx should error", func(t *testing.T) { + t.Parallel() + + txCopy := *tx + txCopy.GasLimit = userTx.GasLimit - 1 + testProcessRelayedTransactionV3(t, &txCopy, userTx.SndAddr, userTx.RcvAddr, process.ErrFailedTransaction, vmcommon.UserError) + }) + t.Run("failure to add fees on destination should skip transaction and continue", func(t *testing.T) { + t.Parallel() + + providedAddrFail := []byte("fail addr") + providedInitialBalance := big.NewInt(100) + pubKeyConverter := testscommon.NewPubkeyConverterMock(4) + + accounts := map[string]state.UserAccountHandler{} + adb := &stateMock.AccountsStub{} + adb.LoadAccountCalled = func(address []byte) (vmcommon.AccountHandler, error) { + if bytes.Equal(address, providedAddrFail) { + return &stateMock.UserAccountStub{ + AddToBalanceCalled: func(value *big.Int) error { + return errors.New("won't add to balance") + }, + }, nil + } + + acnt, exists := accounts[string(address)] + if !exists { + acnt = createUserAcc(address) + accounts[string(address)] = acnt + _ = acnt.AddToBalance(providedInitialBalance) + } + + return acnt, nil + } + + scProcessorMock := &testscommon.SCProcessorMock{} + shardC, _ := sharding.NewMultiShardCoordinator(1, 0) + esdtTransferParser, _ := parsers.NewESDTTransferParser(marshaller) + argTxTypeHandler := coordinator.ArgNewTxTypeHandler{ + PubkeyConverter: pubKeyConverter, + ShardCoordinator: shardC, + BuiltInFunctions: builtInFunctions.NewBuiltInFunctionContainer(), + ArgumentParser: parsers.NewCallArgsParser(), + ESDTTransferParser: esdtTransferParser, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.ESDTMetadataContinuousCleanupFlag), + } + 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, common.FixRelayedBaseCostFlag) + args.EconomicsFee = &economicsmocks.EconomicsHandlerStub{ + ComputeMoveBalanceFeeCalled: func(tx data.TransactionWithFeeHandler) *big.Int { + return big.NewInt(1) + }, + ComputeRelayedTxFeesCalled: func(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) { + relayerFee := big.NewInt(0).SetInt64(int64(len(tx.GetUserTransactions()))) // gasPrice = 1 + totalFee := *relayerFee + for _, innerTx := range tx.GetUserTransactions() { + totalFee.Add(&totalFee, big.NewInt(0).SetUint64(innerTx.GetGasLimit())) + } + + return relayerFee, &totalFee, nil + }, + } + args.RelayedTxV3Processor, _ = txproc.NewRelayedTxV3Processor(txproc.ArgRelayedTxV3Processor{ + EconomicsFee: args.EconomicsFee, + ShardCoordinator: args.ShardCoordinator, + MaxTransactionsAllowed: 10, + }) + logs := make([]*vmcommon.LogEntry, 0) + args.TxLogsProcessor = &mock.TxLogsProcessorStub{ + SaveLogCalled: func(txHash []byte, tx data.TransactionHandler, vmLogs []*vmcommon.LogEntry) error { + logs = append(logs, vmLogs...) + return nil + }, + } + execTx, _ := txproc.NewTxProcessor(args) + + txCopy := *tx + innerTx1 := &transaction.Transaction{ + Nonce: 0, + Value: big.NewInt(10), + RcvAddr: []byte("sDST"), + SndAddr: []byte("sender inner tx 1"), + GasPrice: 1, + GasLimit: 1, + RelayerAddr: txCopy.SndAddr, + } + innerTx2 := &transaction.Transaction{ + Nonce: 0, + Value: big.NewInt(10), + RcvAddr: []byte("sDST"), + SndAddr: []byte("sender inner tx 2"), + GasPrice: 1, + GasLimit: 1, + RelayerAddr: txCopy.SndAddr, + } + innerTx3 := &transaction.Transaction{ + Nonce: 0, + Value: big.NewInt(10), + RcvAddr: []byte("sDST"), + SndAddr: providedAddrFail, + GasPrice: 1, + GasLimit: 1, + RelayerAddr: txCopy.SndAddr, + } + + txCopy.InnerTransactions = []*transaction.Transaction{innerTx1, innerTx2, innerTx3} + returnCode, err := execTx.ProcessTransaction(&txCopy) + assert.NoError(t, err) + assert.Equal(t, vmcommon.Ok, returnCode) + + expectedBalance := providedInitialBalance + for _, acnt := range accounts { + switch string(acnt.AddressBytes()) { + case "sSRC": + continue // relayer + case "sDST": + expectedBalance = big.NewInt(120) // 2 successful txs received + case "sender inner tx 1", "sender inner tx 2": + expectedBalance = big.NewInt(90) // one successful tx sent from each + default: + assert.Fail(t, "should not be other participants") + } + + assert.Equal(t, expectedBalance, acnt.GetBalance(), fmt.Sprintf("checks failed for address: %s", string(acnt.AddressBytes()))) + } + + require.Equal(t, 2, len(logs)) + for _, log := range logs { + require.Equal(t, core.CompletedTxEventIdentifier, string(log.Identifier)) + } + }) + t.Run("one inner fails should return success on relayed", func(t *testing.T) { + t.Parallel() + + providedInitialBalance := big.NewInt(100) + pubKeyConverter := testscommon.NewPubkeyConverterMock(4) + + accounts := map[string]state.UserAccountHandler{} + adb := &stateMock.AccountsStub{} + adb.LoadAccountCalled = func(address []byte) (vmcommon.AccountHandler, error) { + acnt, exists := accounts[string(address)] + if !exists { + acnt = createUserAcc(address) + accounts[string(address)] = acnt + _ = acnt.AddToBalance(providedInitialBalance) + } + + return acnt, nil + } + + scProcessorMock := &testscommon.SCProcessorMock{} + shardC, _ := sharding.NewMultiShardCoordinator(1, 0) + esdtTransferParser, _ := parsers.NewESDTTransferParser(marshaller) + argTxTypeHandler := coordinator.ArgNewTxTypeHandler{ + PubkeyConverter: pubKeyConverter, + ShardCoordinator: shardC, + BuiltInFunctions: builtInFunctions.NewBuiltInFunctionContainer(), + ArgumentParser: parsers.NewCallArgsParser(), + ESDTTransferParser: esdtTransferParser, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.ESDTMetadataContinuousCleanupFlag), + } + 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, common.FixRelayedBaseCostFlag) + args.EconomicsFee = &economicsmocks.EconomicsHandlerStub{ + ComputeMoveBalanceFeeCalled: func(tx data.TransactionWithFeeHandler) *big.Int { + return big.NewInt(int64(tx.GetGasPrice() * tx.GetGasLimit())) + }, + ComputeRelayedTxFeesCalled: func(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) { + relayerFee := big.NewInt(0).SetInt64(int64(len(tx.GetUserTransactions()))) // gasPrice = 1 + totalFee := *relayerFee + for _, innerTx := range tx.GetUserTransactions() { + totalFee.Add(&totalFee, big.NewInt(0).SetUint64(innerTx.GetGasLimit())) + } + + return relayerFee, &totalFee, nil + }, + } + args.RelayedTxV3Processor, _ = txproc.NewRelayedTxV3Processor(txproc.ArgRelayedTxV3Processor{ + EconomicsFee: args.EconomicsFee, + ShardCoordinator: args.ShardCoordinator, + MaxTransactionsAllowed: 10, + }) + wasGetLogsCalled := false + wasRemoveCalled := false + args.FailedTxLogsAccumulator = &processMocks.FailedTxLogsAccumulatorMock{ + GetLogsCalled: func(txHash []byte) (data.TransactionHandler, []*vmcommon.LogEntry, bool) { + wasGetLogsCalled = true + + return &smartContractResult.SmartContractResult{}, []*vmcommon.LogEntry{}, true + }, + RemoveCalled: func(txHash []byte) { + wasRemoveCalled = true + }, + } + execTx, _ := txproc.NewTxProcessor(args) + + txCopy := *tx + usertTxCopy := *userTx // same inner tx twice should fail second time + txCopy.InnerTransactions = append(txCopy.InnerTransactions, &usertTxCopy) + returnCode, err := execTx.ProcessTransaction(&txCopy) + assert.NoError(t, err) + assert.Equal(t, vmcommon.Ok, returnCode) + assert.True(t, wasGetLogsCalled) + assert.True(t, wasRemoveCalled) + }) + t.Run("fees consumed mismatch should error", func(t *testing.T) { + t.Parallel() + + providedInitialBalance := big.NewInt(100) + pubKeyConverter := testscommon.NewPubkeyConverterMock(4) + + accounts := map[string]state.UserAccountHandler{} + adb := &stateMock.AccountsStub{} + adb.LoadAccountCalled = func(address []byte) (vmcommon.AccountHandler, error) { + acnt, exists := accounts[string(address)] + if !exists { + acnt = createUserAcc(address) + accounts[string(address)] = acnt + _ = acnt.AddToBalance(providedInitialBalance) + } + + return acnt, nil + } + wasRevertToSnapshotCalled := false + adb.RevertToSnapshotCalled = func(snapshot int) error { + wasRevertToSnapshotCalled = true + return nil + } + + scProcessorMock := &testscommon.SCProcessorMock{} + shardC, _ := sharding.NewMultiShardCoordinator(1, 0) + esdtTransferParser, _ := parsers.NewESDTTransferParser(marshaller) + argTxTypeHandler := coordinator.ArgNewTxTypeHandler{ + PubkeyConverter: pubKeyConverter, + ShardCoordinator: shardC, + BuiltInFunctions: builtInFunctions.NewBuiltInFunctionContainer(), + ArgumentParser: parsers.NewCallArgsParser(), + ESDTTransferParser: esdtTransferParser, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.ESDTMetadataContinuousCleanupFlag), + } + 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, common.FixRelayedBaseCostFlag) + increasingFee := big.NewInt(0) + args.EconomicsFee = &economicsmocks.EconomicsHandlerStub{ + ComputeMoveBalanceFeeCalled: func(tx data.TransactionWithFeeHandler) *big.Int { + increasingFee.Add(increasingFee, big.NewInt(1)) + return increasingFee + }, + } + args.RelayedTxV3Processor, _ = txproc.NewRelayedTxV3Processor(txproc.ArgRelayedTxV3Processor{ + EconomicsFee: args.EconomicsFee, + ShardCoordinator: args.ShardCoordinator, + MaxTransactionsAllowed: 10, + }) + execTx, _ := txproc.NewTxProcessor(args) + + txCopy := *tx + innerTx1 := &transaction.Transaction{ + Nonce: 0, + Value: big.NewInt(10), + RcvAddr: []byte("sDST"), + SndAddr: []byte("sender inner tx 1"), + GasPrice: 1, + GasLimit: 1, + RelayerAddr: txCopy.SndAddr, + } + innerTx2 := &transaction.Transaction{ + Nonce: 0, + Value: big.NewInt(10), + RcvAddr: []byte("sDST"), + SndAddr: []byte("sender inner tx 2"), + GasPrice: 1, + GasLimit: 1, + RelayerAddr: txCopy.SndAddr, + } + + txCopy.InnerTransactions = []*transaction.Transaction{innerTx1, innerTx2} + returnCode, err := execTx.ProcessTransaction(&txCopy) + assert.Error(t, err) + assert.Equal(t, vmcommon.UserError, returnCode) + assert.True(t, wasRevertToSnapshotCalled) + }) + t.Run("should work", func(t *testing.T) { + t.Parallel() + testProcessRelayedTransactionV3(t, tx, userTx.SndAddr, userTx.RcvAddr, nil, vmcommon.Ok) + }) +} + +func testProcessRelayedTransactionV3( + t *testing.T, + tx *transaction.Transaction, + innerSender []byte, + finalRcvr []byte, + expectedErr error, + expectedCode vmcommon.ReturnCode, +) { + pubKeyConverter := testscommon.NewPubkeyConverterMock(4) + marshaller := &mock.MarshalizerMock{} + + acntSrc := createUserAcc(tx.SndAddr) + _ = acntSrc.AddToBalance(big.NewInt(100)) + acntDst := createUserAcc(tx.RcvAddr) + _ = acntDst.AddToBalance(big.NewInt(10)) + + acntFinal := createUserAcc(finalRcvr) + _ = acntFinal.AddToBalance(big.NewInt(10)) + acntInnerSender := createUserAcc(innerSender) + _ = acntInnerSender.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, finalRcvr) { + return acntFinal, nil + } + if bytes.Equal(address, innerSender) { + return acntInnerSender, nil + } + + return nil, errors.New("failure") + } + + scProcessorMock := &testscommon.SCProcessorMock{} + shardC, _ := sharding.NewMultiShardCoordinator(1, 0) + esdtTransferParser, _ := parsers.NewESDTTransferParser(marshaller) + argTxTypeHandler := coordinator.ArgNewTxTypeHandler{ + PubkeyConverter: pubKeyConverter, + ShardCoordinator: shardC, + BuiltInFunctions: builtInFunctions.NewBuiltInFunctionContainer(), + ArgumentParser: parsers.NewCallArgsParser(), + ESDTTransferParser: esdtTransferParser, + EnableEpochsHandler: enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.ESDTMetadataContinuousCleanupFlag), + } + 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, common.FixRelayedBaseCostFlag) + args.EconomicsFee = &economicsmocks.EconomicsHandlerMock{ + ComputeTxFeeCalled: func(tx data.TransactionWithFeeHandler) *big.Int { + return big.NewInt(4) + }, + ComputeMoveBalanceFeeCalled: func(tx data.TransactionWithFeeHandler) *big.Int { + return big.NewInt(4) + }, + ComputeGasLimitCalled: func(tx data.TransactionWithFeeHandler) uint64 { + return 4 + }, + ComputeRelayedTxFeesCalled: func(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) { + relayerFee := big.NewInt(0).SetInt64(int64(len(tx.GetUserTransactions()))) // gasPrice = 1 + totalFee := *relayerFee + for _, innerTx := range tx.GetUserTransactions() { + totalFee.Add(&totalFee, big.NewInt(0).SetUint64(innerTx.GetGasLimit())) + } + + return relayerFee, &totalFee, nil + }, + } + args.RelayedTxV3Processor, _ = txproc.NewRelayedTxV3Processor(txproc.ArgRelayedTxV3Processor{ + EconomicsFee: args.EconomicsFee, + ShardCoordinator: args.ShardCoordinator, + MaxTransactionsAllowed: 10, + }) + + execTx, _ := txproc.NewTxProcessor(args) + + returnCode, err := execTx.ProcessTransaction(tx) + assert.Equal(t, expectedErr, err) + assert.Equal(t, expectedCode, returnCode) +} + func TestTxProcessor_ProcessRelayedTransaction(t *testing.T) { t.Parallel() @@ -2126,7 +2702,7 @@ func TestTxProcessor_ProcessRelayedTransactionArgsParserErrorShouldError(t *test parseError := errors.New("parse error") args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return "", nil, parseError }} @@ -2189,7 +2765,7 @@ func TestTxProcessor_ProcessRelayedTransactionMultipleArgumentsShouldError(t *te tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{[]byte("0"), []byte("1")}, nil }} @@ -2252,7 +2828,7 @@ func TestTxProcessor_ProcessRelayedTransactionFailUnMarshalInnerShouldError(t *t tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{[]byte("0")}, nil }} @@ -2315,7 +2891,7 @@ func TestTxProcessor_ProcessRelayedTransactionDifferentSenderInInnerTxThanReceiv tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2378,7 +2954,7 @@ func TestTxProcessor_ProcessRelayedTransactionSmallerValueInnerTxShouldError(t * tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2441,7 +3017,7 @@ func TestTxProcessor_ProcessRelayedTransactionGasPriceMismatchShouldError(t *tes tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2504,7 +3080,7 @@ func TestTxProcessor_ProcessRelayedTransactionGasLimitMismatchShouldError(t *tes tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2612,7 +3188,7 @@ func TestTxProcessor_ProcessRelayedTransactionDisabled(t *testing.T) { args.ArgsParser = smartContract.NewArgumentParser() called := false args.BadTxForwarder = &mock.IntermediateTransactionHandlerMock{ - AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler) error { + AddIntermediateTransactionsCalled: func(txs []data.TransactionHandler, key []byte) error { called = true return nil }, @@ -2629,13 +3205,14 @@ func TestTxProcessor_ConsumeMoveBalanceWithUserTx(t *testing.T) { t.Parallel() args := createArgsForTxProcessor() + args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub() args.EconomicsFee = &economicsmocks.EconomicsHandlerStub{ - ComputeFeeForProcessingCalled: func(tx data.TransactionWithFeeHandler, gasToUse uint64) *big.Int { - return big.NewInt(1) - }, ComputeTxFeeCalled: func(tx data.TransactionWithFeeHandler) *big.Int { return big.NewInt(150) }, + ComputeFeeForProcessingCalled: func(tx data.TransactionWithFeeHandler, gasToUse uint64) *big.Int { + return big.NewInt(1) + }, } args.TxFeeHandler = &mock.FeeAccumulatorStub{ ProcessTransactionFeeCalled: func(cost *big.Int, devFee *big.Int, hash []byte) { @@ -2657,7 +3234,7 @@ func TestTxProcessor_ConsumeMoveBalanceWithUserTx(t *testing.T) { err := execTx.ProcessMoveBalanceCostRelayedUserTx(userTx, &smartContractResult.SmartContractResult{}, acntSrc, originalTxHash) assert.Nil(t, err) - assert.Equal(t, acntSrc.GetBalance(), big.NewInt(99)) + assert.Equal(t, big.NewInt(99), acntSrc.GetBalance()) } func TestTxProcessor_IsCrossTxFromMeShouldWork(t *testing.T) { @@ -2699,7 +3276,7 @@ func TestTxProcessor_ProcessUserTxOfTypeRelayedShouldError(t *testing.T) { tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2732,7 +3309,6 @@ func TestTxProcessor_ProcessUserTxOfTypeRelayedShouldError(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - txHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, tx) returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.UserError, returnCode) @@ -2763,7 +3339,7 @@ func TestTxProcessor_ProcessUserTxOfTypeMoveBalanceShouldWork(t *testing.T) { tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2796,7 +3372,6 @@ func TestTxProcessor_ProcessUserTxOfTypeMoveBalanceShouldWork(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - txHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, tx) returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.Ok, returnCode) @@ -2827,7 +3402,7 @@ func TestTxProcessor_ProcessUserTxOfTypeSCDeploymentShouldWork(t *testing.T) { tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2860,7 +3435,6 @@ func TestTxProcessor_ProcessUserTxOfTypeSCDeploymentShouldWork(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - txHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, tx) returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.Ok, returnCode) @@ -2891,7 +3465,7 @@ func TestTxProcessor_ProcessUserTxOfTypeSCInvokingShouldWork(t *testing.T) { tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2924,7 +3498,6 @@ func TestTxProcessor_ProcessUserTxOfTypeSCInvokingShouldWork(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - txHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, tx) returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.Ok, returnCode) @@ -2955,7 +3528,7 @@ func TestTxProcessor_ProcessUserTxOfTypeBuiltInFunctionCallShouldWork(t *testing tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -2988,7 +3561,6 @@ func TestTxProcessor_ProcessUserTxOfTypeBuiltInFunctionCallShouldWork(t *testing execTx, _ := txproc.NewTxProcessor(args) - txHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, tx) returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.Ok, returnCode) @@ -3019,7 +3591,7 @@ func TestTxProcessor_ProcessUserTxErrNotPayableShouldFailRelayTx(t *testing.T) { tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -3056,7 +3628,6 @@ func TestTxProcessor_ProcessUserTxErrNotPayableShouldFailRelayTx(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - txHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, tx) returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.UserError, returnCode) @@ -3087,7 +3658,7 @@ func TestTxProcessor_ProcessUserTxFailedBuiltInFunctionCall(t *testing.T) { tx.Data = []byte(core.RelayedTransaction + "@" + hex.EncodeToString(userTxMarshalled)) args := createArgsForTxProcessor() - args.ArgsParser = &mock.ArgumentParserMock{ + args.ArgsParser = &testscommon.ArgumentParserMock{ ParseCallDataCalled: func(data string) (string, [][]byte, error) { return core.RelayedTransaction, [][]byte{userTxMarshalled}, nil }} @@ -3126,7 +3697,6 @@ func TestTxProcessor_ProcessUserTxFailedBuiltInFunctionCall(t *testing.T) { execTx, _ := txproc.NewTxProcessor(args) - txHash, _ := core.CalculateHash(args.Marshalizer, args.Hasher, tx) returnCode, err := execTx.ProcessUserTx(&tx, &userTx, tx.Value, tx.Nonce, txHash) assert.Nil(t, err) assert.Equal(t, vmcommon.ExecutionFailed, returnCode) @@ -3212,7 +3782,7 @@ func TestTxProcessor_shouldIncreaseNonce(t *testing.T) { t.Run("fix not enabled, should return true", func(t *testing.T) { args := createArgsForTxProcessor() - args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub() + args.EnableEpochsHandler = enableEpochsHandlerMock.NewEnableEpochsHandlerStub(common.RelayedNonceFixFlag) txProc, _ := txproc.NewTxProcessor(args) assert.True(t, txProc.ShouldIncreaseNonce(nil)) @@ -3276,12 +3846,12 @@ func TestTxProcessor_AddNonExecutableLog(t *testing.T) { originalTxHash, err := core.CalculateHash(args.Marshalizer, args.Hasher, originalTx) assert.Nil(t, err) numLogsSaved := 0 - args.TxLogsProcessor = &mock.TxLogsProcessorStub{ - SaveLogCalled: func(txHash []byte, tx data.TransactionHandler, vmLogs []*vmcommon.LogEntry) error { + args.FailedTxLogsAccumulator = &processMocks.FailedTxLogsAccumulatorMock{ + SaveLogsCalled: func(txHash []byte, tx data.TransactionHandler, logs []*vmcommon.LogEntry) error { assert.Equal(t, originalTxHash, txHash) assert.Equal(t, originalTx, tx) - assert.Equal(t, 1, len(vmLogs)) - firstLog := vmLogs[0] + assert.Equal(t, 1, len(logs)) + firstLog := logs[0] assert.Equal(t, core.SignalErrorOperation, string(firstLog.Identifier)) assert.Equal(t, sender, firstLog.Address) assert.Empty(t, firstLog.Data) @@ -3305,3 +3875,15 @@ func TestTxProcessor_AddNonExecutableLog(t *testing.T) { assert.Equal(t, 3, numLogsSaved) }) } + +func TestTxProcessor_IsInterfaceNil(t *testing.T) { + t.Parallel() + + args := createArgsForTxProcessor() + args.RelayedTxV3Processor = nil + proc, _ := txproc.NewTxProcessor(args) + require.True(t, proc.IsInterfaceNil()) + + proc, _ = txproc.NewTxProcessor(createArgsForTxProcessor()) + require.False(t, proc.IsInterfaceNil()) +} diff --git a/process/transactionEvaluator/transactionEvaluator.go b/process/transactionEvaluator/transactionEvaluator.go index 9e61d138419..032aeefdc80 100644 --- a/process/transactionEvaluator/transactionEvaluator.go +++ b/process/transactionEvaluator/transactionEvaluator.go @@ -119,7 +119,7 @@ func (ate *apiTransactionEvaluator) ComputeTransactionGasLimit(tx *transaction.T switch txTypeOnSender { case process.SCDeployment, process.SCInvoking, process.BuiltInFunctionCall, process.MoveBalance: return ate.simulateTransactionCost(tx, txTypeOnSender) - case process.RelayedTx, process.RelayedTxV2: + case process.RelayedTx, process.RelayedTxV2, process.RelayedTxV3: // TODO implement in the next PR return &transaction.CostResponse{ GasUnits: 0, diff --git a/process/transactionLog/failedTxLogsAccumulator.go b/process/transactionLog/failedTxLogsAccumulator.go new file mode 100644 index 00000000000..a0d973541bc --- /dev/null +++ b/process/transactionLog/failedTxLogsAccumulator.go @@ -0,0 +1,109 @@ +package transactionLog + +import ( + "sync" + + "github.com/multiversx/mx-chain-core-go/core/check" + "github.com/multiversx/mx-chain-core-go/data" + "github.com/multiversx/mx-chain-go/process" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" +) + +type logData struct { + tx data.TransactionHandler + logs []*vmcommon.LogEntry +} + +type failedTxLogsAccumulator struct { + mut sync.RWMutex + logsMap map[string]*logData +} + +// NewFailedTxLogsAccumulator returns a new instance of failedTxLogsAccumulator +func NewFailedTxLogsAccumulator() *failedTxLogsAccumulator { + return &failedTxLogsAccumulator{ + logsMap: make(map[string]*logData), + } +} + +// GetLogs returns the accumulated logs for the provided txHash +func (accumulator *failedTxLogsAccumulator) GetLogs(txHash []byte) (data.TransactionHandler, []*vmcommon.LogEntry, bool) { + if len(txHash) == 0 { + return nil, nil, false + } + + logsData, found := accumulator.getLogDataCopy(txHash) + + if !found { + return nil, nil, found + } + + return logsData.tx, logsData.logs, found +} + +func (accumulator *failedTxLogsAccumulator) getLogDataCopy(txHash []byte) (logData, bool) { + accumulator.mut.RLock() + defer accumulator.mut.RUnlock() + + logsData, found := accumulator.logsMap[string(txHash)] + if !found { + return logData{}, found + } + + logsDataCopy := logData{ + tx: logsData.tx, + } + + logsDataCopy.logs = append(logsDataCopy.logs, logsData.logs...) + + return logsDataCopy, found +} + +// SaveLogs saves the logs into the internal map +func (accumulator *failedTxLogsAccumulator) SaveLogs(txHash []byte, tx data.TransactionHandler, logs []*vmcommon.LogEntry) error { + if len(txHash) == 0 { + return process.ErrNilTxHash + } + + if check.IfNil(tx) { + return process.ErrNilTransaction + } + + if len(logs) == 0 { + return nil + } + + accumulator.mut.Lock() + defer accumulator.mut.Unlock() + + _, found := accumulator.logsMap[string(txHash)] + if !found { + accumulator.logsMap[string(txHash)] = &logData{ + tx: tx, + logs: logs, + } + + return nil + } + + accumulator.logsMap[string(txHash)].logs = append(accumulator.logsMap[string(txHash)].logs, logs...) + + return nil +} + +// Remove removes the accumulated logs for the provided txHash +func (accumulator *failedTxLogsAccumulator) Remove(txHash []byte) { + if len(txHash) == 0 { + return + } + + accumulator.mut.Lock() + defer accumulator.mut.Unlock() + + delete(accumulator.logsMap, string(txHash)) +} + +// IsInterfaceNil returns true if there is no value under the interface +func (accumulator *failedTxLogsAccumulator) IsInterfaceNil() bool { + return accumulator == nil +} diff --git a/process/transactionLog/failedTxLogsAccumulator_test.go b/process/transactionLog/failedTxLogsAccumulator_test.go new file mode 100644 index 00000000000..691f4b41ffa --- /dev/null +++ b/process/transactionLog/failedTxLogsAccumulator_test.go @@ -0,0 +1,168 @@ +package transactionLog + +import ( + "fmt" + "sync" + "testing" + + "github.com/multiversx/mx-chain-core-go/data/transaction" + "github.com/multiversx/mx-chain-go/process" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" + "github.com/stretchr/testify/require" +) + +var ( + providedHash = []byte("hash") + providedTx = &transaction.Transaction{Nonce: 123} + providedLogs = []*vmcommon.LogEntry{ + { + Identifier: []byte("identifier"), + Address: []byte("addr"), + Topics: [][]byte{[]byte("topic")}, + Data: [][]byte{[]byte("data")}, + }, + } +) + +func TestNewFailedTxLogsAccumulator(t *testing.T) { + t.Parallel() + + accumulator := NewFailedTxLogsAccumulator() + require.NotNil(t, accumulator) +} + +func TestFailedTxLogsAccumulator_IsInterfaceNil(t *testing.T) { + t.Parallel() + + var accumulator *failedTxLogsAccumulator + require.True(t, accumulator.IsInterfaceNil()) + + accumulator = NewFailedTxLogsAccumulator() + require.False(t, accumulator.IsInterfaceNil()) +} + +func TestFailedTxLogsAccumulator_GetLogs(t *testing.T) { + t.Parallel() + + accumulator := NewFailedTxLogsAccumulator() + tx, logs, ok := accumulator.GetLogs([]byte("")) + require.False(t, ok) + require.Nil(t, tx) + require.Nil(t, logs) + + err := accumulator.SaveLogs(providedHash, providedTx, providedLogs) + require.NoError(t, err) + + tx, logs, ok = accumulator.GetLogs([]byte("missing hash")) + require.False(t, ok) + require.Nil(t, tx) + require.Nil(t, logs) + + tx, logs, ok = accumulator.GetLogs(providedHash) + require.True(t, ok) + require.Equal(t, providedTx, tx) + require.Equal(t, providedLogs, logs) +} + +func TestFailedTxLogsAccumulator_SaveLogs(t *testing.T) { + t.Parallel() + + t.Run("empty hash should error", func(t *testing.T) { + t.Parallel() + + accumulator := NewFailedTxLogsAccumulator() + err := accumulator.SaveLogs([]byte(""), nil, nil) + require.Equal(t, process.ErrNilTxHash, err) + }) + t.Run("nil tx should error", func(t *testing.T) { + t.Parallel() + + accumulator := NewFailedTxLogsAccumulator() + err := accumulator.SaveLogs(providedHash, nil, nil) + require.Equal(t, process.ErrNilTransaction, err) + }) + t.Run("empty logs should return nil", func(t *testing.T) { + t.Parallel() + + accumulator := NewFailedTxLogsAccumulator() + err := accumulator.SaveLogs(providedHash, providedTx, nil) + require.NoError(t, err) + }) + t.Run("should work and append logs", func(t *testing.T) { + t.Parallel() + + accumulator := NewFailedTxLogsAccumulator() + err := accumulator.SaveLogs(providedHash, providedTx, providedLogs) + require.NoError(t, err) + + providedNewLogs := []*vmcommon.LogEntry{ + { + Identifier: []byte("identifier 2"), + Address: []byte("addr"), + Topics: [][]byte{[]byte("topic 2")}, + Data: [][]byte{[]byte("data 2")}, + }, + } + err = accumulator.SaveLogs(providedHash, providedTx, providedNewLogs) + require.NoError(t, err) + + expectedLogs := append(providedLogs, providedNewLogs...) + receivedTx, receivedLogs, ok := accumulator.GetLogs(providedHash) + require.True(t, ok) + require.Equal(t, providedTx, receivedTx) + require.Equal(t, expectedLogs, receivedLogs) + }) +} + +func TestFailedTxLogsAccumulator_Remove(t *testing.T) { + t.Parallel() + + accumulator := NewFailedTxLogsAccumulator() + err := accumulator.SaveLogs(providedHash, providedTx, providedLogs) + require.NoError(t, err) + _, _, ok := accumulator.GetLogs(providedHash) + require.True(t, ok) + + accumulator.Remove([]byte("")) // coverage only + + accumulator.Remove(providedHash) + _, _, ok = accumulator.GetLogs(providedHash) + require.False(t, ok) +} + +func TestTxLogProcessor_ConcurrentOperations(t *testing.T) { + t.Parallel() + + require.NotPanics(t, func() { + accumulator := NewFailedTxLogsAccumulator() + + numCalls := 1000 + wg := sync.WaitGroup{} + wg.Add(numCalls) + + for i := 0; i < numCalls; i++ { + go func(idx int) { + switch idx % 3 { + case 0: + err := accumulator.SaveLogs(providedHash, providedTx, []*vmcommon.LogEntry{ + { + Identifier: []byte(fmt.Sprintf("identifier %d", idx)), + Address: []byte("addr"), + Topics: [][]byte{[]byte(fmt.Sprintf("topic %d", idx))}, + Data: [][]byte{[]byte(fmt.Sprintf("data %d", idx))}, + }, + }) + require.NoError(t, err) + case 1: + _, _, _ = accumulator.GetLogs(providedHash) + case 2: + accumulator.Remove(providedHash) + } + + wg.Done() + }(i) + } + + wg.Wait() + }) +} diff --git a/process/transactionLog/printTxLogProcessor_test.go b/process/transactionLog/printTxLogProcessor_test.go index 5074ec617a4..c442440afb9 100644 --- a/process/transactionLog/printTxLogProcessor_test.go +++ b/process/transactionLog/printTxLogProcessor_test.go @@ -65,9 +65,6 @@ func TestPrintTxLogProcessor_SaveLog(t *testing.T) { err := ptlp.SaveLog([]byte("hash"), &transaction.Transaction{}, txLogEntry) require.Nil(t, err) - err = ptlp.SaveLog([]byte("hash"), &transaction.Transaction{}, nil) - require.Nil(t, err) - require.True(t, strings.Contains(buff.String(), "printTxLogProcessor.SaveLog")) require.True(t, strings.Contains(buff.String(), "printTxLogProcessor.entry")) } diff --git a/process/transactionLog/process.go b/process/transactionLog/process.go index 76a44294cd2..39b74f4b02a 100644 --- a/process/transactionLog/process.go +++ b/process/transactionLog/process.go @@ -36,7 +36,7 @@ type txLogProcessor struct { } // NewTxLogProcessor creates a transaction log processor capable of parsing logs from the VM -// and saving them into the injected storage +// and saving them into the injected storage func NewTxLogProcessor(args ArgTxLogProcessor) (*txLogProcessor, error) { storer := args.Storer if check.IfNil(storer) && args.SaveInStorageEnabled { @@ -179,7 +179,6 @@ func (tlp *txLogProcessor) saveLogToCache(txHash []byte, log *transaction.Log) { }) tlp.logsIndices[string(txHash)] = len(tlp.logs) - 1 tlp.mut.Unlock() - } // For SC deployment transactions, we use the sender address diff --git a/process/transactionLog/process_test.go b/process/transactionLog/process_test.go index f132c865486..c4f58322056 100644 --- a/process/transactionLog/process_test.go +++ b/process/transactionLog/process_test.go @@ -8,6 +8,7 @@ import ( "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/mock" "github.com/multiversx/mx-chain-go/process/transactionLog" + "github.com/multiversx/mx-chain-go/testscommon" storageStubs "github.com/multiversx/mx-chain-go/testscommon/storage" vmcommon "github.com/multiversx/mx-chain-vm-common-go" "github.com/stretchr/testify/require" @@ -88,7 +89,7 @@ func TestTxLogProcessor_SaveLogsMarshalErr(t *testing.T) { retErr := errors.New("marshal err") txLogProcessor, _ := transactionLog.NewTxLogProcessor(transactionLog.ArgTxLogProcessor{ Storer: &storageStubs.StorerStub{}, - Marshalizer: &mock.MarshalizerStub{ + Marshalizer: &testscommon.MarshallerStub{ MarshalCalled: func(obj interface{}) (bytes []byte, err error) { return nil, retErr }, @@ -111,7 +112,7 @@ func TestTxLogProcessor_SaveLogsStoreErr(t *testing.T) { return retErr }, }, - Marshalizer: &mock.MarshalizerStub{ + Marshalizer: &testscommon.MarshallerStub{ MarshalCalled: func(obj interface{}) (bytes []byte, err error) { return nil, nil }, @@ -138,7 +139,7 @@ func TestTxLogProcessor_SaveLogsCallsPutWithMarshalBuff(t *testing.T) { return nil }, }, - Marshalizer: &mock.MarshalizerStub{ + Marshalizer: &testscommon.MarshallerStub{ MarshalCalled: func(obj interface{}) (bytes []byte, err error) { log, _ := obj.(*transaction.Log) require.Equal(t, expectedLogData[0], log.Events[0].Data) @@ -164,7 +165,7 @@ func TestTxLogProcessor_GetLogErrNotFound(t *testing.T) { return nil, errors.New("storer error") }, }, - Marshalizer: &mock.MarshalizerStub{}, + Marshalizer: &testscommon.MarshallerStub{}, SaveInStorageEnabled: true, }) @@ -181,7 +182,7 @@ func TestTxLogProcessor_GetLogUnmarshalErr(t *testing.T) { return make([]byte, 0), nil }, }, - Marshalizer: &mock.MarshalizerStub{ + Marshalizer: &testscommon.MarshallerStub{ UnmarshalCalled: func(obj interface{}, buff []byte) error { return retErr }, @@ -240,3 +241,19 @@ func TestTxLogProcessor_GetLogFromCacheNotInCacheShouldReturnFromStorage(t *test _, found := txLogProcessor.GetLogFromCache([]byte("txhash")) require.True(t, found) } + +func TestTxLogProcessor_IsInterfaceNil(t *testing.T) { + t.Parallel() + + txLogProcessor, _ := transactionLog.NewTxLogProcessor(transactionLog.ArgTxLogProcessor{ + Storer: &storageStubs.StorerStub{}, + Marshalizer: nil, + }) + require.True(t, txLogProcessor.IsInterfaceNil()) + + txLogProcessor, _ = transactionLog.NewTxLogProcessor(transactionLog.ArgTxLogProcessor{ + Storer: &storageStubs.StorerStub{}, + Marshalizer: &testscommon.MarshallerStub{}, + }) + require.False(t, txLogProcessor.IsInterfaceNil()) +} diff --git a/sharding/mock/enableEpochsHandlerMock.go b/sharding/mock/enableEpochsHandlerMock.go index 32c6b4fa14c..9a842f9adae 100644 --- a/sharding/mock/enableEpochsHandlerMock.go +++ b/sharding/mock/enableEpochsHandlerMock.go @@ -48,6 +48,16 @@ func (mock *EnableEpochsHandlerMock) FixGasRemainingForSaveKeyValueBuiltinFuncti return false } +// IsRelayedTransactionsV3FlagEnabled - +func (mock *EnableEpochsHandlerMock) IsRelayedTransactionsV3FlagEnabled() bool { + return false +} + +// IsFixRelayedBaseCostFlagEnabled - +func (mock *EnableEpochsHandlerMock) IsFixRelayedBaseCostFlagEnabled() bool { + return false +} + // IsInterfaceNil returns true if there is no value under the interface func (mock *EnableEpochsHandlerMock) IsInterfaceNil() bool { return mock == nil diff --git a/state/interface.go b/state/interface.go index 0b53a4f5fcd..a9b460957b1 100644 --- a/state/interface.go +++ b/state/interface.go @@ -59,7 +59,7 @@ type PeerAccountHandler interface { GetTempRating() uint32 SetTempRating(uint32) GetConsecutiveProposerMisses() uint32 - SetConsecutiveProposerMisses(uint322 uint32) + SetConsecutiveProposerMisses(consecutiveMisses uint32) ResetAtNewEpoch() SetPreviousList(list string) vmcommon.AccountHandler diff --git a/statusHandler/statusMetricsProvider.go b/statusHandler/statusMetricsProvider.go index b47b6851eae..30ead1e5749 100644 --- a/statusHandler/statusMetricsProvider.go +++ b/statusHandler/statusMetricsProvider.go @@ -377,6 +377,7 @@ func (sm *statusMetrics) EnableEpochsMetrics() (map[string]interface{}, error) { enableEpochsMetrics[common.MetricDynamicESDTEnableEpoch] = sm.uint64Metrics[common.MetricDynamicESDTEnableEpoch] enableEpochsMetrics[common.MetricEGLDInMultiTransferEnableEpoch] = sm.uint64Metrics[common.MetricEGLDInMultiTransferEnableEpoch] enableEpochsMetrics[common.MetricCryptoOpcodesV2EnableEpoch] = sm.uint64Metrics[common.MetricCryptoOpcodesV2EnableEpoch] + enableEpochsMetrics[common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch] = sm.uint64Metrics[common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch] numNodesChangeConfig := sm.uint64Metrics[common.MetricMaxNodesChangeEnableEpoch+"_count"] diff --git a/statusHandler/statusMetricsProvider_test.go b/statusHandler/statusMetricsProvider_test.go index 2eecf8cd598..02f33d62549 100644 --- a/statusHandler/statusMetricsProvider_test.go +++ b/statusHandler/statusMetricsProvider_test.go @@ -400,6 +400,7 @@ func TestStatusMetrics_EnableEpochMetrics(t *testing.T) { sm.SetUInt64Value(common.MetricDynamicESDTEnableEpoch, uint64(4)) sm.SetUInt64Value(common.MetricEGLDInMultiTransferEnableEpoch, uint64(4)) sm.SetUInt64Value(common.MetricCryptoOpcodesV2EnableEpoch, uint64(4)) + sm.SetUInt64Value(common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch, uint64(4)) maxNodesChangeConfig := []map[string]uint64{ { @@ -529,6 +530,7 @@ func TestStatusMetrics_EnableEpochMetrics(t *testing.T) { common.MetricDynamicESDTEnableEpoch: uint64(4), common.MetricEGLDInMultiTransferEnableEpoch: uint64(4), common.MetricCryptoOpcodesV2EnableEpoch: uint64(4), + common.MetricMultiESDTNFTTransferAndExecuteByUserEnableEpoch: uint64(4), common.MetricMaxNodesChangeEnableEpoch: []map[string]interface{}{ { diff --git a/epochStart/mock/argumentsParserMock.go b/testscommon/argumentsParserMock.go similarity index 98% rename from epochStart/mock/argumentsParserMock.go rename to testscommon/argumentsParserMock.go index 02ce8f408ae..b23b66b682b 100644 --- a/epochStart/mock/argumentsParserMock.go +++ b/testscommon/argumentsParserMock.go @@ -1,4 +1,4 @@ -package mock +package testscommon import ( vmcommon "github.com/multiversx/mx-chain-vm-common-go" diff --git a/testscommon/components/default.go b/testscommon/components/default.go index 514b8355407..8e1942037dd 100644 --- a/testscommon/components/default.go +++ b/testscommon/components/default.go @@ -20,6 +20,7 @@ import ( "github.com/multiversx/mx-chain-go/testscommon/marshallerMock" "github.com/multiversx/mx-chain-go/testscommon/nodeTypeProviderMock" "github.com/multiversx/mx-chain-go/testscommon/p2pmocks" + "github.com/multiversx/mx-chain-go/testscommon/processMocks" "github.com/multiversx/mx-chain-go/testscommon/shardingMocks" "github.com/multiversx/mx-chain-go/testscommon/stakingcommon" stateMock "github.com/multiversx/mx-chain-go/testscommon/state" @@ -156,6 +157,7 @@ func GetDefaultProcessComponents(shardCoordinator sharding.Coordinator) *mock.Pr return &mock.PrivateKeyStub{} }, }, - HardforkTriggerField: &testscommon.HardforkTriggerStub{}, + HardforkTriggerField: &testscommon.HardforkTriggerStub{}, + RelayedTxV3ProcessorField: &processMocks.RelayedTxV3ProcessorMock{}, } } diff --git a/testscommon/economicsmocks/economicsDataHandlerStub.go b/testscommon/economicsmocks/economicsDataHandlerStub.go index b6cf36f4491..bb59020bc27 100644 --- a/testscommon/economicsmocks/economicsDataHandlerStub.go +++ b/testscommon/economicsmocks/economicsDataHandlerStub.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data" + "github.com/multiversx/mx-chain-go/process" ) // EconomicsHandlerStub - @@ -46,6 +47,8 @@ type EconomicsHandlerStub struct { ComputeGasLimitInEpochCalled func(tx data.TransactionWithFeeHandler, epoch uint32) uint64 ComputeGasUsedAndFeeBasedOnRefundValueInEpochCalled func(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) (uint64, *big.Int) ComputeTxFeeBasedOnGasUsedInEpochCalled func(tx data.TransactionWithFeeHandler, gasUsed uint64, epoch uint32) *big.Int + ComputeRelayedTxFeesCalled func(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) + SetTxTypeHandlerCalled func(txTypeHandler process.TxTypeHandler) error } // ComputeFeeForProcessing - @@ -356,6 +359,22 @@ func (e *EconomicsHandlerStub) ComputeTxFeeBasedOnGasUsedInEpoch(tx data.Transac return nil } +// ComputeRelayedTxFees - +func (e *EconomicsHandlerStub) ComputeRelayedTxFees(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) { + if e.ComputeRelayedTxFeesCalled != nil { + return e.ComputeRelayedTxFeesCalled(tx) + } + return big.NewInt(0), big.NewInt(0), nil +} + +// SetTxTypeHandler - +func (e *EconomicsHandlerStub) SetTxTypeHandler(txTypeHandler process.TxTypeHandler) error { + if e.SetTxTypeHandlerCalled != nil { + return e.SetTxTypeHandlerCalled(txTypeHandler) + } + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (e *EconomicsHandlerStub) IsInterfaceNil() bool { return e == nil diff --git a/testscommon/economicsmocks/economicsHandlerMock.go b/testscommon/economicsmocks/economicsHandlerMock.go index 88a54c90e72..3506d2ba9a7 100644 --- a/testscommon/economicsmocks/economicsHandlerMock.go +++ b/testscommon/economicsmocks/economicsHandlerMock.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/core" "github.com/multiversx/mx-chain-core-go/data" + "github.com/multiversx/mx-chain-go/process" ) // EconomicsHandlerMock - @@ -46,6 +47,8 @@ type EconomicsHandlerMock struct { ComputeGasLimitInEpochCalled func(tx data.TransactionWithFeeHandler, epoch uint32) uint64 ComputeGasUsedAndFeeBasedOnRefundValueInEpochCalled func(tx data.TransactionWithFeeHandler, refundValue *big.Int, epoch uint32) (uint64, *big.Int) ComputeTxFeeBasedOnGasUsedInEpochCalled func(tx data.TransactionWithFeeHandler, gasUsed uint64, epoch uint32) *big.Int + ComputeRelayedTxFeesCalled func(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) + SetTxTypeHandlerCalled func(txTypeHandler process.TxTypeHandler) error } // LeaderPercentage - @@ -335,6 +338,22 @@ func (ehm *EconomicsHandlerMock) ComputeTxFeeBasedOnGasUsedInEpoch(tx data.Trans return nil } +// ComputeRelayedTxFees - +func (ehm *EconomicsHandlerMock) ComputeRelayedTxFees(tx data.TransactionWithFeeHandler) (*big.Int, *big.Int, error) { + if ehm.ComputeRelayedTxFeesCalled != nil { + return ehm.ComputeRelayedTxFeesCalled(tx) + } + return big.NewInt(0), big.NewInt(0), nil +} + +// SetTxTypeHandler - +func (ehm *EconomicsHandlerMock) SetTxTypeHandler(txTypeHandler process.TxTypeHandler) error { + if ehm.SetTxTypeHandlerCalled != nil { + return ehm.SetTxTypeHandlerCalled(txTypeHandler) + } + return nil +} + // IsInterfaceNil returns true if there is no value under the interface func (ehm *EconomicsHandlerMock) IsInterfaceNil() bool { return ehm == nil diff --git a/testscommon/generalConfig.go b/testscommon/generalConfig.go index 1eea96a2bdb..53299443ebe 100644 --- a/testscommon/generalConfig.go +++ b/testscommon/generalConfig.go @@ -429,6 +429,9 @@ func GetGeneralConfig() config.Config { ResourceStats: config.ResourceStatsConfig{ RefreshIntervalInSec: 1, }, + RelayedTransactionConfig: config.RelayedTransactionConfig{ + MaxTransactionsAllowed: 10, + }, } } diff --git a/testscommon/preProcessorExecutionInfoHandlerMock.go b/testscommon/preProcessorExecutionInfoHandlerMock.go index 116f58f7d88..0946db0f4ba 100644 --- a/testscommon/preProcessorExecutionInfoHandlerMock.go +++ b/testscommon/preProcessorExecutionInfoHandlerMock.go @@ -3,7 +3,7 @@ package testscommon // PreProcessorExecutionInfoHandlerMock - type PreProcessorExecutionInfoHandlerMock struct { GetNumOfCrossInterMbsAndTxsCalled func() (int, int) - InitProcessedTxsResultsCalled func(key []byte) + InitProcessedTxsResultsCalled func(key []byte, parentKey []byte) RevertProcessedTxsResultsCalled func(txHashes [][]byte, key []byte) } @@ -16,9 +16,9 @@ func (ppeihm *PreProcessorExecutionInfoHandlerMock) GetNumOfCrossInterMbsAndTxs( } // InitProcessedTxsResults - -func (ppeihm *PreProcessorExecutionInfoHandlerMock) InitProcessedTxsResults(key []byte) { +func (ppeihm *PreProcessorExecutionInfoHandlerMock) InitProcessedTxsResults(key []byte, parentKey []byte) { if ppeihm.InitProcessedTxsResultsCalled != nil { - ppeihm.InitProcessedTxsResultsCalled(key) + ppeihm.InitProcessedTxsResultsCalled(key, parentKey) } } diff --git a/testscommon/processMocks/failedTxLogsAccumulatorMock.go b/testscommon/processMocks/failedTxLogsAccumulatorMock.go new file mode 100644 index 00000000000..903e56cd79f --- /dev/null +++ b/testscommon/processMocks/failedTxLogsAccumulatorMock.go @@ -0,0 +1,41 @@ +package processMocks + +import ( + "github.com/multiversx/mx-chain-core-go/data" + vmcommon "github.com/multiversx/mx-chain-vm-common-go" +) + +// FailedTxLogsAccumulatorMock - +type FailedTxLogsAccumulatorMock struct { + GetLogsCalled func(txHash []byte) (data.TransactionHandler, []*vmcommon.LogEntry, bool) + SaveLogsCalled func(txHash []byte, tx data.TransactionHandler, logs []*vmcommon.LogEntry) error + RemoveCalled func(txHash []byte) +} + +// GetLogs - +func (mock *FailedTxLogsAccumulatorMock) GetLogs(txHash []byte) (data.TransactionHandler, []*vmcommon.LogEntry, bool) { + if mock.GetLogsCalled != nil { + return mock.GetLogsCalled(txHash) + } + return nil, nil, false +} + +// SaveLogs - +func (mock *FailedTxLogsAccumulatorMock) SaveLogs(txHash []byte, tx data.TransactionHandler, logs []*vmcommon.LogEntry) error { + if mock.SaveLogsCalled != nil { + return mock.SaveLogsCalled(txHash, tx, logs) + } + return nil +} + +// Remove - +func (mock *FailedTxLogsAccumulatorMock) Remove(txHash []byte) { + if mock.RemoveCalled != nil { + mock.RemoveCalled(txHash) + } +} + +// IsInterfaceNil - +func (mock *FailedTxLogsAccumulatorMock) IsInterfaceNil() bool { + return mock == nil +} diff --git a/testscommon/processMocks/relayedTxV3ProcessorMock.go b/testscommon/processMocks/relayedTxV3ProcessorMock.go new file mode 100644 index 00000000000..85af9584af5 --- /dev/null +++ b/testscommon/processMocks/relayedTxV3ProcessorMock.go @@ -0,0 +1,23 @@ +package processMocks + +import ( + "github.com/multiversx/mx-chain-core-go/data/transaction" +) + +// RelayedTxV3ProcessorMock - +type RelayedTxV3ProcessorMock struct { + CheckRelayedTxCalled func(tx *transaction.Transaction) error +} + +// CheckRelayedTx - +func (mock *RelayedTxV3ProcessorMock) CheckRelayedTx(tx *transaction.Transaction) error { + if mock.CheckRelayedTxCalled != nil { + return mock.CheckRelayedTxCalled(tx) + } + return nil +} + +// IsInterfaceNil - +func (mock *RelayedTxV3ProcessorMock) IsInterfaceNil() bool { + return mock == nil +} diff --git a/testscommon/toml/config.go b/testscommon/toml/config.go index 47a45839be0..56cfeb1f0ad 100644 --- a/testscommon/toml/config.go +++ b/testscommon/toml/config.go @@ -15,6 +15,7 @@ type Config struct { TestConfigStruct TestConfigNestedStruct TestMap + TestInterface } // TestConfigI8 will hold an int8 value for testing @@ -24,7 +25,7 @@ type TestConfigI8 struct { // Int8 will hold the value type Int8 struct { - Value int8 + Number int8 } // TestConfigI16 will hold an int16 value for testing @@ -34,7 +35,7 @@ type TestConfigI16 struct { // Int16 will hold the value type Int16 struct { - Value int16 + Number int16 } // TestConfigI32 will hold an int32 value for testing @@ -44,7 +45,7 @@ type TestConfigI32 struct { // Int32 will hold the value type Int32 struct { - Value int32 + Number int32 } // TestConfigI64 will hold an int64 value for testing @@ -54,7 +55,7 @@ type TestConfigI64 struct { // Int64 will hold the value type Int64 struct { - Value int64 + Number int64 } // TestConfigU8 will hold an uint8 value for testing @@ -64,7 +65,7 @@ type TestConfigU8 struct { // Uint8 will hold the value type Uint8 struct { - Value uint8 + Number uint8 } // TestConfigU16 will hold an uint16 value for testing @@ -74,7 +75,7 @@ type TestConfigU16 struct { // Uint16 will hold the value type Uint16 struct { - Value uint16 + Number uint16 } // TestConfigU32 will hold an uint32 value for testing @@ -84,7 +85,7 @@ type TestConfigU32 struct { // Uint32 will hold the value type Uint32 struct { - Value uint32 + Number uint32 } // TestConfigU64 will hold an uint64 value for testing @@ -94,7 +95,7 @@ type TestConfigU64 struct { // Uint64 will hold the value type Uint64 struct { - Value uint64 + Number uint64 } // TestConfigF32 will hold a float32 value for testing @@ -104,7 +105,7 @@ type TestConfigF32 struct { // Float32 will hold the value type Float32 struct { - Value float32 + Number float32 } // TestConfigF64 will hold a float64 value for testing @@ -114,7 +115,7 @@ type TestConfigF64 struct { // Float64 will hold the value type Float64 struct { - Value float64 + Number float64 } // TestConfigStruct will hold a configuration struct for testing @@ -167,5 +168,15 @@ type MessageDescriptionOtherName struct { // TestMap will hold a map for testing type TestMap struct { - Value map[string]int + Map map[string]MapValues +} + +// MapValues will hold a value for map +type MapValues struct { + Number int +} + +// TestInterface will hold an interface for testing +type TestInterface struct { + Value interface{} } diff --git a/testscommon/toml/config.toml b/testscommon/toml/config.toml index af54141fe5f..91512d5e664 100644 --- a/testscommon/toml/config.toml +++ b/testscommon/toml/config.toml @@ -48,5 +48,6 @@ Text = "Config Nested Struct" Mesage = { Public = true, MessageDescription = [{ Text = "Text1" }, { Text = "Text2"}] } -[TestMap] - Value = { "key" = 0 } +[Map] + [Map.Key1] + Number = 999 diff --git a/testscommon/toml/overwrite.toml b/testscommon/toml/overwrite.toml index 5d1e6690caf..63f74b7828c 100644 --- a/testscommon/toml/overwrite.toml +++ b/testscommon/toml/overwrite.toml @@ -1,38 +1,40 @@ OverridableConfigTomlValues = [ - { File = "config.toml", Path = "TestConfigI8.Int8", Value = 127 }, - { File = "config.toml", Path = "TestConfigI8.Int8", Value = 128 }, - { File = "config.toml", Path = "TestConfigI8.Int8", Value = -128 }, - { File = "config.toml", Path = "TestConfigI8.Int8", Value = -129 }, - { File = "config.toml", Path = "TestConfigI16.Int16", Value = 32767 }, - { File = "config.toml", Path = "TestConfigI16.Int16", Value = 32768 }, - { File = "config.toml", Path = "TestConfigI16.Int16", Value = -32768 }, - { File = "config.toml", Path = "TestConfigI16.Int16", Value = -32769 }, - { File = "config.toml", Path = "TestConfigI32.Int32", Value = 2147483647 }, - { File = "config.toml", Path = "TestConfigI32.Int32", Value = 2147483648 }, - { File = "config.toml", Path = "TestConfigI32.Int32", Value = -2147483648 }, - { File = "config.toml", Path = "TestConfigI32.Int32", Value = -2147483649 }, - { File = "config.toml", Path = "TestConfigI32.Int64", Value = 9223372036854775807 }, - { File = "config.toml", Path = "TestConfigI32.Int64", Value = -9223372036854775808 }, - { File = "config.toml", Path = "TestConfigU8.Uint8", Value = 255 }, - { File = "config.toml", Path = "TestConfigU8.Uint8", Value = 256 }, - { File = "config.toml", Path = "TestConfigU8.Uint8", Value = -256 }, - { File = "config.toml", Path = "TestConfigU16.Uint16", Value = 65535 }, - { File = "config.toml", Path = "TestConfigU16.Uint16", Value = 65536 }, - { File = "config.toml", Path = "TestConfigU16.Uint16", Value = -65536 }, - { File = "config.toml", Path = "TestConfigU32.Uint32", Value = 4294967295 }, - { File = "config.toml", Path = "TestConfigU32.Uint32", Value = 4294967296 }, - { File = "config.toml", Path = "TestConfigU32.Uint32", Value = -4294967296 }, - { File = "config.toml", Path = "TestConfigU64.Uint64", Value = 9223372036854775807 }, - { File = "config.toml", Path = "TestConfigU64.Uint64", Value = -9223372036854775808 }, - { File = "config.toml", Path = "TestConfigF32.Float32", Value = 3.4 }, - { File = "config.toml", Path = "TestConfigF32.Float32", Value = 3.4e+39 }, - { File = "config.toml", Path = "TestConfigF32.Float32", Value = -3.4 }, - { File = "config.toml", Path = "TestConfigF32.Float32", Value = -3.4e+40 }, - { File = "config.toml", Path = "TestConfigF64.Float64", Value = 1.7e+308 }, - { File = "config.toml", Path = "TestConfigF64.Float64", Value = -1.7e+308 }, + { 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 } } }, ] diff --git a/testscommon/transactionCoordinatorMock.go b/testscommon/transactionCoordinatorMock.go index cd25a769912..a1889b0b753 100644 --- a/testscommon/transactionCoordinatorMock.go +++ b/testscommon/transactionCoordinatorMock.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" + "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/processedMb" ) @@ -29,7 +30,7 @@ type TransactionCoordinatorMock struct { VerifyCreatedBlockTransactionsCalled func(hdr data.HeaderHandler, body *block.Body) error CreatePostProcessMiniBlocksCalled func() block.MiniBlockSlice VerifyCreatedMiniBlocksCalled func(hdr data.HeaderHandler, body *block.Body) error - AddIntermediateTransactionsCalled func(mapSCRs map[block.Type][]data.TransactionHandler) error + AddIntermediateTransactionsCalled func(mapSCRs map[block.Type][]data.TransactionHandler, key []byte) error GetAllIntermediateTxsCalled func() map[block.Type]map[string]data.TransactionHandler AddTxsFromMiniBlocksCalled func(miniBlocks block.MiniBlockSlice) AddTransactionsCalled func(txHandlers []data.TransactionHandler, blockType block.Type) @@ -215,12 +216,12 @@ func (tcm *TransactionCoordinatorMock) VerifyCreatedMiniBlocks(hdr data.HeaderHa } // AddIntermediateTransactions - -func (tcm *TransactionCoordinatorMock) AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler) error { +func (tcm *TransactionCoordinatorMock) AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler, key []byte) error { if tcm.AddIntermediateTransactionsCalled == nil { return nil } - return tcm.AddIntermediateTransactionsCalled(mapSCRs) + return tcm.AddIntermediateTransactionsCalled(mapSCRs, key) } // GetAllIntermediateTxs - diff --git a/update/factory/exportHandlerFactory.go b/update/factory/exportHandlerFactory.go index c13f25f3f5a..a8ed95f4ceb 100644 --- a/update/factory/exportHandlerFactory.go +++ b/update/factory/exportHandlerFactory.go @@ -18,6 +18,7 @@ import ( mxFactory "github.com/multiversx/mx-chain-go/factory" "github.com/multiversx/mx-chain-go/genesis/process/disabled" "github.com/multiversx/mx-chain-go/process" + processDisabled "github.com/multiversx/mx-chain-go/process/disabled" "github.com/multiversx/mx-chain-go/sharding" "github.com/multiversx/mx-chain-go/sharding/nodesCoordinator" "github.com/multiversx/mx-chain-go/state" @@ -588,6 +589,7 @@ func (e *exportHandlerFactory) createInterceptors() error { FullArchiveInterceptorsContainer: e.fullArchiveInterceptorsContainer, AntifloodHandler: e.networkComponents.InputAntiFloodHandler(), NodeOperationMode: e.nodeOperationMode, + RelayedTxV3Processor: processDisabled.NewRelayedTxV3Processor(), } fullSyncInterceptors, err := NewFullSyncInterceptorsContainerFactory(argsInterceptors) if err != nil { diff --git a/update/factory/fullSyncInterceptors.go b/update/factory/fullSyncInterceptors.go index 0fe0298c4d6..67d5a86a503 100644 --- a/update/factory/fullSyncInterceptors.go +++ b/update/factory/fullSyncInterceptors.go @@ -75,6 +75,7 @@ type ArgsNewFullSyncInterceptorsContainerFactory struct { FullArchiveInterceptorsContainer process.InterceptorsContainer AntifloodHandler process.P2PAntifloodHandler NodeOperationMode common.NodeOperation + RelayedTxV3Processor process.RelayedTxV3Processor } // NewFullSyncInterceptorsContainerFactory is responsible for creating a new interceptors factory object @@ -145,6 +146,7 @@ func NewFullSyncInterceptorsContainerFactory( EpochStartTrigger: args.EpochStartTrigger, WhiteListerVerifiedTxs: args.WhiteListerVerifiedTxs, ArgsParser: smartContract.NewArgumentParser(), + RelayedTxV3Processor: args.RelayedTxV3Processor, } icf := &fullSyncInterceptorsContainerFactory{ diff --git a/update/mock/transactionCoordinatorMock.go b/update/mock/transactionCoordinatorMock.go index 07183d9467a..c0bb061a713 100644 --- a/update/mock/transactionCoordinatorMock.go +++ b/update/mock/transactionCoordinatorMock.go @@ -5,6 +5,7 @@ import ( "github.com/multiversx/mx-chain-core-go/data" "github.com/multiversx/mx-chain-core-go/data/block" + "github.com/multiversx/mx-chain-go/process" "github.com/multiversx/mx-chain-go/process/block/processedMb" ) @@ -29,7 +30,7 @@ type TransactionCoordinatorMock struct { VerifyCreatedBlockTransactionsCalled func(hdr data.HeaderHandler, body *block.Body) error CreatePostProcessMiniBlocksCalled func() block.MiniBlockSlice VerifyCreatedMiniBlocksCalled func(hdr data.HeaderHandler, body *block.Body) error - AddIntermediateTransactionsCalled func(mapSCRs map[block.Type][]data.TransactionHandler) error + AddIntermediateTransactionsCalled func(mapSCRs map[block.Type][]data.TransactionHandler, key []byte) error GetAllIntermediateTxsCalled func() map[block.Type]map[string]data.TransactionHandler AddTxsFromMiniBlocksCalled func(miniBlocks block.MiniBlockSlice) AddTransactionsCalled func(txHandlers []data.TransactionHandler, blockType block.Type) @@ -204,12 +205,12 @@ func (tcm *TransactionCoordinatorMock) VerifyCreatedMiniBlocks(hdr data.HeaderHa } // AddIntermediateTransactions - -func (tcm *TransactionCoordinatorMock) AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler) error { +func (tcm *TransactionCoordinatorMock) AddIntermediateTransactions(mapSCRs map[block.Type][]data.TransactionHandler, key []byte) error { if tcm.AddIntermediateTransactionsCalled == nil { return nil } - return tcm.AddIntermediateTransactionsCalled(mapSCRs) + return tcm.AddIntermediateTransactionsCalled(mapSCRs, key) } // GetAllIntermediateTxs - diff --git a/vm/systemSmartContracts/delegation.go b/vm/systemSmartContracts/delegation.go index ab5c97cfce0..da23e0c8a15 100644 --- a/vm/systemSmartContracts/delegation.go +++ b/vm/systemSmartContracts/delegation.go @@ -2096,7 +2096,7 @@ func (d *delegation) claimRewards(args *vmcommon.ContractCallInput) vmcommon.Ret } } - d.createAndAddLogEntry(args, unclaimedRewardsBytes, boolToSlice(wasDeleted)) + d.createAndAddLogEntry(args, unclaimedRewardsBytes, boolToSlice(wasDeleted), args.RecipientAddr) return vmcommon.Ok } diff --git a/vm/systemSmartContracts/esdt.go b/vm/systemSmartContracts/esdt.go index e8371e1eb79..99b29035aef 100644 --- a/vm/systemSmartContracts/esdt.go +++ b/vm/systemSmartContracts/esdt.go @@ -42,6 +42,7 @@ const canTransferNFTCreateRole = "canTransferNFTCreateRole" const upgradable = "canUpgrade" const canCreateMultiShard = "canCreateMultiShard" const upgradeProperties = "upgradeProperties" +const eGLD = "EGLD" const conversionBase = 10 @@ -547,9 +548,21 @@ func (e *esdt) registerAndSetRoles(args *vmcommon.ContractCallInput) vmcommon.Re func (e *esdt) getAllRolesForTokenType(tokenType string) ([][]byte, error) { switch tokenType { case core.NonFungibleESDT, core.NonFungibleESDTv2, core.DynamicNFTESDT: - nftRoles := [][]byte{[]byte(core.ESDTRoleNFTCreate), []byte(core.ESDTRoleNFTBurn), []byte(core.ESDTRoleNFTUpdateAttributes), []byte(core.ESDTRoleNFTAddURI)} + nftRoles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleNFTBurn), + []byte(core.ESDTRoleNFTUpdateAttributes), + []byte(core.ESDTRoleNFTAddURI), + } + if e.enableEpochsHandler.IsFlagEnabled(common.DynamicESDTFlag) { - nftRoles = append(nftRoles, [][]byte{[]byte(core.ESDTRoleNFTRecreate), []byte(core.ESDTRoleModifyCreator), []byte(core.ESDTRoleModifyRoyalties), []byte(core.ESDTRoleSetNewURI)}...) + nftRoles = append(nftRoles, [][]byte{ + []byte(core.ESDTRoleNFTRecreate), + []byte(core.ESDTRoleModifyCreator), + []byte(core.ESDTRoleModifyRoyalties), + []byte(core.ESDTRoleSetNewURI), + []byte(core.ESDTRoleNFTUpdate), + }...) } return nftRoles, nil @@ -558,8 +571,21 @@ func (e *esdt) getAllRolesForTokenType(tokenType string) ([][]byte, error) { case core.FungibleESDT: return [][]byte{[]byte(core.ESDTRoleLocalMint), []byte(core.ESDTRoleLocalBurn)}, nil case core.DynamicSFTESDT, core.DynamicMetaESDT: - dynamicRoles := [][]byte{[]byte(core.ESDTRoleNFTCreate), []byte(core.ESDTRoleNFTBurn), []byte(core.ESDTRoleNFTAddQuantity), []byte(core.ESDTRoleNFTUpdateAttributes), []byte(core.ESDTRoleNFTAddURI)} - dynamicRoles = append(dynamicRoles, [][]byte{[]byte(core.ESDTRoleNFTRecreate), []byte(core.ESDTRoleModifyCreator), []byte(core.ESDTRoleModifyRoyalties), []byte(core.ESDTRoleSetNewURI)}...) + dynamicRoles := [][]byte{ + []byte(core.ESDTRoleNFTCreate), + []byte(core.ESDTRoleNFTBurn), + []byte(core.ESDTRoleNFTAddQuantity), + []byte(core.ESDTRoleNFTUpdateAttributes), + []byte(core.ESDTRoleNFTAddURI), + } + + dynamicRoles = append(dynamicRoles, [][]byte{ + []byte(core.ESDTRoleNFTRecreate), + []byte(core.ESDTRoleModifyCreator), + []byte(core.ESDTRoleModifyRoyalties), + []byte(core.ESDTRoleSetNewURI), + []byte(core.ESDTRoleNFTUpdate), + }...) return dynamicRoles, nil } @@ -585,6 +611,15 @@ func (e *esdt) getTokenType(compressed []byte) (bool, []byte, error) { return false, nil, vm.ErrInvalidArgument } +func getDynamicTokenType(tokenType []byte) []byte { + if bytes.Equal(tokenType, []byte(core.NonFungibleESDTv2)) || + bytes.Equal(tokenType, []byte(core.NonFungibleESDT)) { + return []byte(core.DynamicNFTESDT) + } + + return append([]byte(core.Dynamic), tokenType...) +} + func (e *esdt) changeSFTToMetaESDT(args *vmcommon.ContractCallInput) vmcommon.ReturnCode { if !e.enableEpochsHandler.IsFlagEnabled(common.MetaESDTSetFlag) { e.eei.AddReturnMessage("invalid method to call") @@ -714,6 +749,11 @@ func isTokenNameHumanReadable(tokenName []byte) bool { } func (e *esdt) createNewTokenIdentifier(caller []byte, ticker []byte) ([]byte, error) { + if e.enableEpochsHandler.IsFlagEnabled(common.EGLDInESDTMultiTransferFlag) { + if bytes.Equal(ticker, []byte(eGLD)) { + return nil, vm.ErrCouldNotCreateNewTokenIdentifier + } + } newRandomBase := append(caller, e.eei.BlockChainHook().CurrentRandomSeed()...) newRandom := e.hasher.Compute(string(newRandomBase)) newRandomForTicker := newRandom[:tickerRandomSequenceLength] @@ -1626,6 +1666,11 @@ func (e *esdt) isSpecialRoleValidForNonFungible(argument string) error { return nil } return vm.ErrInvalidArgument + case core.ESDTRoleNFTUpdate: + if e.enableEpochsHandler.IsFlagEnabled(common.DynamicESDTFlag) { + return nil + } + return vm.ErrInvalidArgument default: return vm.ErrInvalidArgument } @@ -1651,6 +1696,8 @@ func (e *esdt) isSpecialRoleValidForDynamicNFT(argument string) error { return nil case core.ESDTRoleNFTRecreate: return nil + case core.ESDTRoleNFTUpdate: + return nil default: return vm.ErrInvalidArgument } @@ -1757,8 +1804,16 @@ func isDynamicTokenType(tokenType []byte) bool { } func rolesForDynamicWhichHasToBeSingular() []string { - return []string{core.ESDTRoleNFTCreate, core.ESDTRoleNFTUpdateAttributes, core.ESDTRoleNFTAddURI, - core.ESDTRoleSetNewURI, core.ESDTRoleModifyCreator, core.ESDTRoleModifyRoyalties, core.ESDTRoleNFTRecreate} + return []string{ + core.ESDTRoleNFTCreate, + core.ESDTRoleNFTUpdateAttributes, + core.ESDTRoleNFTAddURI, + core.ESDTRoleSetNewURI, + core.ESDTRoleModifyCreator, + core.ESDTRoleModifyRoyalties, + core.ESDTRoleNFTRecreate, + core.ESDTRoleNFTUpdate, + } } func (e *esdt) checkRolesForDynamicTokens( @@ -2236,6 +2291,11 @@ func (e *esdt) createDynamicToken(args *vmcommon.ContractCallInput) ([]byte, *ES return nil, nil, vmcommon.UserError } + if isNotAllowedToCreateDynamicToken(tokenType) { + e.eei.AddReturnMessage(fmt.Sprintf("cannot create %s tokens as dynamic", tokenType)) + return nil, nil, vmcommon.UserError + } + propertiesStart := 3 numOfDecimals := uint32(0) if isWithDecimals { @@ -2257,7 +2317,7 @@ func (e *esdt) createDynamicToken(args *vmcommon.ContractCallInput) ([]byte, *ES } } - dynamicTokenType := append([]byte(core.Dynamic), tokenType...) + dynamicTokenType := getDynamicTokenType(tokenType) tokenIdentifier, token, err := e.createNewToken( args.CallerAddr, @@ -2400,6 +2460,10 @@ func isNotAllowed(tokenType []byte) bool { return false } +func isNotAllowedToCreateDynamicToken(tokenType []byte) bool { + return bytes.Equal(tokenType, []byte(core.FungibleESDT)) +} + func (e *esdt) sendTokenTypeToSystemAccounts(caller []byte, tokenID []byte, token *ESDTDataV2) { if !e.enableEpochsHandler.IsFlagEnabled(common.DynamicESDTFlag) { return diff --git a/vm/systemSmartContracts/logs.go b/vm/systemSmartContracts/logs.go index 69af22820e1..c40834107f3 100644 --- a/vm/systemSmartContracts/logs.go +++ b/vm/systemSmartContracts/logs.go @@ -64,13 +64,10 @@ func (d *delegation) createAndAddLogEntryForDelegate( function == mergeValidatorDataToDelegation || function == changeOwner { address = contractCallInput.Arguments[0] - - topics = append(topics, contractCallInput.RecipientAddr) - } - if function == core.SCDeployInitFunctionName { - topics = append(topics, contractCallInput.RecipientAddr) } + topics = append(topics, contractCallInput.RecipientAddr) + entry := &vmcommon.LogEntry{ Identifier: []byte("delegate"), Address: address, diff --git a/vm/systemSmartContracts/logs_test.go b/vm/systemSmartContracts/logs_test.go index 5f88b1ddabd..4fc3f536878 100644 --- a/vm/systemSmartContracts/logs_test.go +++ b/vm/systemSmartContracts/logs_test.go @@ -37,6 +37,7 @@ func TestCreateLogEntryForDelegate(t *testing.T) { VMInput: vmcommon.VMInput{ CallerAddr: []byte("caller"), }, + RecipientAddr: []byte("recipient"), }, delegationValue, &GlobalFundData{ @@ -52,7 +53,7 @@ func TestCreateLogEntryForDelegate(t *testing.T) { require.Equal(t, &vmcommon.LogEntry{ Identifier: []byte("delegate"), Address: []byte("caller"), - Topics: [][]byte{delegationValue.Bytes(), big.NewInt(6000).Bytes(), big.NewInt(1).Bytes(), big.NewInt(1001000).Bytes()}, + Topics: [][]byte{delegationValue.Bytes(), big.NewInt(6000).Bytes(), big.NewInt(1).Bytes(), big.NewInt(1001000).Bytes(), []byte("recipient")}, }, res) }