diff --git a/.github/workflows/build_and_run_chain_simulator_and_execute_system_test.yml b/.github/workflows/build_and_run_chain_simulator_and_execute_system_test.yml
new file mode 100644
index 00000000000..f766ccddbf5
--- /dev/null
+++ b/.github/workflows/build_and_run_chain_simulator_and_execute_system_test.yml
@@ -0,0 +1,316 @@
+name: Chain Simulator Build and Integration Test
+
+on:
+ pull_request:
+ branches:
+ - 'main'
+ - 'master'
+ - 'rc/*'
+ workflow_dispatch:
+ issue_comment:
+ types: [created]
+
+permissions:
+ issues: write
+ pull-requests: write
+ contents: read
+
+jobs:
+ build-and-test:
+ if: |
+ github.event_name == 'pull_request' ||
+ (github.event_name == 'issue_comment' && contains(github.event.comment.body, 'Run Tests:')) ||
+ github.event_name == 'workflow_dispatch'
+
+ strategy:
+ matrix:
+ #TODO Include Macos support later on
+ runs-on: [ubuntu-latest]
+ runs-on: ${{ matrix.runs-on }}
+ env:
+ BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
+ TARGET_BRANCH: ""
+ MX_CHAIN_GO_TARGET_BRANCH: ""
+ MX_CHAIN_SIMULATOR_TARGET_BRANCH: ""
+ MX_CHAIN_TESTING_SUITE_TARGET_BRANCH: ""
+
+ steps:
+ - name: Determine Target Branches
+ id: target_branch
+ run: |
+ echo "CURRENT_BRANCH=${GITHUB_HEAD_REF:-${GITHUB_REF_NAME}}" >> $GITHUB_ENV
+
+ # Default target branches based on the PR base branch
+ if [[ "${{ github.event.pull_request.base.ref }}" == "main" ]]; then
+ echo "MX_CHAIN_SIMULATOR_TARGET_BRANCH=main" >> $GITHUB_ENV
+ echo "MX_CHAIN_TESTING_SUITE_TARGET_BRANCH=main" >> $GITHUB_ENV
+ elif [[ "${{ github.event.pull_request.base.ref }}" == "master" ]]; then
+ echo "MX_CHAIN_SIMULATOR_TARGET_BRANCH=main" >> $GITHUB_ENV
+ echo "MX_CHAIN_TESTING_SUITE_TARGET_BRANCH=main" >> $GITHUB_ENV
+ else
+ echo "MX_CHAIN_SIMULATOR_TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV
+ echo "MX_CHAIN_TESTING_SUITE_TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV
+ fi
+
+ # Always set MX_CHAIN_GO_TARGET_BRANCH based on the PR base branch
+ echo "MX_CHAIN_GO_TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV
+
+
+ - name: Fetch and Parse Last Comment for Branches
+ uses: actions/github-script@v7
+ id: fetch_and_parse_last_comment
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ // Get the latest comment
+ const comments = await github.rest.issues.listComments({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: context.issue.number,
+ });
+
+ const lastComment = comments.data.pop(); // Get the last comment
+
+ if (lastComment && lastComment.body.includes('Run Tests:')) {
+ const body = lastComment.body.trim();
+ core.setOutput('latest_comment', body);
+
+ // Parse the branches from the last comment
+ const simulatorBranchMatch = body.match(/mx-chain-simulator-go:\s*(\S+)/);
+ const testingSuiteBranchMatch = body.match(/mx-chain-testing-suite:\s*(\S+)/);
+
+ // Override the target branches if specified
+ if (simulatorBranchMatch) {
+ core.exportVariable('MX_CHAIN_SIMULATOR_TARGET_BRANCH', simulatorBranchMatch[1]);
+ }
+ if (testingSuiteBranchMatch) {
+ core.exportVariable('MX_CHAIN_TESTING_SUITE_TARGET_BRANCH', testingSuiteBranchMatch[1]);
+ }
+ } else {
+ core.info('The last comment does not contain "Run Tests:". Skipping branch override.');
+ }
+
+
+ - name: Print Target Branches
+ run: |
+ echo "Current branch mx-chain-go: ${{ env.CURRENT_BRANCH }}"
+ echo "mx-chain-go target branch: ${{ env.MX_CHAIN_GO_TARGET_BRANCH }}"
+ echo "mx-chain-simulator-go target branch: ${{ env.MX_CHAIN_SIMULATOR_TARGET_BRANCH }}"
+ echo "mx-chain-testing-suite target branch: ${{ env.MX_CHAIN_TESTING_SUITE_TARGET_BRANCH }}"
+
+ - name: Set up Go 1.20.7
+ uses: actions/setup-go@v3
+ with:
+ go-version: 1.20.7
+ id: go
+
+ - name: Checkout mx-chain-go
+ uses: actions/checkout@v4
+ with:
+ repository: 'multiversx/mx-chain-go'
+ ref: ${{ github.head_ref }}
+ fetch-depth: 0
+ path: 'mx-chain-go'
+
+ - name: Get Latest mx-chain-go Commit Hash
+ run: |
+ cd mx-chain-go
+ current_branch=$(git symbolic-ref --short HEAD)
+ echo "CURRENT_BRANCH=${current_branch}" >> $GITHUB_ENV
+ git fetch origin ${current_branch} --prune
+ latest_commit_hash=$(git rev-parse origin/${current_branch})
+ echo "LATEST_COMMIT_HASH=${latest_commit_hash}" >> $GITHUB_ENV
+ echo "Latest commit hash: ${latest_commit_hash}"
+
+ - name: Checkout mx-chain-simulator-go
+ uses: actions/checkout@v4
+ with:
+ repository: 'multiversx/mx-chain-simulator-go'
+ ref: ${{ env.MX_CHAIN_SIMULATOR_TARGET_BRANCH || github.event.pull_request.base.ref }}
+ path: 'mx-chain-simulator-go'
+
+ - name: Set up Python 3.10
+ uses: actions/setup-python@v2
+ with:
+ python-version: '3.10'
+
+ - name: Install Python Dependencies and Update go.mod
+ run: |
+ cd mx-chain-simulator-go
+ pip install -r scripts/update-go-mod/requirements.txt
+ python scripts/update-go-mod/update-go-mod.py $LATEST_COMMIT_HASH
+
+ - name: Run go build
+ run: |
+ cd mx-chain-simulator-go/cmd/chainsimulator
+ go build
+ echo "CHAIN_SIMULATOR_BUILD_PATH=$(pwd)" >> $GITHUB_ENV
+
+ - name: Checkout mx-chain-testing-suite
+ uses: actions/checkout@v4
+ with:
+ repository: 'multiversx/mx-chain-testing-suite'
+ path: 'mx-chain-testing-suite'
+ fetch-depth: 0
+ ref: ${{ env.MX_CHAIN_TESTING_SUITE_TARGET_BRANCH || github.event.pull_request.base.ref }}
+ token: ${{ secrets.MVX_TESTER_GH_TOKEN }}
+
+ - name: Install Dependencies
+ run: |
+ pip install -r mx-chain-testing-suite/requirements.txt
+ echo "PYTHONPATH=mx-chain-testing-suite" >> $GITHUB_ENV
+
+
+ - name: Run tests and generate HTML report
+ run: |
+ set +e
+ pytest mx-chain-testing-suite/scenarios/ --html=report.html --self-contained-html --continue-on-collection-errors
+ PYTEST_EXIT_CODE=$?
+ set -e
+ echo "PYTEST_EXIT_CODE=$PYTEST_EXIT_CODE" >> $GITHUB_ENV
+ echo "Pytest exit code: $PYTEST_EXIT_CODE"
+ if [ -f "report.html" ]; then
+ echo "Report generated successfully."
+ mkdir -p ./reports
+ mv report.html ./reports/
+ else
+ echo "Report not found."
+ fi
+
+ - name: Upload test report
+ if: always()
+ uses: actions/upload-artifact@v3
+ with:
+ name: pytest-report-${{ github.run_id }}
+ path: reports/report.html
+
+ - name: Deploy Report to GitHub Pages
+ if: always()
+ id: deploy_report
+ run: |
+ # Navigate to the mx-chain-testing-suite directory
+ cd mx-chain-testing-suite
+
+ # Configure Git user
+ git config user.name "GitHub Action"
+ git config user.email "action@github.com"
+
+ # Check if the report exists
+ if [ -f "../reports/report.html" ]; then
+ # Ensure we're on the 'gh-pages' branch and up to date
+ git fetch --all
+ git checkout gh-pages || git checkout --orphan gh-pages
+
+ # Create a new directory for the report based on the current timestamp
+ TIMESTAMP=$(date +'%d%m%Y-%H%M%S')
+ echo "TIMESTAMP=$TIMESTAMP" >> $GITHUB_ENV
+ REPORT_DIR="reports/${BRANCH_NAME}/${TIMESTAMP}"
+ mkdir -p $REPORT_DIR
+
+ # Move the report into the new directory
+ cp ../reports/report.html $REPORT_DIR/index.html
+
+ # Add and commit only the new report
+ git add $REPORT_DIR/index.html
+ git commit -m "Deploy Test Report at $BRANCH_NAME/$TIMESTAMP"
+
+ # Set remote URL with authentication token
+ git remote set-url origin https://x-access-token:${{ secrets.MVX_TESTER_GH_TOKEN }}@github.com/multiversx/mx-chain-testing-suite.git
+
+ # Push changes to the remote 'gh-pages' branch
+ git push --force origin gh-pages
+ else
+ echo "Report file not found, skipping deployment."
+ fi
+
+
+ - name: Update Index Page
+ if: always()
+ run: |
+ cd mx-chain-testing-suite
+ git fetch --all
+ git checkout gh-pages || git checkout --orphan gh-pages
+ if [ -d "docs" ]; then
+ cd docs
+ echo "
Test Reports
" > index.html
+ for report in $(ls ../reports); do
+ echo "- Report - $report
" >> index.html
+ done
+ echo "
" >> index.html
+ git add index.html
+ git commit -m "Update Index of Reports"
+ git push origin gh-pages --force
+ else
+ mkdir -p docs
+ cd docs
+ echo "Test Reports
" >> index.html
+ echo "Docs directory was not found and has been created."
+ fi
+
+ - name: Comment PR with report link or error message
+ if: always()
+ uses: actions/github-script@v7
+ env:
+ TIMESTAMP: ${{ env.TIMESTAMP }}
+ BRANCH_NAME: ${{ env.BRANCH_NAME }}
+ CURRENT_BRANCH: ${{ env.CURRENT_BRANCH }}
+ MX_CHAIN_GO_TARGET_BRANCH: ${{ env.MX_CHAIN_GO_TARGET_BRANCH }}
+ MX_CHAIN_SIMULATOR_TARGET_BRANCH: ${{ env.MX_CHAIN_SIMULATOR_TARGET_BRANCH }}
+ MX_CHAIN_TESTING_SUITE_TARGET_BRANCH: ${{ env.MX_CHAIN_TESTING_SUITE_TARGET_BRANCH }}
+ LATEST_COMMIT_HASH: ${{ env.LATEST_COMMIT_HASH }}
+ PYTEST_EXIT_CODE: ${{ env.PYTEST_EXIT_CODE }}
+
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const timestamp = process.env.TIMESTAMP;
+ const branchName = process.env.BRANCH_NAME;
+ const currentBranch = process.env.CURRENT_BRANCH;
+ const goTargetBranch = process.env.MX_CHAIN_GO_TARGET_BRANCH;
+ const simulatorTargetBranch = process.env.MX_CHAIN_SIMULATOR_TARGET_BRANCH;
+ const testingSuiteTargetBranch = process.env.MX_CHAIN_TESTING_SUITE_TARGET_BRANCH;
+ const commitHash = process.env.LATEST_COMMIT_HASH;
+ const exitCode = process.env.PYTEST_EXIT_CODE;
+ const issue_number = context.issue.number;
+ const owner = context.repo.owner;
+ const repo = context.repo.repo;
+ let message;
+
+ if (timestamp && branchName && timestamp !== "" && branchName !== "") {
+ const reportUrl = `https://multiversx.github.io/mx-chain-testing-suite/reports/${branchName}/${timestamp}/index.html`;
+ message = `
+ 📊 **MultiversX Automated Test Report:** [View Report](${reportUrl})
+
+ 🔄 **Build Details:**
+ - **mx-chain-go Commit Hash:** \`${commitHash}\`
+ - **Current Branch:** \`${currentBranch}\`
+ - **mx-chain-go Target Branch:** \`${goTargetBranch}\`
+ - **mx-chain-simulator-go Target Branch:** \`${simulatorTargetBranch}\`
+ - **mx-chain-testing-suite Target Branch:** \`${testingSuiteTargetBranch}\`
+
+ 🚀 **Environment Variables:**
+ - **TIMESTAMP:** \`${timestamp}\`
+ - **PYTEST_EXIT_CODE:** \`${exitCode}\`
+ 🎉 **MultiversX CI/CD Workflow Complete!**
+ `;
+ } else {
+ message = "⚠️ No report was generated due to an error or cancellation of the process.\nPlease checkout gh action logs for details";
+ }
+
+ github.rest.issues.createComment({
+ issue_number: issue_number,
+ owner: owner,
+ repo: repo,
+ body: message
+ });
+
+ - name: Fail job if tests failed
+ if: always()
+ run: |
+ if [ "${{ env.PYTEST_EXIT_CODE }}" != "0" ]; then
+ echo "Tests failed with exit code ${{ env.PYTEST_EXIT_CODE }}"
+ exit 1
+ else
+ echo "Tests passed successfully."
+ fi
\ No newline at end of file
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index b43adf3ef0e..8f8985811cc 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-latest]
runs-on: ${{ matrix.runs-on }}
name: Build
steps:
diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml
index 81fd087a704..bac2bab26b7 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]
runs-on: ${{ matrix.runs-on }}
name: Build
steps:
@@ -129,7 +129,7 @@ jobs:
zip -r -j ${ARCHIVE} ${BUILD_DIR}
- name: Save artifacts
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ env.ARCHIVE }}
path: ${{ env.ARCHIVE }}
@@ -145,7 +145,7 @@ jobs:
# https://docs.github.com/en/free-pro-team@latest/actions/guides/storing-workflow-data-as-artifacts#downloading-or-deleting-artifacts
# A directory for each artifact is created using its name
- name: Download all workflow run artifacts
- uses: actions/download-artifact@v2
+ uses: actions/download-artifact@v4
with:
path: assets
diff --git a/.github/workflows/docker-keygenerator.yaml b/.github/workflows/docker-keygenerator.yaml
index 5e4d9d44a32..c3cca7fc279 100644
--- a/.github/workflows/docker-keygenerator.yaml
+++ b/.github/workflows/docker-keygenerator.yaml
@@ -2,7 +2,6 @@ name: Build & push keygenerator docker image
on:
workflow_dispatch:
- pull_request:
jobs:
build-docker-image:
@@ -19,7 +18,6 @@ jobs:
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 }}
@@ -32,5 +30,5 @@ jobs:
context: .
file: ./docker/keygenerator/Dockerfile
platforms: linux/amd64,linux/arm64
- push: ${{ github.event_name != 'pull_request' }}
+ push: true
tags: multiversx/chain-keygenerator:latest
diff --git a/api/errors/errors.go b/api/errors/errors.go
index b01cec657ca..3f4e495b9d2 100644
--- a/api/errors/errors.go
+++ b/api/errors/errors.go
@@ -64,6 +64,9 @@ var ErrTxGenerationFailed = errors.New("transaction generation failed")
// ErrValidationEmptyTxHash signals that an empty tx hash was provided
var ErrValidationEmptyTxHash = errors.New("TxHash is empty")
+// ErrValidationEmptySCRHash signals that provided smart contract result hash is empty
+var ErrValidationEmptySCRHash = errors.New("SCRHash is empty")
+
// ErrInvalidBlockNonce signals that an invalid block nonce was provided
var ErrInvalidBlockNonce = errors.New("invalid block nonce")
@@ -79,6 +82,9 @@ var ErrValidationEmptyBlockHash = errors.New("block hash is empty")
// ErrGetTransaction signals an error happening when trying to fetch a transaction
var ErrGetTransaction = errors.New("getting transaction failed")
+// ErrGetSmartContractResults signals an error happening when trying to fetch smart contract results
+var ErrGetSmartContractResults = errors.New("getting smart contract results failed")
+
// ErrGetBlock signals an error happening when trying to fetch a block
var ErrGetBlock = errors.New("getting block failed")
@@ -174,3 +180,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/blockGroup.go b/api/groups/blockGroup.go
index 26d9c05b000..f9f0ed81fd8 100644
--- a/api/groups/blockGroup.go
+++ b/api/groups/blockGroup.go
@@ -26,6 +26,7 @@ const (
urlParamTokensFilter = "tokens"
urlParamWithTxs = "withTxs"
urlParamWithLogs = "withLogs"
+ urlParamForHyperblock = "forHyperblock"
)
// blockFacadeHandler defines the methods to be implemented by a facade for handling block requests
@@ -219,7 +220,12 @@ func parseBlockQueryOptions(c *gin.Context) (api.BlockQueryOptions, error) {
return api.BlockQueryOptions{}, err
}
- options := api.BlockQueryOptions{WithTransactions: withTxs, WithLogs: withLogs}
+ forHyperBlock, err := parseBoolUrlParam(c, urlParamForHyperblock)
+ if err != nil {
+ return api.BlockQueryOptions{}, err
+ }
+
+ options := api.BlockQueryOptions{WithTransactions: withTxs, WithLogs: withLogs, ForHyperblock: forHyperBlock}
return options, nil
}
diff --git a/api/groups/blockGroup_test.go b/api/groups/blockGroup_test.go
index b190c2f0561..a2ebc61548b 100644
--- a/api/groups/blockGroup_test.go
+++ b/api/groups/blockGroup_test.go
@@ -90,7 +90,7 @@ func TestBlockGroup_getBlockByNonce(t *testing.T) {
t.Parallel()
providedNonce := uint64(37)
- expectedOptions := api.BlockQueryOptions{WithTransactions: true}
+ expectedOptions := api.BlockQueryOptions{WithTransactions: true, ForHyperblock: true}
expectedBlock := api.Block{
Nonce: 37,
Round: 39,
@@ -107,7 +107,7 @@ func TestBlockGroup_getBlockByNonce(t *testing.T) {
loadBlockGroupResponse(
t,
facade,
- fmt.Sprintf("/block/by-nonce/%d?withTxs=true", providedNonce),
+ fmt.Sprintf("/block/by-nonce/%d?withTxs=true&forHyperblock=true", providedNonce),
"GET",
nil,
response,
diff --git a/api/groups/networkGroup.go b/api/groups/networkGroup.go
index ae0cca6846d..8a8e7854f9d 100644
--- a/api/groups/networkGroup.go
+++ b/api/groups/networkGroup.go
@@ -117,7 +117,7 @@ func NewNetworkGroup(facade networkFacadeHandler) (*networkGroup, error) {
{
Path: getNFTsPath,
Method: http.MethodGet,
- Handler: ng.getHandlerFuncForEsdt(core.NonFungibleESDT),
+ Handler: ng.getHandlerFuncForEsdt(core.NonFungibleESDTv2),
},
{
Path: directStakedInfoPath,
diff --git a/api/groups/networkGroup_test.go b/api/groups/networkGroup_test.go
index 3eb52a4a0c0..c809a632b56 100644
--- a/api/groups/networkGroup_test.go
+++ b/api/groups/networkGroup_test.go
@@ -206,6 +206,36 @@ func TestNetworkConfigMetrics_GasLimitGuardedTxShouldWork(t *testing.T) {
assert.True(t, keyAndValueFoundInResponse)
}
+func TestNetworkConfigMetrics_GasLimitRelayedTxShouldWork(t *testing.T) {
+ t.Parallel()
+
+ statusMetricsProvider := statusHandler.NewStatusMetrics()
+ key := common.MetricExtraGasLimitRelayedTx
+ val := uint64(123)
+ statusMetricsProvider.SetUInt64Value(key, val)
+
+ facade := mock.FacadeStub{}
+ facade.StatusMetricsHandler = func() external.StatusMetricsHandler {
+ return statusMetricsProvider
+ }
+
+ networkGroup, err := groups.NewNetworkGroup(&facade)
+ require.NoError(t, err)
+
+ ws := startWebServer(networkGroup, "network", getNetworkRoutesConfig())
+
+ req, _ := http.NewRequest("GET", "/network/config", nil)
+ resp := httptest.NewRecorder()
+ ws.ServeHTTP(resp, req)
+
+ respBytes, _ := io.ReadAll(resp.Body)
+ respStr := string(respBytes)
+ assert.Equal(t, resp.Code, http.StatusOK)
+
+ keyAndValueFoundInResponse := strings.Contains(respStr, key) && strings.Contains(respStr, fmt.Sprintf("%d", val))
+ assert.True(t, keyAndValueFoundInResponse)
+}
+
func TestNetworkStatusMetrics_ShouldWork(t *testing.T) {
t.Parallel()
diff --git a/api/groups/transactionGroup.go b/api/groups/transactionGroup.go
index 3c62221d121..86f04dfca22 100644
--- a/api/groups/transactionGroup.go
+++ b/api/groups/transactionGroup.go
@@ -26,11 +26,13 @@ const (
simulateTransactionEndpoint = "/transaction/simulate"
sendMultipleTransactionsEndpoint = "/transaction/send-multiple"
getTransactionEndpoint = "/transaction/:hash"
+ getScrsByTxHashEndpoint = "/transaction/scrs-by-tx-hash/:txhash"
sendTransactionPath = "/send"
simulateTransactionPath = "/simulate"
costPath = "/cost"
sendMultiplePath = "/send-multiple"
getTransactionPath = "/:txhash"
+ getScrsByTxHashPath = "/scrs-by-tx-hash/:txhash"
getTransactionsPool = "/pool"
queryParamWithResults = "withResults"
@@ -39,6 +41,7 @@ const (
queryParamFields = "fields"
queryParamLastNonce = "last-nonce"
queryParamNonceGaps = "nonce-gaps"
+ queryParameterScrHash = "scrHash"
)
// transactionFacadeHandler defines the methods to be implemented by a facade for transaction requests
@@ -49,6 +52,7 @@ type transactionFacadeHandler interface {
SendBulkTransactions([]*transaction.Transaction) (uint64, error)
SimulateTransactionExecution(tx *transaction.Transaction) (*txSimData.SimulationResultsWithVMOutput, error)
GetTransaction(hash string, withResults bool) (*transaction.ApiTransactionResult, error)
+ GetSCRsByTxHash(txHash string, scrHash string) ([]*transaction.ApiSmartContractResult, error)
GetTransactionsPool(fields string) (*common.TransactionsPoolAPIResponse, error)
GetTransactionsPoolForSender(sender, fields string) (*common.TransactionsPoolForSenderApiResponse, error)
GetLastPoolNonceForSender(sender string) (uint64, error)
@@ -137,6 +141,17 @@ func NewTransactionGroup(facade transactionFacadeHandler) (*transactionGroup, er
},
},
},
+ {
+ Path: getScrsByTxHashPath,
+ Method: http.MethodGet,
+ Handler: tg.getScrsByTxHash,
+ AdditionalMiddlewares: []shared.AdditionalMiddleware{
+ {
+ Middleware: middleware.CreateEndpointThrottlerFromFacade(getScrsByTxHashEndpoint, facade),
+ Position: shared.Before,
+ },
+ },
+ },
}
tg.endpoints = endpoints
@@ -182,27 +197,7 @@ 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,
- }
- start := time.Now()
- tx, txHash, err := tg.getFacade().CreateTransaction(txArgs)
- logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction")
-
+ tx, txHash, err := tg.createTransaction(&ftx)
if err != nil {
c.JSON(
http.StatusBadRequest,
@@ -215,7 +210,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 +267,7 @@ 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,
- }
- start := time.Now()
- tx, txHash, err := tg.getFacade().CreateTransaction(txArgs)
- logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction")
+ tx, txHash, err := tg.createTransaction(&ftx)
if err != nil {
c.JSON(
http.StatusBadRequest,
@@ -304,7 +280,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 +346,7 @@ 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,
- }
- tx, txHash, err = tg.getFacade().CreateTransaction(txArgs)
- logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction")
+ tx, txHash, err = tg.createTransaction(&receivedTx)
if err != nil {
continue
}
@@ -430,6 +388,57 @@ func (tg *transactionGroup) sendMultipleTransactions(c *gin.Context) {
)
}
+func (tg *transactionGroup) getScrsByTxHash(c *gin.Context) {
+ txhash := c.Param("txhash")
+ if txhash == "" {
+ c.JSON(
+ http.StatusBadRequest,
+ shared.GenericAPIResponse{
+ Data: nil,
+ Error: fmt.Sprintf("%s: %s", errors.ErrValidation.Error(), errors.ErrValidationEmptyTxHash.Error()),
+ Code: shared.ReturnCodeRequestError,
+ },
+ )
+ return
+ }
+ scrHashStr := c.Request.URL.Query().Get(queryParameterScrHash)
+ if scrHashStr == "" {
+ c.JSON(
+ http.StatusBadRequest,
+ shared.GenericAPIResponse{
+ Data: nil,
+ Error: fmt.Sprintf("%s: %s", errors.ErrValidation.Error(), errors.ErrValidationEmptySCRHash.Error()),
+ Code: shared.ReturnCodeRequestError,
+ },
+ )
+ return
+ }
+
+ start := time.Now()
+ scrs, err := tg.getFacade().GetSCRsByTxHash(txhash, scrHashStr)
+ if err != nil {
+ c.JSON(
+ http.StatusInternalServerError,
+ shared.GenericAPIResponse{
+ Data: nil,
+ Error: fmt.Sprintf("%s: %s", errors.ErrGetSmartContractResults.Error(), err.Error()),
+ Code: shared.ReturnCodeInternalError,
+ },
+ )
+ return
+ }
+ logging.LogAPIActionDurationIfNeeded(start, "API call: GetSCRsByTxHash")
+
+ c.JSON(
+ http.StatusOK,
+ shared.GenericAPIResponse{
+ Data: gin.H{"scrs": scrs},
+ Error: "",
+ Code: shared.ReturnCodeSuccess,
+ },
+ )
+}
+
// getTransaction returns transaction details for a given txhash
func (tg *transactionGroup) getTransaction(c *gin.Context) {
txhash := c.Param("txhash")
@@ -499,26 +508,7 @@ 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,
- }
- start := time.Now()
- tx, _, err := tg.getFacade().CreateTransaction(txArgs)
- logging.LogAPIActionDurationIfNeeded(start, "API call: CreateTransaction")
+ tx, _, err := tg.createTransaction(&ftx)
if err != nil {
c.JSON(
http.StatusInternalServerError,
@@ -531,7 +521,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 +718,33 @@ func (tg *transactionGroup) getTransactionsPoolNonceGapsForSender(sender string,
)
}
+func (tg *transactionGroup) createTransaction(receivedTx *transaction.FrontendTransaction) (*transaction.Transaction, []byte, error) {
+ txArgs := &external.ArgsCreateTransaction{
+ Nonce: receivedTx.Nonce,
+ Value: receivedTx.Value,
+ Receiver: receivedTx.Receiver,
+ ReceiverUsername: receivedTx.ReceiverUsername,
+ Sender: receivedTx.Sender,
+ SenderUsername: receivedTx.SenderUsername,
+ GasPrice: receivedTx.GasPrice,
+ GasLimit: receivedTx.GasLimit,
+ DataField: receivedTx.Data,
+ SignatureHex: receivedTx.Signature,
+ ChainID: receivedTx.ChainID,
+ Version: receivedTx.Version,
+ Options: receivedTx.Options,
+ Guardian: receivedTx.GuardianAddr,
+ GuardianSigHex: receivedTx.GuardianSignature,
+ Relayer: receivedTx.RelayerAddr,
+ RelayerSignatureHex: receivedTx.RelayerSignature,
+ }
+ 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
diff --git a/api/groups/transactionGroup_test.go b/api/groups/transactionGroup_test.go
index 22085956fe9..9f603412ae0 100644
--- a/api/groups/transactionGroup_test.go
+++ b/api/groups/transactionGroup_test.go
@@ -342,6 +342,76 @@ func TestTransactionGroup_sendTransaction(t *testing.T) {
})
}
+func TestTransactionsGroup_getSCRsByTxHash(t *testing.T) {
+ t.Parallel()
+
+ t.Run("get SCRsByTxHash empty scr hash should error", func(t *testing.T) {
+ facade := &mock.FacadeStub{}
+
+ transactionGroup, err := groups.NewTransactionGroup(facade)
+ require.NoError(t, err)
+
+ ws := startWebServer(transactionGroup, "transaction", getTransactionRoutesConfig())
+
+ req, _ := http.NewRequest(http.MethodGet, "/transaction/scrs-by-tx-hash/txHash", bytes.NewBuffer([]byte{}))
+ 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.ErrValidationEmptySCRHash.Error()))
+ assert.Empty(t, txResp.Data)
+ })
+ t.Run("get scrs facade error", func(t *testing.T) {
+ localErr := fmt.Errorf("error")
+ facade := &mock.FacadeStub{
+ GetSCRsByTxHashCalled: func(txHash string, scrHash string) ([]*dataTx.ApiSmartContractResult, error) {
+ return nil, localErr
+ },
+ }
+
+ transactionGroup, err := groups.NewTransactionGroup(facade)
+ require.NoError(t, err)
+
+ ws := startWebServer(transactionGroup, "transaction", getTransactionRoutesConfig())
+
+ req, _ := http.NewRequest(http.MethodGet, "/transaction/scrs-by-tx-hash/txhash?scrHash=hash", bytes.NewBuffer([]byte{}))
+ resp := httptest.NewRecorder()
+ ws.ServeHTTP(resp, req)
+
+ txResp := shared.GenericAPIResponse{}
+ loadResponse(resp.Body, &txResp)
+
+ assert.Equal(t, http.StatusInternalServerError, resp.Code)
+ assert.True(t, strings.Contains(txResp.Error, localErr.Error()))
+ assert.Empty(t, txResp.Data)
+ })
+ t.Run("get scrs should work", func(t *testing.T) {
+ facade := &mock.FacadeStub{
+ GetSCRsByTxHashCalled: func(txHash string, scrHash string) ([]*dataTx.ApiSmartContractResult, error) {
+ return []*dataTx.ApiSmartContractResult{}, nil
+ },
+ }
+
+ transactionGroup, err := groups.NewTransactionGroup(facade)
+ require.NoError(t, err)
+
+ ws := startWebServer(transactionGroup, "transaction", getTransactionRoutesConfig())
+
+ req, _ := http.NewRequest(http.MethodGet, "/transaction/scrs-by-tx-hash/txhash?scrHash=hash", bytes.NewBuffer([]byte{}))
+ resp := httptest.NewRecorder()
+ ws.ServeHTTP(resp, req)
+
+ txResp := shared.GenericAPIResponse{}
+ loadResponse(resp.Body, &txResp)
+
+ assert.Equal(t, http.StatusOK, resp.Code)
+ assert.Equal(t, "", txResp.Error)
+ })
+}
+
func TestTransactionGroup_sendMultipleTransactions(t *testing.T) {
t.Parallel()
@@ -1122,6 +1192,7 @@ func getTransactionRoutesConfig() config.ApiRoutesConfig {
{Name: "/:txhash", Open: true},
{Name: "/:txhash/status", Open: true},
{Name: "/simulate", Open: true},
+ {Name: "/scrs-by-tx-hash/:txhash", Open: true},
},
},
},
diff --git a/api/mock/facadeStub.go b/api/mock/facadeStub.go
index e40645c1ac3..62de2febc81 100644
--- a/api/mock/facadeStub.go
+++ b/api/mock/facadeStub.go
@@ -97,6 +97,16 @@ type FacadeStub struct {
GetWaitingEpochsLeftForPublicKeyCalled func(publicKey string) (uint32, error)
P2PPrometheusMetricsEnabledCalled func() bool
AuctionListHandler func() ([]*common.AuctionListValidatorAPIResponse, error)
+ GetSCRsByTxHashCalled func(txHash string, scrHash string) ([]*transaction.ApiSmartContractResult, error)
+}
+
+// GetSCRsByTxHash -
+func (f *FacadeStub) GetSCRsByTxHash(txHash string, scrHash string) ([]*transaction.ApiSmartContractResult, error) {
+ if f.GetSCRsByTxHashCalled != nil {
+ return f.GetSCRsByTxHashCalled(txHash, scrHash)
+ }
+
+ return nil, nil
}
// GetTokenSupply -
diff --git a/api/shared/interface.go b/api/shared/interface.go
index 4b775ebdd39..206cea6ee30 100644
--- a/api/shared/interface.go
+++ b/api/shared/interface.go
@@ -135,6 +135,7 @@ type FacadeHandler interface {
GetEligibleManagedKeys() ([]string, error)
GetWaitingManagedKeys() ([]string, error)
GetWaitingEpochsLeftForPublicKey(publicKey string) (uint32, error)
+ GetSCRsByTxHash(txHash string, scrHash string) ([]*transaction.ApiSmartContractResult, error)
P2PPrometheusMetricsEnabled() bool
IsInterfaceNil() bool
}
diff --git a/cmd/node/config/api.toml b/cmd/node/config/api.toml
index a10ec049554..fcf9cf7fc0b 100644
--- a/cmd/node/config/api.toml
+++ b/cmd/node/config/api.toml
@@ -221,6 +221,9 @@
# /transaction/:txhash will return the transaction in JSON format based on its hash
{ Name = "/:txhash", Open = true },
+
+ # /transaction/scrs-by-tx-hash/:txhash will return the smart contract results generated by the provided transaction hash
+ { Name = "/scrs-by-tx-hash/:txhash", Open = true },
]
[APIPackages.block]
diff --git a/cmd/node/config/config.toml b/cmd/node/config/config.toml
index 16277a259f1..85bd2557636 100644
--- a/cmd/node/config/config.toml
+++ b/cmd/node/config/config.toml
@@ -394,9 +394,9 @@
[TxDataPool]
Name = "TxDataPool"
Capacity = 600000
- SizePerSender = 20000
+ SizePerSender = 5001
SizeInBytes = 419430400 #400MB
- SizeInBytesPerSender = 12288000
+ SizeInBytesPerSender = 12288000 #12MB
Type = "TxCache"
Shards = 16
diff --git a/cmd/node/config/enableEpochs.toml b/cmd/node/config/enableEpochs.toml
index 4307c976acc..b2fc119d6a4 100644
--- a/cmd/node/config/enableEpochs.toml
+++ b/cmd/node/config/enableEpochs.toml
@@ -309,14 +309,32 @@
# AlwaysMergeContextsInEEIEnableEpoch represents the epoch in which the EEI will always merge the contexts
AlwaysMergeContextsInEEIEnableEpoch = 1
+ # UseGasBoundedShouldFailExecutionEnableEpoch represents the epoch when use bounded gas function should fail execution in case of error
+ UseGasBoundedShouldFailExecutionEnableEpoch = 1
+
# DynamicESDTEnableEpoch represents the epoch when dynamic NFT feature is enabled
- DynamicESDTEnableEpoch = 4
+ DynamicESDTEnableEpoch = 1
# EGLDInMultiTransferEnableEpoch represents the epoch when EGLD in multitransfer is enabled
- EGLDInMultiTransferEnableEpoch = 4
+ EGLDInMultiTransferEnableEpoch = 1
# CryptoOpcodesV2EnableEpoch represents the epoch when BLSMultiSig, Secp256r1 and other opcodes are enabled
- CryptoOpcodesV2EnableEpoch = 4
+ CryptoOpcodesV2EnableEpoch = 1
+
+ # UnjailCleanupEnableEpoch represents the epoch when the cleanup of the unjailed nodes is enabled
+ UnJailCleanupEnableEpoch = 1
+
+ # FixRelayedBaseCostEnableEpoch represents the epoch when the fix for relayed base cost will be enabled
+ FixRelayedBaseCostEnableEpoch = 1
+
+ # MultiESDTNFTTransferAndExecuteByUserEnableEpoch represents the epoch when enshrined sovereign cross chain opcodes are enabled
+ MultiESDTNFTTransferAndExecuteByUserEnableEpoch = 9999999
+
+ # FixRelayedMoveBalanceToNonPayableSCEnableEpoch represents the epoch when the fix for relayed move balance to non payable sc will be enabled
+ FixRelayedMoveBalanceToNonPayableSCEnableEpoch = 1
+
+ # RelayedTransactionsV3EnableEpoch represents the epoch when the relayed transactions v3 will be enabled
+ RelayedTransactionsV3EnableEpoch = 1
# EquivalentMessagesEnableEpoch represents the epoch when the equivalent messages are enabled
EquivalentMessagesEnableEpoch = 8 # the chain simulator tests for staking v4 fail if this is set earlier, as they test the transition in epochs 4-7
diff --git a/cmd/node/config/external.toml b/cmd/node/config/external.toml
index 1058e0c3fb7..6fbbbb195c6 100644
--- a/cmd/node/config/external.toml
+++ b/cmd/node/config/external.toml
@@ -51,7 +51,7 @@
# URL for the WebSocket client/server connection
# This value represents the IP address and port number that the WebSocket client or server will use to establish a connection.
- URL = "127.0.0.1:22111"
+ URL = "ws://127.0.0.1:22111"
# After a message will be sent it will wait for an ack message if this flag is enabled
WithAcknowledge = true
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
index 424c07e79f2..7a0c11de4e9 100644
--- a/cmd/node/config/gasSchedules/gasScheduleV8.toml
+++ b/cmd/node/config/gasSchedules/gasScheduleV8.toml
@@ -113,6 +113,7 @@
GetCallbackClosure = 10000
GetCodeMetadata = 10000
IsBuiltinFunction = 10000
+ IsReservedFunctionName = 10000
[EthAPICost]
UseGas = 100
diff --git a/cmd/node/main.go b/cmd/node/main.go
index 2ce7fb6c626..c75dd40a393 100644
--- a/cmd/node/main.go
+++ b/cmd/node/main.go
@@ -299,6 +299,7 @@ func attachFileLogger(log logger.Logger, flagsConfig *config.ContextFlagsConfig)
logger.ToggleCorrelation(flagsConfig.EnableLogCorrelation)
logger.ToggleLoggerName(flagsConfig.EnableLogName)
logLevelFlagValue := flagsConfig.LogLevel
+
err = logger.SetLogLevel(logLevelFlagValue)
if err != nil {
return nil, err
diff --git a/common/common.go b/common/common.go
index 3d5e874c231..b2c035ca240 100644
--- a/common/common.go
+++ b/common/common.go
@@ -10,6 +10,29 @@ import (
"github.com/multiversx/mx-chain-vm-v1_2-go/ipc/marshaling"
)
+// IsValidRelayedTxV3 returns true if the provided transaction is a valid transaction of type relayed v3
+func IsValidRelayedTxV3(tx data.TransactionHandler) bool {
+ relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler)
+ if !isRelayedV3 {
+ return false
+ }
+ hasValidRelayer := len(relayedTx.GetRelayerAddr()) == len(tx.GetSndAddr()) && len(relayedTx.GetRelayerAddr()) > 0
+ hasValidRelayerSignature := len(relayedTx.GetRelayerSignature()) == len(relayedTx.GetSignature()) && len(relayedTx.GetRelayerSignature()) > 0
+ return hasValidRelayer && hasValidRelayerSignature
+}
+
+// IsRelayedTxV3 returns true if the provided transaction is a transaction of type relayed v3, without any further checks
+func IsRelayedTxV3(tx data.TransactionHandler) bool {
+ relayedTx, isRelayedV3 := tx.(data.RelayedTransactionHandler)
+ if !isRelayedV3 {
+ return false
+ }
+
+ hasRelayer := len(relayedTx.GetRelayerAddr()) > 0
+ hasRelayerSignature := len(relayedTx.GetRelayerSignature()) > 0
+ return hasRelayer || hasRelayerSignature
+}
+
// IsEpochChangeBlockForFlagActivation returns true if the provided header is the first one after the specified flag's activation
func IsEpochChangeBlockForFlagActivation(header data.HeaderHandler, enableEpochsHandler EnableEpochsHandler, flag core.EnableEpochFlag) bool {
isStartOfEpochBlock := header.IsStartOfEpochBlock()
diff --git a/common/common_test.go b/common/common_test.go
new file mode 100644
index 00000000000..5a0ec53a21f
--- /dev/null
+++ b/common/common_test.go
@@ -0,0 +1,70 @@
+package common
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/multiversx/mx-chain-core-go/data/smartContractResult"
+ "github.com/multiversx/mx-chain-core-go/data/transaction"
+ "github.com/stretchr/testify/require"
+)
+
+func TestIsValidRelayedTxV3(t *testing.T) {
+ t.Parallel()
+
+ scr := &smartContractResult.SmartContractResult{}
+ require.False(t, IsValidRelayedTxV3(scr))
+ require.False(t, IsRelayedTxV3(scr))
+
+ notRelayedTxV3 := &transaction.Transaction{
+ Nonce: 1,
+ Value: big.NewInt(100),
+ RcvAddr: []byte("receiver"),
+ SndAddr: []byte("sender0"),
+ GasPrice: 100,
+ GasLimit: 10,
+ Signature: []byte("signature"),
+ }
+ require.False(t, IsValidRelayedTxV3(notRelayedTxV3))
+ require.False(t, IsRelayedTxV3(notRelayedTxV3))
+
+ invalidRelayedTxV3 := &transaction.Transaction{
+ Nonce: 1,
+ Value: big.NewInt(100),
+ RcvAddr: []byte("receiver"),
+ SndAddr: []byte("sender0"),
+ GasPrice: 100,
+ GasLimit: 10,
+ Signature: []byte("signature"),
+ RelayerAddr: []byte("relayer"),
+ }
+ require.False(t, IsValidRelayedTxV3(invalidRelayedTxV3))
+ require.True(t, IsRelayedTxV3(invalidRelayedTxV3))
+
+ invalidRelayedTxV3 = &transaction.Transaction{
+ Nonce: 1,
+ Value: big.NewInt(100),
+ RcvAddr: []byte("receiver"),
+ SndAddr: []byte("sender0"),
+ GasPrice: 100,
+ GasLimit: 10,
+ Signature: []byte("signature"),
+ RelayerSignature: []byte("signature"),
+ }
+ require.False(t, IsValidRelayedTxV3(invalidRelayedTxV3))
+ require.True(t, IsRelayedTxV3(invalidRelayedTxV3))
+
+ relayedTxV3 := &transaction.Transaction{
+ Nonce: 1,
+ Value: big.NewInt(100),
+ RcvAddr: []byte("receiver"),
+ SndAddr: []byte("sender1"),
+ GasPrice: 100,
+ GasLimit: 10,
+ Signature: []byte("signature"),
+ RelayerAddr: []byte("relayer"),
+ RelayerSignature: []byte("signature"),
+ }
+ require.True(t, IsValidRelayedTxV3(relayedTxV3))
+ require.True(t, IsRelayedTxV3(relayedTxV3))
+}
diff --git a/common/constants.go b/common/constants.go
index 4f9ac681316..755a07ecab8 100644
--- a/common/constants.go
+++ b/common/constants.go
@@ -343,6 +343,9 @@ const MetricMinGasLimit = "erd_min_gas_limit"
// MetricExtraGasLimitGuardedTx specifies the extra gas limit required for guarded transactions
const MetricExtraGasLimitGuardedTx = "erd_extra_gas_limit_guarded_tx"
+// MetricExtraGasLimitRelayedTx specifies the extra gas limit required for relayed v3 transactions
+const MetricExtraGasLimitRelayedTx = "erd_extra_gas_limit_relayed_tx"
+
// MetricRewardsTopUpGradientPoint is the metric that specifies the rewards top up gradient point
const MetricRewardsTopUpGradientPoint = "erd_rewards_top_up_gradient_point"
@@ -498,6 +501,9 @@ const (
// MetricRelayedTransactionsV2EnableEpoch represents the epoch when the relayed transactions v2 is enabled
MetricRelayedTransactionsV2EnableEpoch = "erd_relayed_transactions_v2_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"
@@ -731,6 +737,15 @@ 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"
+
+ // MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch represents the epoch when the fix for relayed move balance to non-payable sc is enabled
+ MetricFixRelayedMoveBalanceToNonPayableSCEnableEpoch = "erd_fix_relayed_move_balance_to_non_payable_sc_enable_epoch"
+
+ // MetricRelayedTransactionsV3EnableEpoch represents the epoch when the relayed transactions v3 are enabled
+ MetricRelayedTransactionsV3EnableEpoch = "erd_relayed_transactions_v3_enable_epoch"
+
// MetricMaxNodesChangeEnableEpoch holds configuration for changing the maximum number of nodes and the enabling epoch
MetricMaxNodesChangeEnableEpoch = "erd_max_nodes_change_enable_epoch"
@@ -1224,9 +1239,15 @@ const (
CleanupAuctionOnLowWaitingListFlag core.EnableEpochFlag = "CleanupAuctionOnLowWaitingListFlag"
StakingV4StartedFlag core.EnableEpochFlag = "StakingV4StartedFlag"
AlwaysMergeContextsInEEIFlag core.EnableEpochFlag = "AlwaysMergeContextsInEEIFlag"
+ UseGasBoundedShouldFailExecutionFlag core.EnableEpochFlag = "UseGasBoundedShouldFailExecutionFlag"
DynamicESDTFlag core.EnableEpochFlag = "DynamicEsdtFlag"
EGLDInESDTMultiTransferFlag core.EnableEpochFlag = "EGLDInESDTMultiTransferFlag"
CryptoOpcodesV2Flag core.EnableEpochFlag = "CryptoOpcodesV2Flag"
+ UnJailCleanupFlag core.EnableEpochFlag = "UnJailCleanupFlag"
+ FixRelayedBaseCostFlag core.EnableEpochFlag = "FixRelayedBaseCostFlag"
+ MultiESDTNFTTransferAndExecuteByUserFlag core.EnableEpochFlag = "MultiESDTNFTTransferAndExecuteByUserFlag"
+ FixRelayedMoveBalanceToNonPayableSCFlag core.EnableEpochFlag = "FixRelayedMoveBalanceToNonPayableSCFlag"
+ RelayedTransactionsV3Flag core.EnableEpochFlag = "RelayedTransactionsV3Flag"
EquivalentMessagesFlag core.EnableEpochFlag = "EquivalentMessagesFlag"
FixedOrderInConsensusFlag core.EnableEpochFlag = "FixedOrderInConsensusFlag"
// all new flags must be added to createAllFlagsMap method, as part of enableEpochsHandler allFlagsDefined
diff --git a/common/converters.go b/common/converters.go
index 036cce7d070..83ccbc084e1 100644
--- a/common/converters.go
+++ b/common/converters.go
@@ -23,7 +23,7 @@ func ProcessDestinationShardAsObserver(destinationShardIdAsObserver string) (uin
val, err := strconv.ParseUint(destShard, 10, 32)
if err != nil {
- return 0, fmt.Errorf("error parsing DestinationShardAsObserver option: " + err.Error())
+ return 0, fmt.Errorf("error parsing DestinationShardAsObserver option: %s", err.Error())
}
return uint32(val), err
diff --git a/common/enablers/enableEpochsHandler.go b/common/enablers/enableEpochsHandler.go
index dac7e1aba6b..c7826d86c5a 100644
--- a/common/enablers/enableEpochsHandler.go
+++ b/common/enablers/enableEpochsHandler.go
@@ -732,6 +732,12 @@ func (handler *enableEpochsHandler) createAllFlagsMap() {
},
activationEpoch: handler.enableEpochsConfig.AlwaysMergeContextsInEEIEnableEpoch,
},
+ common.UseGasBoundedShouldFailExecutionFlag: {
+ isActiveInEpoch: func(epoch uint32) bool {
+ return epoch >= handler.enableEpochsConfig.UseGasBoundedShouldFailExecutionEnableEpoch
+ },
+ activationEpoch: handler.enableEpochsConfig.UseGasBoundedShouldFailExecutionEnableEpoch,
+ },
common.DynamicESDTFlag: {
isActiveInEpoch: func(epoch uint32) bool {
return epoch >= handler.enableEpochsConfig.DynamicESDTEnableEpoch
@@ -750,6 +756,36 @@ 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.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,
+ },
+ common.FixRelayedMoveBalanceToNonPayableSCFlag: {
+ isActiveInEpoch: func(epoch uint32) bool {
+ return epoch >= handler.enableEpochsConfig.FixRelayedMoveBalanceToNonPayableSCEnableEpoch
+ },
+ activationEpoch: handler.enableEpochsConfig.FixRelayedMoveBalanceToNonPayableSCEnableEpoch,
+ },
+ common.RelayedTransactionsV3Flag: {
+ isActiveInEpoch: func(epoch uint32) bool {
+ return epoch >= handler.enableEpochsConfig.RelayedTransactionsV3EnableEpoch
+ },
+ activationEpoch: handler.enableEpochsConfig.RelayedTransactionsV3EnableEpoch,
+ },
common.EquivalentMessagesFlag: {
isActiveInEpoch: func(epoch uint32) bool {
return epoch >= handler.enableEpochsConfig.EquivalentMessagesEnableEpoch
diff --git a/common/enablers/enableEpochsHandler_test.go b/common/enablers/enableEpochsHandler_test.go
index a1b47200647..7bd3673b786 100644
--- a/common/enablers/enableEpochsHandler_test.go
+++ b/common/enablers/enableEpochsHandler_test.go
@@ -119,8 +119,13 @@ func createEnableEpochsConfig() config.EnableEpochs {
DynamicESDTEnableEpoch: 102,
EGLDInMultiTransferEnableEpoch: 103,
CryptoOpcodesV2EnableEpoch: 104,
- EquivalentMessagesEnableEpoch: 105,
- FixedOrderInConsensusEnableEpoch: 106,
+ FixRelayedBaseCostEnableEpoch: 105,
+ MultiESDTNFTTransferAndExecuteByUserEnableEpoch: 106,
+ FixRelayedMoveBalanceToNonPayableSCEnableEpoch: 107,
+ UseGasBoundedShouldFailExecutionEnableEpoch: 108,
+ RelayedTransactionsV3EnableEpoch: 109,
+ EquivalentMessagesEnableEpoch: 110,
+ FixedOrderInConsensusEnableEpoch: 111,
}
}
@@ -321,6 +326,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.FixRelayedBaseCostFlag))
+ require.True(t, handler.IsFlagEnabled(common.FixRelayedMoveBalanceToNonPayableSCFlag))
require.True(t, handler.IsFlagEnabled(common.EquivalentMessagesFlag))
require.True(t, handler.IsFlagEnabled(common.FixedOrderInConsensusFlag))
}
@@ -439,9 +446,14 @@ func TestEnableEpochsHandler_GetActivationEpoch(t *testing.T) {
require.Equal(t, cfg.CleanupAuctionOnLowWaitingListEnableEpoch, handler.GetActivationEpoch(common.CleanupAuctionOnLowWaitingListFlag))
require.Equal(t, cfg.StakingV4Step1EnableEpoch, handler.GetActivationEpoch(common.StakingV4StartedFlag))
require.Equal(t, cfg.AlwaysMergeContextsInEEIEnableEpoch, handler.GetActivationEpoch(common.AlwaysMergeContextsInEEIFlag))
+ require.Equal(t, cfg.UseGasBoundedShouldFailExecutionEnableEpoch, handler.GetActivationEpoch(common.UseGasBoundedShouldFailExecutionFlag))
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.FixRelayedBaseCostEnableEpoch, handler.GetActivationEpoch(common.FixRelayedBaseCostFlag))
+ require.Equal(t, cfg.MultiESDTNFTTransferAndExecuteByUserEnableEpoch, handler.GetActivationEpoch(common.MultiESDTNFTTransferAndExecuteByUserFlag))
+ require.Equal(t, cfg.FixRelayedMoveBalanceToNonPayableSCEnableEpoch, handler.GetActivationEpoch(common.FixRelayedMoveBalanceToNonPayableSCFlag))
+ require.Equal(t, cfg.RelayedTransactionsV3EnableEpoch, handler.GetActivationEpoch(common.RelayedTransactionsV3Flag))
require.Equal(t, cfg.EquivalentMessagesEnableEpoch, handler.GetActivationEpoch(common.EquivalentMessagesFlag))
require.Equal(t, cfg.FixedOrderInConsensusEnableEpoch, handler.GetActivationEpoch(common.FixedOrderInConsensusFlag))
}
diff --git a/common/reflectcommon/structFieldsUpdate.go b/common/reflectcommon/structFieldsUpdate.go
index 94ad6002c07..7f8940b0400 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 trySetMapValue(value, mapValue)
default:
return fmt.Errorf("unsupported type <%s> when trying to set the value '%v' of type <%s>", valueKind, newValue, reflect.TypeOf(newValue))
}
@@ -137,7 +141,7 @@ func trySetSliceValue(value *reflect.Value, newValue interface{}) error {
item := sliceVal.Index(i)
newItem := reflect.New(value.Type().Elem()).Elem()
- err := trySetStructValue(&newItem, item)
+ err := trySetTheNewValue(&newItem, item.Interface())
if err != nil {
return err
}
@@ -163,6 +167,31 @@ func trySetStructValue(value *reflect.Value, newValue reflect.Value) error {
}
}
+func trySetMapValue(value *reflect.Value, newValue reflect.Value) error {
+ if value.IsNil() {
+ value.Set(reflect.MakeMap(value.Type()))
+ }
+
+ 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..27a30ea9d00 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