Skip to content

impr: Allow to receive multiple /block/current requests and use highest height.#1010

Open
speeddragon wants to merge 4 commits into
edgefrom
feat/arweave_multiple_current_height
Open

impr: Allow to receive multiple /block/current requests and use highest height.#1010
speeddragon wants to merge 4 commits into
edgefrom
feat/arweave_multiple_current_height

Conversation

@speeddragon

@speeddragon speeddragon commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Nodes can fall behind the current block height. Currently, the code only receives one response when asking for the current block, so if the node with the faster reply is the one that lags, the copycat Arweave index will not index the newest blocks.

This PR allows receiving two responses (2) from nodes when requesting Arweave nodes for /block/current.

Alternative solution

An alternative solution could be to implement a device that uses <<"admissible">> (or another property) to filter the entire response list. This is too complicated, and this is the only case that fits it.

Comment thread src/preloaded/arweave/dev_arweave.erl Outdated
Comment on lines +895 to +898
case current_height_responses(Responses) of
[] -> best_response(Responses);
Heights -> current_height_best_response(Heights)
end;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What about removing the current_height_responses and having current_height_best_response(Responses) do the json:decode and then either return {ok, Response} or {error, no_viable_responses}. That would then be the switch to delgate to best_response(Responses)

Comment thread src/preloaded/arweave/dev_arweave.erl
@speeddragon
speeddragon requested a review from JamesPiechota July 9, 2026 16:43
%% ascending by HTTP status code. Returns the first (best) response tuple.
best_response(Path, {error, {no_viable_responses, Responses}}) ->
best_response(Path, Responses);
best_response(<<"/height">>, Responses) when is_list(Responses) ->

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

/height Also needs to be added to the templates I think?

Comment thread src/preloaded/arweave/dev_arweave.erl Outdated
Comment on lines +923 to +963
%% @doc Parse responses that contains block height to return the one with the
%% highest value. This helps when one node lags behind.
current_height_best_response(Responses) ->
FilteredResponsesHeight = lists:filtermap(
fun
({ok, #{ <<"body">> := Body }} = Response) ->
try hb_json:decode(Body) of
#{ <<"height">> := Height } ->
{true, {hb_util:int(Height), Response}};
Height when is_integer(Height) ->
{true, {Height, Response}};
_ ->
false
catch _:_ ->
case hb_util:safe_int(Body) of
{ok, Height} -> {true, {Height, Response}};
{error, invalid} -> false
end
end;
(_) ->
false
end,
Responses
),
case FilteredResponsesHeight of
[] ->
{error, no_viable_responses};
[{Height, Response} | Rest] ->
{_, BestResponse} =
lists:foldl(
fun({NextHeight, NextResponse}, {BestHeight, Best}) ->
case NextHeight > BestHeight of
true -> {NextHeight, NextResponse};
false -> {BestHeight, Best}
end
end,
{Height, Response},
Rest
),
BestResponse
end.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah maybe your old implementation was better? I thought by combining them we could collapse the logic - one loop that queries the height and maintains the best response rather than 2 loops. But if that's not possible, then your old is probably cleaner.

Also the new implementation lost the delegation to best_response/1 which was probably a good delegation (but I guess could be retinaed by delegating to best_response/1 instead of returning {error, no_viable_responses}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Ok, my bad. I've updated the function to merge both loops into one. In terms of readability, I think the first version was the best. Performance-wise, we don't expect many requests, so we can keep the old version, or we can go with this one.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Got it, yeah first version best. Sorry for the detour. It was the 2 separate data structures (list of Responses and list of {Height, Response}) that I was trying to simplify, but I agree the old one had some extra encapsulation that made it more readable than this one.

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.

2 participants