Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solution Rebasing #545

Merged
merged 22 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
820e173
Define handle_found_solution callback
Apr 4, 2024
c5307cb
Add support for solution rebasing
Apr 4, 2024
e17d13d
Do not create pool jobs we do not have step checkpoints for
May 23, 2024
6e92473
Try another VDF server immediately on error unless tried recently
May 23, 2024
160a016
Send step checkpoints for 100 steps in every session update
May 23, 2024
3b3b652
Increase timeouts of syncs_data_test_ & syncs_after_joining_test_
May 23, 2024
249a65d
Drop support for format=1 nonce_limiter_update serialization
May 23, 2024
f09c413
Drop checkpoints from #nonce_limiter_update
May 23, 2024
428862d
Bump release number 70, 2.7.4 (pre-release)
JamesPiechota May 23, 2024
915d567
Use system_time instead of monotonic_time for timestamps
JamesPiechota May 24, 2024
c24198f
Only rotate VDF servers on errors
May 26, 2024
7d2ecf2
Serve prepared binary VDF updates
May 26, 2024
a57e838
Refactor ar_nonce_limiter:apply_external_update
May 27, 2024
e3d0500
Do not send many VDF checkpoints with regular updates
May 27, 2024
e4819e0
Reduce steps with checkpoints on session updates to 20
May 27, 2024
5d064d4
Include two steps in regular VDF updates
May 27, 2024
98e3882
Only make addditional session requests on last session mismatch
May 27, 2024
387c983
Restrict the number of allowed VDF (session) requests
May 27, 2024
301b35b
Do not cache VDF updates unless configured as VDF server
May 27, 2024
bd5cd27
Rotate VDF servers when we are strictly ahead
May 27, 2024
ba5f9a2
Do not spawn VDF server process unless configured
May 27, 2024
ea2cde4
Increase the /vdfx/x_session RPM to 60
JamesPiechota May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions apps/arweave/include/ar.hrl
Expand Up @@ -27,7 +27,7 @@
-define(CLIENT_VERSION, 5).

%% The current build number -- incremented for every release.
-define(RELEASE_NUMBER, 69).
-define(RELEASE_NUMBER, 70).

-define(DEFAULT_REQUEST_HEADERS,
[
Expand Down Expand Up @@ -406,7 +406,6 @@
-record(nonce_limiter_update, {
session_key,
session,
checkpoints,
is_partial = true
}).

Expand Down
20 changes: 16 additions & 4 deletions apps/arweave/include/ar_blacklist_middleware.hrl
Expand Up @@ -39,9 +39,15 @@ end).
[<<"vdf">>] ->
{get_vdf, maps:get(get_vdf, LimitByIP, 180)};
[<<"vdf">>, <<"session">>] ->
{get_vdf, maps:get(get_vdf, LimitByIP, 180)};
{get_vdf_session, maps:get(get_vdf_session, LimitByIP, 120)};
[<<"vdf2">>, <<"session">>] ->
{get_vdf_session, maps:get(get_vdf_session, LimitByIP, 120)};
[<<"vdf3">>, <<"session">>] ->
{get_vdf_session, maps:get(get_vdf_session, LimitByIP, 120)};
[<<"vdf">>, <<"previous_session">>] ->
{get_vdf, maps:get(get_vdf, LimitByIP, 180)};
{get_previous_vdf_session, maps:get(get_previous_vdf_session, LimitByIP, 60)};
[<<"vdf2">>, <<"previous_session">>] ->
{get_previous_vdf_session, maps:get(get_previous_vdf_session, LimitByIP, 60)};
_ ->
{default, maps:get(default, LimitByIP, DefaultPathLimit)}
end
Expand Down Expand Up @@ -74,9 +80,15 @@ end).
[<<"vdf">>] ->
{get_vdf, maps:get(get_vdf, LimitByIP, 180)};
[<<"vdf">>, <<"session">>] ->
{get_vdf, maps:get(get_vdf, LimitByIP, 180)};
{get_vdf_session, maps:get(get_vdf_session, LimitByIP, 60)};
[<<"vdf2">>, <<"session">>] ->
{get_vdf_session, maps:get(get_vdf_session, LimitByIP, 60)};
[<<"vdf3">>, <<"session">>] ->
{get_vdf_session, maps:get(get_vdf_session, LimitByIP, 60)};
[<<"vdf">>, <<"previous_session">>] ->
{get_vdf, maps:get(get_vdf, LimitByIP, 180)};
{get_previous_vdf_session, maps:get(get_previous_vdf_session, LimitByIP, 60)};
[<<"vdf2">>, <<"previous_session">>] ->
{get_previous_vdf_session, maps:get(get_previous_vdf_session, LimitByIP, 60)};
_ ->
{default, maps:get(default, LimitByIP, DefaultPathLimit)}
end
Expand Down
65 changes: 50 additions & 15 deletions apps/arweave/src/ar_block_cache.erl
Expand Up @@ -7,7 +7,8 @@
mark_tip/2, get/2, get_earliest_not_validated_from_longest_chain/1,
get_longest_chain_cache/1,
get_block_and_status/2, remove/2, get_checkpoint_block/1, prune/2,
get_by_solution_hash/5, is_known_solution_hash/2]).
get_by_solution_hash/5, is_known_solution_hash/2,
get_siblings/2, get_fork_blocks/2]).

-include_lib("arweave/include/ar.hrl").
-include_lib("eunit/include/eunit.hrl").
Expand All @@ -21,10 +22,6 @@
%% validated: block is validated but does not belong to the tip fork
%% not_validated: block is not validated yet
%% none: null status
-type validation_status() :: on_chain | validated | not_validated | none.
-type nonce_limiter_validation_status() :: nonce_limiter_validated |
awaiting_nonce_limiter_validation.
-type block_status() :: validation_status() | {not_validated, nonce_limiter_validation_status()}.

%% @doc ETS table: block_cache
%% {block, BlockHash} => {#block{}, block_status(), Timestamp, set(Children)}
Expand Down Expand Up @@ -306,8 +303,8 @@ get_block_and_status(Tab, H) ->
case ets:lookup(Tab, {block, H}) of
[] ->
not_found;
[{_, {B, Status, _Timestamp, _Children}}] ->
{B, Status}
[{_, {B, Status, Timestamp, _Children}}] ->
{B, {Status, Timestamp}}
end.

%% @doc Mark the given block as the tip block. Mark the previous blocks as on-chain.
Expand Down Expand Up @@ -432,6 +429,33 @@ get_by_solution_hash(Tab, SolutionH, H, CDiff, PrevCDiff, [H2 | L], _B) ->
get_by_solution_hash(Tab, SolutionH, H, CDiff, PrevCDiff, L, B2)
end.

%% @doc Return the list of siblings of the given block, if any.
get_siblings(Tab, B) ->
H = B#block.indep_hash,
PrevH = B#block.previous_block,
case ets:lookup(Tab, {block, PrevH}) of
[] ->
[];
[{_, {_B, _Status, _CurrentTimestamp, Children}}] ->
sets:fold(
fun(SibH, Acc) ->
case SibH of
H ->
Acc;
_ ->
case ets:lookup(Tab, {block, SibH}) of
[] ->
Acc;
[{_, {Sib, _, _, _}}] ->
[Sib | Acc]
end
end
end,
[],
Children
)
end.

%%%===================================================================
%%% Private functions.
%%%===================================================================
Expand Down Expand Up @@ -1013,6 +1037,7 @@ block_cache_test() ->
assert_tip(block_id(B1)),
assert_max_cdiff({0, block_id(B1)}),
assert_is_valid_fork(true, on_chain, B1),
?assertEqual([], get_siblings(bcache_test, B1)),

%% Re-adding B1 shouldn't change anything - i.e. nothing should be updated because the
%% block is already on chain
Expand Down Expand Up @@ -1056,6 +1081,7 @@ block_cache_test() ->
assert_max_cdiff({1, block_id(B2)}),
assert_is_valid_fork(true, on_chain, B1),
assert_is_valid_fork(true, not_validated, B2),
?assertEqual([], get_siblings(bcache_test, B2)),

%% Add a TXID to B2, but still don't mark as validated
%%
Expand Down Expand Up @@ -1113,6 +1139,8 @@ block_cache_test() ->
assert_is_valid_fork(true, on_chain, B1),
assert_is_valid_fork(true, not_validated, B2),
assert_is_valid_fork(true, not_validated, B1_2),
?assertEqual([B2], get_siblings(bcache_test, B1_2)),
?assertEqual([B1_2], get_siblings(bcache_test, B2)),

%% Even though B2 is marked as a tip, it is still lower difficulty than B1_2 so will
%% not be included in the longest chain
Expand Down Expand Up @@ -1243,7 +1271,8 @@ block_cache_test() ->
%% \ /
%% 0 B1/on_chain
add_validated(bcache_test, B2_2),
?assertEqual({B2_2, validated}, get_block_and_status(bcache_test, B2_2#block.indep_hash)),
?assertMatch({B2_2, {validated, _}},
get_block_and_status(bcache_test, B2_2#block.indep_hash)),
?assertMatch({B2_3, [B2_2, B2], {{not_validated, ExpectedStatus}, _}},
get_earliest_not_validated_from_longest_chain(bcache_test)),
assert_longest_chain([B2_2, B2, B1], 1),
Expand Down Expand Up @@ -1281,6 +1310,9 @@ block_cache_test() ->
assert_is_valid_fork(true, validated, B2_2),
assert_is_valid_fork(true, not_validated, B2_3),
assert_is_valid_fork(true, on_chain, B3),
?assertEqual([B2_2], get_siblings(bcache_test, B3)),
?assertEqual([B3], get_siblings(bcache_test, B2_2)),
?assertEqual([B2], get_siblings(bcache_test, B1_2)),

%% B3->B2->B1 fork is still heaviest
%%
Expand Down Expand Up @@ -1346,6 +1378,8 @@ block_cache_test() ->
assert_is_valid_fork(true, not_validated, B2_3),
assert_is_valid_fork(true, validated, B3),
assert_is_valid_fork(true, not_validated, B4),
?assertEqual([], get_siblings(bcache_test, B2_3)),
?assertEqual([], get_siblings(bcache_test, B4)),

%% Height Block/Status
%%
Expand Down Expand Up @@ -1494,8 +1528,9 @@ block_cache_test() ->
%% 0 B11/on_chain
mark_nonce_limiter_validated(bcache_test, crypto:strong_rand_bytes(48)),
mark_nonce_limiter_validated(bcache_test, block_id(B13)),
?assertEqual({B13, on_chain}, get_block_and_status(bcache_test, block_id(B13))),
?assertMatch({B14, {not_validated, awaiting_nonce_limiter_validation}},
?assertMatch({B13, {on_chain, _}},
get_block_and_status(bcache_test, block_id(B13))),
?assertMatch({B14, {{not_validated, awaiting_nonce_limiter_validation}, _}},
get_block_and_status(bcache_test, block_id(B14))),
assert_longest_chain([B13, B11], 0),
assert_tip(block_id(B13)),
Expand All @@ -1512,7 +1547,7 @@ block_cache_test() ->
%% 1 B12/not_validated B13/on_chain
%% \ /
%% 0 B11/on_chain
?assertMatch({B14, {not_validated, awaiting_nonce_limiter_validation}},
?assertMatch({B14, {{not_validated, awaiting_nonce_limiter_validation}, _}},
get_block_and_status(bcache_test, block_id(B14))),
?assertMatch({B14, [B13], {{not_validated, awaiting_nonce_limiter_validation}, _}},
get_earliest_not_validated_from_longest_chain(bcache_test)),
Expand All @@ -1532,7 +1567,7 @@ block_cache_test() ->
%% \ /
%% 0 B11/on_chain
mark_nonce_limiter_validated(bcache_test, block_id(B14)),
?assertMatch({B14, {not_validated, nonce_limiter_validated}},
?assertMatch({B14, {{not_validated, nonce_limiter_validated}, _}},
get_block_and_status(bcache_test, block_id(B14))),
?assertMatch({B14, [B13], {{not_validated, nonce_limiter_validated}, _}},
get_earliest_not_validated_from_longest_chain(bcache_test)),
Expand Down Expand Up @@ -1578,7 +1613,7 @@ block_cache_test() ->
add_validated(bcache_test, B14),
?assertMatch({B15, [B14, B13], {{not_validated, awaiting_nonce_limiter_validation}, _}},
get_earliest_not_validated_from_longest_chain(bcache_test)),
?assertMatch({B14, validated}, get_block_and_status(bcache_test, block_id(B14))),
?assertMatch({B14, {validated, _}}, get_block_and_status(bcache_test, block_id(B14))),
assert_longest_chain([B14, B13, B11], 1),
assert_tip(block_id(B13)),
assert_max_cdiff({3, block_id(B15)}),
Expand Down Expand Up @@ -1626,7 +1661,7 @@ block_cache_test() ->
mark_nonce_limiter_validated(bcache_test, block_id(B16)),
?assertMatch({B15, [B14, B13], {{not_validated, awaiting_nonce_limiter_validation}, _}},
get_earliest_not_validated_from_longest_chain(bcache_test)),
?assertMatch({B16, {not_validated, nonce_limiter_validated}},
?assertMatch({B16, {{not_validated, nonce_limiter_validated}, _}},
get_block_and_status(bcache_test, block_id(B16))),
assert_longest_chain([B14, B13, B11], 1),
assert_tip(block_id(B13)),
Expand All @@ -1650,7 +1685,7 @@ block_cache_test() ->
%% \ /
%% 0 B11/on_chain
mark_tip(bcache_test, block_id(B14)),
?assertEqual({B14, on_chain}, get_block_and_status(bcache_test, block_id(B14))),
?assertMatch({B14, {on_chain, _}}, get_block_and_status(bcache_test, block_id(B14))),
?assertMatch({B15, [B14], {{not_validated, awaiting_nonce_limiter_validation}, _}},
get_earliest_not_validated_from_longest_chain(bcache_test)),
assert_longest_chain([B14, B13, B11], 0),
Expand Down
8 changes: 4 additions & 4 deletions apps/arweave/src/ar_http_iface_client.erl
Expand Up @@ -520,7 +520,7 @@ get_vdf_update(Peer) ->
timeout => 2000, headers => p2p_headers()
}) of
{ok, {{<<"200">>, _}, _, Bin, _, _}} ->
ar_serialize:binary_to_nonce_limiter_update(Bin);
ar_serialize:binary_to_nonce_limiter_update(2, Bin);
{ok, {{<<"404">>, _}, _, _, _, _}} ->
{error, not_found};
{ok, {{Status, _}, _, ResponseBody, _, _}} ->
Expand All @@ -530,10 +530,10 @@ get_vdf_update(Peer) ->
end.

get_vdf_session(Peer) ->
case ar_http:req(#{ peer => Peer, method => get, path => "/vdf2/session",
case ar_http:req(#{ peer => Peer, method => get, path => "/vdf3/session",
timeout => 10000, headers => p2p_headers() }) of
{ok, {{<<"200">>, _}, _, Bin, _, _}} ->
ar_serialize:binary_to_nonce_limiter_update(Bin);
ar_serialize:binary_to_nonce_limiter_update(3, Bin);
{ok, {{<<"404">>, _}, _, _, _, _}} ->
{error, not_found};
{ok, {{Status, _}, _, ResponseBody, _, _}} ->
Expand All @@ -546,7 +546,7 @@ get_previous_vdf_session(Peer) ->
case ar_http:req(#{ peer => Peer, method => get, path => "/vdf2/previous_session",
timeout => 10000, headers => p2p_headers() }) of
{ok, {{<<"200">>, _}, _, Bin, _, _}} ->
ar_serialize:binary_to_nonce_limiter_update(Bin);
ar_serialize:binary_to_nonce_limiter_update(2, Bin);
{ok, {{<<"404">>, _}, _, _, _, _}} ->
{error, not_found};
{ok, {{Status, _}, _, ResponseBody, _, _}} ->
Expand Down
31 changes: 20 additions & 11 deletions apps/arweave/src/ar_http_iface_middleware.erl
Expand Up @@ -836,7 +836,7 @@ handle(<<"GET">>, [<<"reward_history">>, EncodedBH], Req, _Pid) ->
{ok, BH} ->
Fork_2_6 = ar_fork:height_2_6(),
case ar_block_cache:get_block_and_status(block_cache, BH) of
{#block{ height = Height, reward_history = RewardHistory }, Status}
{#block{ height = Height, reward_history = RewardHistory }, {Status, _}}
when (Status == on_chain orelse Status == validated),
Height >= Fork_2_6 ->
{200, #{}, ar_serialize:reward_history_to_binary(RewardHistory),
Expand All @@ -859,7 +859,7 @@ handle(<<"GET">>, [<<"block_time_history">>, EncodedBH], Req, _Pid) ->
Fork_2_7 = ar_fork:height_2_7(),
case ar_block_cache:get_block_and_status(block_cache, BH) of
{#block{ height = Height,
block_time_history = BlockTimeHistory }, Status}
block_time_history = BlockTimeHistory }, {Status, _}}
when (Status == on_chain orelse Status == validated),
Height >= Fork_2_7 ->
{200, #{}, ar_serialize:block_time_history_to_binary(
Expand Down Expand Up @@ -1286,7 +1286,7 @@ handle(<<"GET">>, [<<"vdf">>], Req, _Pid) ->
false ->
not_joined(Req);
true ->
handle_get_vdf(Req, get_update, 1)
handle_get_vdf(Req, get_update, 2)
end;

%% Serve an VDF update to a configured VDF client.
Expand All @@ -1306,7 +1306,7 @@ handle(<<"GET">>, [<<"vdf">>, <<"session">>], Req, _Pid) ->
false ->
not_joined(Req);
true ->
handle_get_vdf(Req, get_session, 1)
handle_get_vdf(Req, get_session, 2)
end;

%% Serve the current VDF session to a configured VDF client.
Expand All @@ -1319,14 +1319,24 @@ handle(<<"GET">>, [<<"vdf2">>, <<"session">>], Req, _Pid) ->
handle_get_vdf(Req, get_session, 2)
end;

%% Serve the current VDF session to a configured VDF client.
%% GET request to /vdf3/session.
handle(<<"GET">>, [<<"vdf3">>, <<"session">>], Req, _Pid) ->
case ar_node:is_joined() of
false ->
not_joined(Req);
true ->
handle_get_vdf(Req, get_session, 3)
end;

%% Serve the previous VDF session to a configured VDF client.
%% GET request to /vdf/previous_session.
handle(<<"GET">>, [<<"vdf">>, <<"previous_session">>], Req, _Pid) ->
case ar_node:is_joined() of
false ->
not_joined(Req);
true ->
handle_get_vdf(Req, get_previous_session, 1)
handle_get_vdf(Req, get_previous_session, 2)
end;

%% Serve the previous VDF session to a configured VDF client.
Expand Down Expand Up @@ -3096,7 +3106,7 @@ handle_post_vdf2(Req, Pid, Peer) ->
handle_post_vdf3(Req, Pid, Peer) ->
case read_complete_body(Req, Pid) of
{ok, Body, Req2} ->
case ar_serialize:binary_to_nonce_limiter_update(Body) of
case ar_serialize:binary_to_nonce_limiter_update(2, Body) of
{ok, Update} ->
case ar_nonce_limiter:apply_external_update(Update, Peer) of
ok ->
Expand Down Expand Up @@ -3136,18 +3146,17 @@ handle_get_vdf2(Req, Call, Format) ->
Update =
case Call of
get_update ->
ar_nonce_limiter_server:get_update();
ar_nonce_limiter_server:get_update(Format);
get_session ->
ar_nonce_limiter_server:get_full_update();
ar_nonce_limiter_server:get_full_update(Format);
get_previous_session ->
ar_nonce_limiter_server:get_full_prev_update()
ar_nonce_limiter_server:get_full_prev_update(Format)
end,
case Update of
not_found ->
{404, #{}, <<>>, Req};
Update ->
Bin = ar_serialize:nonce_limiter_update_to_binary(Format, Update),
{200, #{}, Bin, Req}
{200, #{}, Update, Req}
end.

read_complete_body(Req, Pid) ->
Expand Down
3 changes: 3 additions & 0 deletions apps/arweave/src/ar_http_iface_server.erl
Expand Up @@ -121,6 +121,9 @@ name_route([<<"vdf">>, <<"session">>]) ->
"/vdf/session";
name_route([<<"vdf2">>, <<"session">>]) ->
"/vdf2/session";
name_route([<<"vdf3">>, <<"session">>]) ->
"/vdf3/session";

name_route([<<"vdf">>, <<"previous_session">>]) ->
"/vdf/previous_session";
name_route([<<"vdf2">>, <<"previous_session">>]) ->
Expand Down
2 changes: 1 addition & 1 deletion apps/arweave/src/ar_node.erl
Expand Up @@ -241,7 +241,7 @@ get_partition_upper_bound(BI) ->

get_recent_partition_upper_bound_by_prev_h(H, Diff) ->
case ar_block_cache:get_block_and_status(block_cache, H) of
{_B, on_chain} ->
{_B, {on_chain, _}} ->
[{_, BI}] = ets:lookup(node_state, recent_block_index),
Genesis = length(BI) =< ?SEARCH_SPACE_UPPER_BOUND_DEPTH,
get_recent_partition_upper_bound_by_prev_h(H, Diff, BI, Genesis);
Expand Down