Sync upstream v11.2.1 (merge conflicts)#76
Conversation
Co-authored-by: Alexander Kolotov <alexander.kolotov@gmail.com> Co-authored-by: Maxim Filonov <53992153+sl1depengwyn@users.noreply.github.com> Co-authored-by: Victor Baranov <baranov.viktor.27@gmail.com> Co-authored-by: Qwerty5Uiop <105209995+Qwerty5Uiop@users.noreply.github.com>
…oints (blockscout#14227) Co-authored-by: Alexander Kolotov <alexander.kolotov@gmail.com> Co-authored-by: Maxim Filonov <53992153+sl1depengwyn@users.noreply.github.com> Co-authored-by: Victor Baranov <baranov.viktor.27@gmail.com> Co-authored-by: Qwerty5Uiop <105209995+Qwerty5Uiop@users.noreply.github.com>
…ut#14251) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Alexander Kolotov <alexander.kolotov@gmail.com> Co-authored-by: Victor Baranov <baranov.viktor.27@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nikita Pozdniakov <nikitosing4@mail.ru> Co-authored-by: Maxim Filonov <53992153+sl1depengwyn@users.noreply.github.com> Co-authored-by: Qwerty5Uiop <alex000010@bk.ru> Co-authored-by: Qwerty5Uiop <105209995+Qwerty5Uiop@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>
…#14350) 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>
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>
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>
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Victor Baranov <baranov.viktor.27@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…14385) Co-authored-by: Cursor <cursoragent@cursor.com>
…CY (blockscout#14390) Co-authored-by: Victor Baranov <baranov.viktor.27@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.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>
Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…4473) 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>
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>
…lockscout#14433) Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.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>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
| name: Resolve dev package version | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| package_version: ${{ steps.set.outputs.package_version }} | ||
| steps: | ||
| - name: Set version from commit SHA | ||
| id: set | ||
| run: echo "package_version=v0.0.1-beta.${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| publish: |
| name: Build and publish | ||
| needs: version | ||
| uses: ./.github/workflows/publish-api-types-npm.yml | ||
| with: | ||
| package_version: ${{ needs.version.outputs.package_version }} | ||
| secrets: | ||
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} |
There was a problem hiding this comment.
Code Review
This pull request introduces comprehensive OpenAPI specifications for the Arbitrum and Advanced Filter endpoints, optimizes real-time event broadcasting in the Notifier by pre-filtering on active subscribers, and adds architectural guidelines for separate API/Indexer modes. However, several critical issues were identified during the review: the new subscriber-filtering logic in Notifier relies on node-local registry lookups which will silently drop real-time updates in distributed deployments, and it publishes un-preloaded token transfers to Absinthe subscriptions, risking N+1 queries or errors. Additionally, the list_methods action in AdvancedFilterController will crash when the optional q parameter is omitted, and globally dropping :batch_numbers in PagingHelper breaks pagination for the public Arbitrum batches endpoint.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| defp has_subscribers?(topic) when is_binary(topic) do | ||
| Registry.lookup(BlockScoutWeb.PubSub, topic) != [] | ||
| end | ||
|
|
||
| defp address_has_subscribers?(nil), do: false | ||
|
|
||
| defp address_has_subscribers?(address_hash) do | ||
| hash_string = to_string(address_hash) | ||
|
|
||
| has_subscribers?("addresses:" <> hash_string) or | ||
| has_subscribers?("addresses_old:" <> hash_string) | ||
| end |
There was a problem hiding this comment.
Registry.lookup/2 is node-local and only queries the registry of the current Erlang node. In a distributed or split-process deployment (such as running separate api and indexer instances, or multiple clustered api nodes behind a load balancer), clients subscribed to WebSocket topics on other nodes will not be visible to the node running the Notifier. As a result, address_has_subscribers?/1 will return false on publishing nodes, causing real-time updates (coin balances, token balances, transactions, token transfers) to be silently dropped for those clients.\n\nTo fix this, you should avoid filtering broadcasts at the publisher side using local registry lookups, or use a distributed tracking mechanism (like Erlang's :pg groups or Phoenix Tracker) if pre-filtering is absolutely necessary for performance.
| def handle_event({:chain_event, :token_transfers, :realtime, all_token_transfers}) do | ||
| all_token_transfers_full = | ||
| all_token_transfers | ||
| |> Repo.preload( | ||
| DenormalizationHelper.extend_transaction_preload([ | ||
| [token: Reputation.reputation_association()], | ||
| :transaction, | ||
| from_address: [ | ||
| :scam_badge, | ||
| :names, | ||
| :smart_contract, | ||
| proxy_implementations_association() | ||
| ], | ||
| to_address: [ | ||
| :scam_badge, | ||
| :names, | ||
| :smart_contract, | ||
| proxy_implementations_association() | ||
| ] | ||
| ]) | ||
| ) | ||
| |> Instance.preload_nft(@api_true) | ||
|
|
||
| transfers_by_token = Enum.group_by(all_token_transfers_full, fn tt -> to_string(tt.token_contract_address_hash) end) | ||
|
|
||
| broadcast_token_transfers_websocket_v2(all_token_transfers_full, transfers_by_token) | ||
| all_transfers_by_token = | ||
| Enum.group_by(all_token_transfers, fn tt -> to_string(tt.token_contract_address_hash) end) | ||
|
|
||
| for {token_contract_address_hash, token_transfers} <- transfers_by_token do | ||
| for {token_contract_address_hash, token_transfers} <- all_transfers_by_token do | ||
| Subscription.publish( | ||
| Endpoint, | ||
| token_transfers, | ||
| token_transfers: token_contract_address_hash | ||
| ) | ||
| end |
There was a problem hiding this comment.
In the refactored handle_event/1 for :token_transfers, Subscription.publish/3 is called with token_transfers grouped from all_token_transfers instead of all_token_transfers_full. Unlike all_token_transfers_full, all_token_transfers does not have any preloaded associations (such as :token, :transaction, :from_address, :to_address).\n\nWhen Absinthe attempts to resolve fields on these un-preloaded associations for active GraphQL subscription clients, it will either return Ecto.Association.NotLoaded structs (resulting in empty/null fields or errors) or trigger massive N+1 database queries.\n\nTo resolve this, ensure that the token transfers published to Absinthe are fully preloaded.
| @spec list_methods(Plug.Conn.t(), map()) :: Plug.Conn.t() | ||
| def list_methods(conn, %{q: query}) when is_binary(query) do |
There was a problem hiding this comment.
The list_methods/2 action is defined with a single clause matching %{q: query} when is_binary(query). However, the :q parameter is declared as optional (required: false) in the operation :list_methods spec, and the description states: "Without q, returns the default list of popular methods."\n\nIf a client requests this endpoint without the q query parameter, the pattern match will fail, causing the request to crash with a FunctionClauseError.\n\nPlease add a fallback clause to handle the absence of q and return the default list of popular methods.
| |> Map.drop([ | ||
| :address_hash_param, | ||
| :batch_number_param, | ||
| :batch_numbers, | ||
| :data_hash, | ||
| :block_hash_or_number_param, | ||
| :direction, | ||
| :transaction_hash_param, | ||
| :batch_number_param, | ||
| :scale, | ||
| :token_id_param, | ||
| :token_id, |
There was a problem hiding this comment.
Adding :batch_numbers to the global Map.drop list in delete_parameters_from_next_page_params/1 will strip the batch_numbers query parameter from the generated next_page_params cursor.\n\nWhile this prevents validation errors on the DA-specific endpoints (which don't declare :batch_numbers in their specs), it completely breaks pagination for the public GET /api/v2/arbitrum/batches endpoint. If a client filters batches by batch_numbers and requests the next page, the filter will be lost, and subsequent pages will return all batches instead of the filtered subset.\n\nTo fix this, avoid dropping :batch_numbers globally. Instead, either handle the exclusion specifically for the DA endpoints in the controller, or declare :batch_numbers as an optional parameter on those endpoints.
Upstream Sync - v11.2.1
Auto-merge with upstream
v11.2.1failed. Version/workflow conflicts were auto-resolved,but the following files have code conflicts that need manual resolution:
To resolve:
v11.2.1to trigger Docker buildUpstream release notes