Skip to content

Sync upstream v11.0.0 (merge conflicts)#49

Open
JOY (JOY) wants to merge 86 commits intomainfrom
sync-upstream-v11.0.0
Open

Sync upstream v11.0.0 (merge conflicts)#49
JOY (JOY) wants to merge 86 commits intomainfrom
sync-upstream-v11.0.0

Conversation

@JOY
Copy link
Copy Markdown

Upstream Sync - v11.0.0

Auto-merge with upstream v11.0.0 failed. Version/workflow conflicts were auto-resolved,
but the following files have code conflicts that need manual resolution:

apps/explorer/lib/explorer/chain/import/runner/internal_transactions.ex
apps/indexer/lib/indexer/fetcher/on_demand/contract_creator.ex
docker-compose/envs/common-blockscout.env

To resolve:

  1. Check out this branch locally
  2. Resolve remaining conflicts
  3. Push and merge this PR
  4. Then create tag v11.0.0 to trigger Docker build

Upstream release notes

dependabot Bot and others added 30 commits April 1, 2026 12:03
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#14171)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…, CONTRIBUTING.md and PULL_REQUEST_TEMPLATE.md to .github folder
Victor Baranov (vbaranov) and others added 20 commits April 16, 2026 17:44
…lockscout#14239)

Co-authored-by: Alexander Kolotov <alexander.kolotov@gmail.com>
Co-authored-by: Nikita Pozdniakov <nikitosing4@mail.ru>
Co-authored-by: Victor Baranov <baranov.viktor.27@gmail.com>
…CTION_ASSOCIATION flag to preload smart-contract associations (blockscout#14257)
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Comment on lines +26 to +97
name: Build matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
run: |
echo "matrix=$(node -e '

const defaultChainTypes = ["default"];

// Add/remove CI matrix chain types here
const chainTypes = [
"default",
"arbitrum",
"arc",
"blackfort",
"ethereum",
"filecoin",
"optimism",
"optimism-celo",
"rsk",
"scroll",
"shibarium",
"stability",
"zetachain",
"zilliqa",
"zksync",
"neon"
];

// Add/remove CI matrix chain types for "ci:core" label here
const coreChainTypes = [
"default",
"ethereum",
"optimism",
"optimism-celo"
];

const labels = ${{ github.event_name == 'pull_request' && toJson(github.event.pull_request.labels.*.name) || '[]' }};
const ciLabels = labels.filter(label => label.startsWith("ci:"));
const labeledChainTypes = chainTypes.filter(chainType =>
ciLabels.includes("ci:all") ||
ciLabels.includes("ci:core") && coreChainTypes.includes(chainType) ||
ciLabels.includes("ci:" + chainType)
);

// Chain type matrix we use in PRs to master branch
const ciChainTypes = labeledChainTypes.length > 0 ? labeledChainTypes : defaultChainTypes;

// Check for bridged tokens label
const hasBridgedTokensLabel = ciLabels.includes("ci:bridged-tokens");

// Create matrix combinations
const targetChainTypes = ${{ github.event_name == 'pull_request' && 'ciChainTypes' || 'chainTypes' }};
const bridgedTokensConfigs = hasBridgedTokensLabel ? [false, true] : [false];

const matrixIncludes = [];
for (const chainType of targetChainTypes) {
for (const bridgedTokens of bridgedTokensConfigs) {
matrixIncludes.push({
"chain-type": chainType,
"bridged-tokens": bridgedTokens
});
}
}

const matrix = { "include": matrixIncludes };
console.log(JSON.stringify(matrix));
')" >> $GITHUB_OUTPUT

build-and-cache:
Comment on lines +98 to +164
name: Build and Cache deps
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ env.OTP_VERSION }}
elixir-version: ${{ env.ELIXIR_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://cdn.jsdelivr.net/hex

- name: "ELIXIR_VERSION.lock"
run: echo "${ELIXIR_VERSION}" > ELIXIR_VERSION.lock

- name: "OTP_VERSION.lock"
run: echo "${OTP_VERSION}" > OTP_VERSION.lock

- name: Restore Mix Deps Cache
uses: actions/cache@v4
id: deps-cache
with:
path: |
deps
_build
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-

- name: Conditionally build Mix deps cache
if: steps.deps-cache.outputs.cache-hit != 'true'
run: |
mix local.hex --force
mix local.rebar --force
mix deps.clean --all
mix deps.get
mix deps.compile --skip-umbrella-children

- name: Restore Explorer NPM Cache
uses: actions/cache@v4
id: explorer-npm-cache
with:
path: apps/explorer/node_modules
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-${{ hashFiles('apps/explorer/package-lock.json') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-

- name: Conditionally build Explorer NPM Cache
if: steps.explorer-npm-cache.outputs.cache-hit != 'true'
run: npm install
working-directory: apps/explorer

- name: Restore Blockscout Web NPM Cache
uses: actions/cache@v4
id: blockscoutweb-npm-cache
with:
path: apps/block_scout_web/assets/node_modules
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-${{ hashFiles('apps/block_scout_web/assets/package-lock.json') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-

- name: Conditionally build Blockscout Web NPM Cache
if: steps.blockscoutweb-npm-cache.outputs.cache-hit != 'true'
run: npm install
working-directory: apps/block_scout_web/assets

credo:
Comment on lines +165 to +191
name: Credo
runs-on: ubuntu-latest
needs: build-and-cache
steps:
- uses: actions/checkout@v5
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ env.OTP_VERSION }}
elixir-version: ${{ env.ELIXIR_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://cdn.jsdelivr.net/hex

- name: Restore Mix Deps Cache
uses: actions/cache/restore@v4
id: deps-cache
with:
path: |
deps
_build
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-

- run: mix credo

check_formatted:
Comment on lines +192 to +218
name: Code formatting checks
runs-on: ubuntu-latest
needs: build-and-cache
steps:
- uses: actions/checkout@v5
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ env.OTP_VERSION }}
elixir-version: ${{ env.ELIXIR_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://cdn.jsdelivr.net/hex

- name: Restore Mix Deps Cache
uses: actions/cache/restore@v4
id: deps-cache
with:
path: |
deps
_build
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-

- run: mix format --check-formatted

dialyzer:
Comment on lines +219 to +272
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.matrix-builder.outputs.matrix) }}
name: Dialyzer static analysis
runs-on: ubuntu-latest
needs:
- build-and-cache
- matrix-builder
steps:
- uses: actions/checkout@v5
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ env.OTP_VERSION }}
elixir-version: ${{ env.ELIXIR_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://cdn.jsdelivr.net/hex

- name: Restore Mix Deps Cache
uses: actions/cache/restore@v4
id: deps-cache
with:
path: |
deps
_build
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-

- name: Restore Dialyzer Cache
uses: actions/cache@v4
id: dialyzer-cache
with:
path: priv/plts
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-${{ matrix.chain-type }}-${{ matrix.bridged-tokens }}-dialyzer-mixlockhash-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-${{ matrix.chain-type }}-${{ matrix.bridged-tokens }}-dialyzer-mixlockhash-

- name: Conditionally build Dialyzer Cache
if: steps.dialyzer-cache.output.cache-hit != 'true'
run: |
mkdir -p priv/plts
mix dialyzer --plt
env:
CHAIN_TYPE: ${{ matrix.chain-type != 'default' && matrix.chain-type || '' }}
BRIDGED_TOKENS_ENABLED: ${{ matrix.bridged-tokens }}

- name: Run Dialyzer
run: mix dialyzer --halt-exit-status
env:
CHAIN_TYPE: ${{ matrix.chain-type != 'default' && matrix.chain-type || '' }}
BRIDGED_TOKENS_ENABLED: ${{ matrix.bridged-tokens }}

gettext:
Comment on lines +714 to +815
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.matrix-builder.outputs.matrix) }}
name: Blockscout Web Tests
runs-on: ubuntu-latest
needs:
- build-and-cache
- matrix-builder
services:
redis-db:
image: "redis:alpine"
ports:
- 6379:6379

postgres:
image: postgres:17
env:
# Match apps/explorer/config/test.exs config :explorer, Explorer.Repo, database
POSTGRES_DB: explorer_test
# match PGPASSWORD for elixir image above
POSTGRES_PASSWORD: postgres
# match PGUSER for elixir image above
POSTGRES_USER: postgres
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
steps:
- uses: actions/checkout@v5
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ env.OTP_VERSION }}
elixir-version: ${{ env.ELIXIR_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://cdn.jsdelivr.net/hex

- name: Mix Deps Cache
uses: actions/cache/restore@v4
id: deps-cache
with:
path: |
deps
_build
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-

- name: Restore Explorer NPM Cache
uses: actions/cache@v4
id: explorer-npm-cache
with:
path: apps/explorer/node_modules
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-${{ hashFiles('apps/explorer/package-lock.json') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-explorer-npm-

- name: Restore Blockscout Web NPM Cache
uses: actions/cache@v4
id: blockscoutweb-npm-cache
with:
path: apps/block_scout_web/assets/node_modules
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-${{ hashFiles('apps/block_scout_web/assets/package-lock.json') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-blockscoutweb-npm-

- name: Build assets
run: node node_modules/webpack/bin/webpack.js --mode development
working-directory: "apps/block_scout_web/assets"

- run: ./bin/install_chrome_headless.sh

- name: mix test --exclude no_nethermind
run: |
mix ecto.create --quiet
mix ecto.migrate
cd apps/block_scout_web
mix compile
mix test --no-start --exclude no_nethermind
env:
# match POSTGRES_PASSWORD for postgres image below
PGPASSWORD: postgres
# match POSTGRES_USER for postgres image below
PGUSER: postgres
ETHEREUM_JSONRPC_CASE: "EthereumJSONRPC.Case.Nethermind.Mox"
ETHEREUM_JSONRPC_WEB_SOCKET_CASE: "EthereumJSONRPC.WebSocket.Case.Mox"
CHAIN_ID: "10200"
API_RATE_LIMIT_DISABLED: "true"
API_GRAPHQL_RATE_LIMIT_DISABLED: "true"
ADMIN_PANEL_ENABLED: "true"
ACCOUNT_ENABLED: "true"
ACCOUNT_REDIS_URL: "redis://localhost:6379"
SOURCIFY_INTEGRATION_ENABLED: "true"
CHAIN_TYPE: ${{ matrix.chain-type != 'default' && matrix.chain-type || '' }}
WETH_TOKEN_TRANSFERS_FILTERING_ENABLED: "true"
BRIDGED_TOKENS_ENABLED: ${{ matrix.bridged-tokens }}
DISABLE_WEBAPP: "false"
Comment on lines +24 to +58
name: Build matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- id: set-matrix
run: |
echo "matrix=$(node -e '

// Add/remove CI matrix chain types here
const chainTypes = [
"default",
"arbitrum",
"arc",
"blackfort",
"ethereum",
"filecoin",
"neon",
"optimism",
"optimism-celo",
"rsk",
"scroll",
"shibarium",
"stability",
"suave",
"zetachain",
"zilliqa",
"zksync"
];

const matrix = { "chain-type": ${{ 'chainTypes' }} };
console.log(JSON.stringify(matrix));
')" >> $GITHUB_OUTPUT

build-and-cache:
Comment on lines +59 to +96
name: Build and Cache deps
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ env.OTP_VERSION }}
elixir-version: ${{ env.ELIXIR_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://cdn.jsdelivr.net/hex

- name: "ELIXIR_VERSION.lock"
run: echo "${ELIXIR_VERSION}" > ELIXIR_VERSION.lock

- name: "OTP_VERSION.lock"
run: echo "${OTP_VERSION}" > OTP_VERSION.lock

- name: Restore Mix Deps Cache
uses: actions/cache@v4
id: deps-cache
with:
path: |
deps
_build
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-

- name: Conditionally build Mix deps cache
if: steps.deps-cache.outputs.cache-hit != 'true'
run: |
mix local.hex --force
mix local.rebar --force
mix deps.get
mix deps.compile --skip-umbrella-children

generate-swagger:
Comment on lines +97 to +156
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.matrix-builder.outputs.matrix) }}
name: Generate Open API spec
runs-on: ubuntu-latest
needs:
- build-and-cache
- matrix-builder
steps:
- uses: actions/checkout@v5
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ env.OTP_VERSION }}
elixir-version: ${{ env.ELIXIR_VERSION }}
hexpm-mirrors: |
https://builds.hex.pm
https://cdn.jsdelivr.net/hex

- name: Mix Deps Cache
uses: actions/cache/restore@v4
id: deps-cache
with:
path: |
deps
_build
key: ${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-${{ hashFiles('mix.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.ELIXIR_VERSION }}-${{ env.OTP_VERSION }}-${{ env.MIX_ENV }}-deps-mixlockhash-

- name: mix openapi.spec.yaml
run: |
mix openapi.spec.yaml --spec BlockScoutWeb.Specs.Public openapi.${{ matrix.chain-type }}.yaml --start-app=false
env:
CHAIN_TYPE: ${{ matrix.chain-type != 'default' && matrix.chain-type || '' }}
MUD_INDEXER_ENABLED: false

- name: Generate MUD-enabled spec for Optimism
if: matrix.chain-type == 'optimism'
run: |
mix openapi.spec.yaml --spec BlockScoutWeb.Specs.Public openapi.mud.yaml --start-app=false
env:
CHAIN_TYPE: optimism
MUD_INDEXER_ENABLED: true

- name: Upload OpenAPI spec
uses: actions/upload-artifact@v4
with:
name: openapi-spec-${{ matrix.chain-type }}
path: openapi.${{ matrix.chain-type }}.yaml
retention-days: 1

- name: Upload MUD-enabled spec
if: matrix.chain-type == 'optimism'
uses: actions/upload-artifact@v4
with:
name: openapi-spec-mud
path: openapi.mud.yaml
retention-days: 1

push-specs:
Comment on lines +157 to +291
needs:
- generate-swagger
- matrix-builder
runs-on: ubuntu-latest
name: Push all OpenAPI specs
steps:
- name: Validate required secrets
run: |
if [ -z "${{ secrets.API_SPECS_PAT }}" ]; then
echo "Error: API_SPECS_PAT secret is not set"
exit 1
fi

- name: Checkout specs repository
uses: actions/checkout@v5
with:
repository: ${{ vars.API_SPECS_REPOSITORY }}
token: ${{ secrets.API_SPECS_PAT }}
path: api-specs

- name: Download all swagger specs
uses: actions/download-artifact@v5
with:
pattern: openapi-spec-*
merge-multiple: true
path: temp-specs

- name: Merge all OpenAPI specs into all-in-one spec
run: |
npm install js-yaml
cat > merge-specs.js << 'SCRIPT_EOF'
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');

const specDir = './temp-specs';
const outputFile = path.join(specDir, 'openapi.all.yaml');

const files = fs.readdirSync(specDir)
.filter(f => f.endsWith('.yaml'))
.sort();

let merged = null;

for (const file of files) {
const content = yaml.load(fs.readFileSync(path.join(specDir, file), 'utf8'));
if (!merged) {
merged = JSON.parse(JSON.stringify(content));
continue;
}
// Union merge paths (first definition wins for duplicates)
if (content.paths) {
merged.paths = merged.paths || {};
for (const [p, def] of Object.entries(content.paths)) {
if (!merged.paths[p]) {
merged.paths[p] = def;
}
}
}
// Union merge components (first definition wins for duplicates)
if (content.components) {
merged.components = merged.components || {};
for (const [section, defs] of Object.entries(content.components)) {
if (!merged.components[section]) {
merged.components[section] = defs;
} else {
for (const [name, def] of Object.entries(defs)) {
if (!merged.components[section][name]) {
merged.components[section][name] = def;
}
}
}
}
}
// Union merge tags (by name)
if (content.tags) {
merged.tags = merged.tags || [];
const existingTagNames = new Set(merged.tags.map(t => t.name));
for (const tag of content.tags) {
if (!existingTagNames.has(tag.name)) {
merged.tags.push(tag);
existingTagNames.add(tag.name);
}
}
}
}

fs.writeFileSync(outputFile, yaml.dump(merged, { lineWidth: -1 }));
console.log(`Merged ${files.length} specs into ${outputFile}`);
SCRIPT_EOF
node merge-specs.js

- name: Create specs directory structure
run: |
VERSION=${{ github.event_name == 'release' && env.RELEASE_VERSION || 'master' }}

for SPEC_FILE in temp-specs/*; do
if [ -f "$SPEC_FILE" ]; then
FILENAME=$(basename "$SPEC_FILE")

# Handle MUD spec specially
if [ "$FILENAME" = "openapi.mud.yaml" ]; then
mkdir -p "api-specs/blockscout/${VERSION}/mud"
cp "$SPEC_FILE" "api-specs/blockscout/${VERSION}/mud/swagger.yaml"
else
# Extract chain type from filename (openapi.CHAINTYPE.yaml)
CHAIN_TYPE=$(echo "$FILENAME" | sed 's/openapi\.\(.*\)\.yaml/\1/')
mkdir -p "api-specs/blockscout/${VERSION}/${CHAIN_TYPE}"
cp "$SPEC_FILE" "api-specs/blockscout/${VERSION}/${CHAIN_TYPE}/swagger.yaml"
fi
fi
done


- name: Commit and push changes
working-directory: api-specs
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"

git add .

# Only commit if there are changes
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "[SKIP-GH-PAGES] create OpenAPI specs for Blockscout ${{ github.event_name == 'release' && env.RELEASE_VERSION || github.sha }}"
git push
fi

- name: Clean up
if: always()
run: |
rm -rf temp-specs
rm -rf api-specs
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request transitions Blockscout to version 11.0.0, featuring a major refactor of internal transactions to utilize address IDs and the introduction of asynchronous CSV exports via Oban and Gokapi. The changes also include new legacy API wrappers, license updates, and the removal of Polygon zkEVM support. Feedback identifies critical issues including unresolved merge conflict markers in the internal transactions runner and a bug in the batch preloading logic for contract creation transactions. Furthermore, an improvement opportunity was noted to resolve N+1 query performance issues during data preparation.

Comment on lines +27 to +31
<<<<<<< HEAD
alias Explorer.Utility.MissingRangesManipulator
=======
alias Explorer.Utility.{AddressIdToAddressHash, MissingBlockRange}
>>>>>>> v11.0.0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This file contains unresolved merge conflict markers (e.g., <<<<<<< HEAD, =======, >>>>>>> v11.0.0). These must be resolved manually before the pull request can be merged, as they will cause compilation errors. There are multiple such markers throughout this file.

Comment on lines +880 to +883
contract_creation_internal_transaction_preload_query()
|> InternalTransaction.where_address_match(:created_contract_address, address_hashes)
|> repo.all()
|> InternalTransaction.preload_addresses([], repo)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The batch preloading logic for contract_creation_internal_transaction is incorrect. It uses contract_creation_internal_transaction_preload_query/0, which includes a limit(1) clause. This causes the query to return at most one internal transaction for the entire list of addresses, rather than one per address. To fix this for a batch of addresses, you should use a query that fetches the top result for each address hash (e.g., using DISTINCT ON in PostgreSQL).

Comment on lines +710 to +711
AddressIdToAddressHash.id_to_hash(Map.get(trace, :created_contract_address_id)),
error: TransactionError.id_to_error(Map.get(trace, :error_id)),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

These calls to AddressIdToAddressHash.id_to_hash/1 and TransactionError.id_to_error/1 inside an Enum.map loop introduce N+1 query problems. Since the IDs are already available in the valid_internal_transactions list, you should batch load the corresponding hashes and error messages before entering the loop to improve performance.

@JOY JOY (JOY) force-pushed the sync-upstream-v11.0.0 branch 5 times, most recently from f1d8cf5 to ccf92f8 Compare April 28, 2026 05:23
@JOY JOY (JOY) force-pushed the sync-upstream-v11.0.0 branch from ccf92f8 to dd6a2f8 Compare April 28, 2026 10:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants