diff --git a/apps/arweave/include/ar.hrl b/apps/arweave/include/ar.hrl index 226099f79..4def61f54 100644 --- a/apps/arweave/include/ar.hrl +++ b/apps/arweave/include/ar.hrl @@ -124,11 +124,11 @@ %% The number of blocks returned in the /info 'recent' field -ifdef(DEBUG). --define(INFO_BLOCKS, 5). --define(INFO_BLOCKS_WITHOUT_TIMESTAMP, 2). +-define(RECENT_BLOCKS, 5). +-define(RECENT_BLOCKS_WITHOUT_TIMESTAMP, 2). -else. --define(INFO_BLOCKS, 10). --define(INFO_BLOCKS_WITHOUT_TIMESTAMP, 5). +-define(RECENT_BLOCKS, 10). +-define(RECENT_BLOCKS_WITHOUT_TIMESTAMP, 5). -endif. %% How long to wait before giving up on test(s). diff --git a/apps/arweave/src/ar_block_cache.erl b/apps/arweave/src/ar_block_cache.erl index 4f95e57a6..bd25e1d99 100644 --- a/apps/arweave/src/ar_block_cache.erl +++ b/apps/arweave/src/ar_block_cache.erl @@ -474,8 +474,6 @@ update_timestamp(Tab, H, ReceiveTimestamp) -> ok end; [] -> - ?LOG_ERROR([ - {event, ignored_block_missing_from_cache}, {block, ar_util:encode(H)}]), not_found end. diff --git a/apps/arweave/src/ar_block_index.erl b/apps/arweave/src/ar_block_index.erl index 04de83e97..ce482565f 100644 --- a/apps/arweave/src/ar_block_index.erl +++ b/apps/arweave/src/ar_block_index.erl @@ -3,8 +3,6 @@ -export([init/1, update/2, member/1, get_list/1, get_list_by_hash/1, get_element_by_height/1, get_block_bounds/1, get_intersection/2, get_intersection/1, get_range/2]). --include_lib("arweave/include/ar.hrl"). - %%%=================================================================== %%% Public interface. %%%=================================================================== diff --git a/apps/arweave/src/ar_data_sync.erl b/apps/arweave/src/ar_data_sync.erl index eeec42724..56b29e298 100644 --- a/apps/arweave/src/ar_data_sync.erl +++ b/apps/arweave/src/ar_data_sync.erl @@ -1470,7 +1470,7 @@ handle_info({event, disksup, {remaining_disk_space, StoreID, true, _Percentage, handle_info({event, disksup, _}, State) -> {noreply, State}; -handle_info({'EXIT', _, normal}, State) -> +handle_info({'EXIT', _PID, normal}, State) -> {noreply, State}; handle_info({'DOWN', _, process, _, normal}, State) -> diff --git a/apps/arweave/src/ar_http_iface_client.erl b/apps/arweave/src/ar_http_iface_client.erl index 91fde1644..e3f57ae9b 100644 --- a/apps/arweave/src/ar_http_iface_client.erl +++ b/apps/arweave/src/ar_http_iface_client.erl @@ -1086,7 +1086,7 @@ get_info(Peer, Type) -> case get_info(Peer) of info_unavailable -> info_unavailable; Info -> - maps:get(Type, Info) + maps:get(atom_to_binary(Type), Info) end. get_info(Peer) -> case @@ -1102,7 +1102,7 @@ get_info(Peer) -> {ok, {{<<"200">>, _}, _, JSON, _, _}} -> case ar_serialize:json_decode(JSON, [return_maps]) of {ok, JsonMap} -> - ar_serialize:json_map_to_info_map(JsonMap); + JsonMap; {error, _} -> info_unavailable end; diff --git a/apps/arweave/src/ar_http_iface_middleware.erl b/apps/arweave/src/ar_http_iface_middleware.erl index 78477c07f..1c830e1ab 100644 --- a/apps/arweave/src/ar_http_iface_middleware.erl +++ b/apps/arweave/src/ar_http_iface_middleware.erl @@ -183,6 +183,9 @@ handle(<<"GET">>, [], Req, _Pid) -> handle(<<"GET">>, [<<"info">>], Req, _Pid) -> {200, #{}, ar_serialize:jsonify(ar_info:get_info()), Req}; +handle(<<"GET">>, [<<"recent">>], Req, _Pid) -> + {200, #{}, ar_serialize:jsonify(ar_info:get_recent()), Req}; + handle(<<"GET">>, [<<"is_tx_blacklisted">>, EncodedTXID], Req, _Pid) -> case ar_util:safe_decode(EncodedTXID) of {error, invalid} -> diff --git a/apps/arweave/src/ar_info.erl b/apps/arweave/src/ar_info.erl index 49b652b66..e095ed7a1 100644 --- a/apps/arweave/src/ar_info.erl +++ b/apps/arweave/src/ar_info.erl @@ -1,15 +1,13 @@ +%%% +%%% @doc Gathers the data for the /info and /recent endpoints. +%%% + -module(ar_info). --export([get_keys/0, get_info/0]). +-export([get_info/0, get_recent/0]). -include_lib("arweave/include/ar.hrl"). -get_keys() -> - [ - network, version, release, height, current, blocks, peers, - queue_length, node_state_latency, recent - ]. - get_info() -> {Time, Current} = timer:tc(fun() -> ar_node:get_current_block_hash() end), @@ -17,51 +15,56 @@ get_info() -> timer:tc(fun() -> ar_node:get_height() end), [{_, BlockCount}] = ets:lookup(ar_header_sync, synced_blocks), #{ - network => list_to_binary(?NETWORK_NAME), - version => ?CLIENT_VERSION, - release => ?RELEASE_NUMBER, - height => + <<"network">> => list_to_binary(?NETWORK_NAME), + <<"version">> => ?CLIENT_VERSION, + <<"release">> => ?RELEASE_NUMBER, + <<"height">> => case Height of not_joined -> -1; H -> H end, - current => + <<"current">> => case is_atom(Current) of true -> atom_to_binary(Current, utf8); false -> ar_util:encode(Current) end, - blocks => BlockCount, - peers => prometheus_gauge:value(arweave_peer_count), - queue_length => + <<"blocks">> => BlockCount, + <<"peers">> => prometheus_gauge:value(arweave_peer_count), + <<"queue_length">> => element( 2, erlang:process_info(whereis(ar_node_worker), message_queue_len) ), - node_state_latency => (Time + Time2) div 2, + <<"node_state_latency">> => (Time + Time2) div 2 + }. + +get_recent() -> + #{ %% { %% "id": , %% "received": " %% } - recent => get_recent_blocks(Height) + <<"blocks">> => get_recent_blocks(ar_node:get_height()) }. get_recent_blocks(CurrentHeight) -> lists:foldl( fun({H, _WeaveSize, _TXRoot}, Acc) -> Acc ++ [#{ - id => ar_util:encode(H), - received => get_block_timestamp(H, length(Acc)) + <<"id">> => ar_util:encode(H), + <<"received">> => get_block_timestamp(H, length(Acc)) }] end, [], - lists:sublist(ar_block_index:get_list(CurrentHeight), ?INFO_BLOCKS) + lists:sublist(ar_block_index:get_list(CurrentHeight), ?RECENT_BLOCKS) ). -get_block_timestamp(H, Depth) when Depth =< ?INFO_BLOCKS_WITHOUT_TIMESTAMP -> - "pending"; +get_block_timestamp(H, Depth) when Depth < ?RECENT_BLOCKS_WITHOUT_TIMESTAMP -> + <<"pending">>; get_block_timestamp(H, _Depth) -> B = ar_block_cache:get(block_cache, H), case B#block.receive_timestamp of - undefined -> "pending"; + undefined -> <<"pending">>; Timestamp -> ar_util:timestamp_to_seconds(Timestamp) - end. \ No newline at end of file + end. + diff --git a/apps/arweave/src/ar_serialize.erl b/apps/arweave/src/ar_serialize.erl index cacc92ea7..879ebb280 100644 --- a/apps/arweave/src/ar_serialize.erl +++ b/apps/arweave/src/ar_serialize.erl @@ -30,7 +30,7 @@ json_map_to_candidate/1, jobs_to_json_struct/1, json_struct_to_jobs/1, partial_solution_response_to_json_struct/1, - pool_cm_jobs_to_json_struct/1, json_map_to_pool_cm_jobs/1, json_map_to_info_map/1]). + pool_cm_jobs_to_json_struct/1, json_map_to_pool_cm_jobs/1]). -include_lib("arweave/include/ar.hrl"). -include_lib("arweave/include/ar_vdf.hrl"). @@ -1406,7 +1406,6 @@ json_struct_to_poa({JSONStruct}) -> chunk = ar_util:decode(find_value(<<"chunk">>, JSONStruct)) }. -% FIXME. remove [return_maps] in ar_http_iface_middleware and make code uniform json_struct_to_poa_from_map(JSONStruct) -> #poa{ option = binary_to_integer(maps:get(<<"option">>, JSONStruct)), @@ -1968,19 +1967,6 @@ json_map_to_solution(JSON) -> steps = Steps }. -json_map_to_info_map(JSONMap) -> - lists:foldl( - fun(Key, Acc) -> - BinaryKey = atom_to_binary(Key, utf8), - case maps:get(BinaryKey, JSONMap, undefined) of - undefined -> Acc; - Value -> maps:put(Key, Value, Acc) - end - end, - #{}, - ar_info:get_keys() - ). - encode_if_set(JSON, _JSONProperty, not_set, _Encoder) -> JSON; encode_if_set(JSON, _JSONProperty, undefined, _Encoder) -> diff --git a/apps/arweave/test/ar_info_tests.erl b/apps/arweave/test/ar_info_tests.erl index 9045e0103..62f80b478 100644 --- a/apps/arweave/test/ar_info_tests.erl +++ b/apps/arweave/test/ar_info_tests.erl @@ -3,12 +3,15 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("arweave/include/ar.hrl"). -recent_test_() -> +recent_blocks_test_() -> [ {timeout, 120, fun test_recent_blocks_post/0}, {timeout, 120, fun test_recent_blocks_announcement/0} ]. +%% ------------------------------------------------------------------------------------------- +%% Recent blocks tests +%% ------------------------------------------------------------------------------------------- test_recent_blocks_post() -> test_recent_blocks(post). @@ -20,12 +23,11 @@ test_recent_blocks(Type) -> ar_test_node:start_peer(peer1, B0), GenesisBlock = [#{ <<"id">> => ar_util:encode(B0#block.indep_hash), - <<"received">> => "pending" + <<"received">> => <<"pending">> }], - ?assertEqual(GenesisBlock, - ar_http_iface_client:get_info(ar_test_node:peer_ip(peer1), recent)), + ?assertEqual(GenesisBlock, get_recent(ar_test_node:peer_ip(peer1), blocks)), - TargetHeight = ?INFO_BLOCKS+2, + TargetHeight = ?RECENT_BLOCKS+2, PeerBI = lists:foldl( fun(Height, _Acc) -> ar_test_node:mine(peer1), @@ -37,7 +39,7 @@ test_recent_blocks(Type) -> %% Peer1 recent has no timestamps since it hasn't received any of its own blocks %% gossipped back ?assertEqual(expected_blocks(peer1, PeerBI, true), - ar_http_iface_client:get_info(ar_test_node:peer_ip(peer1), recent)), + get_recent(ar_test_node:peer_ip(peer1), blocks)), %% Share blocks to peer1 lists:foreach( @@ -63,7 +65,7 @@ test_recent_blocks(Type) -> %% Peer1 recent should now have timestamps, but also black out the most recent %% ones. ?assertEqual(expected_blocks(peer1, PeerBI), - ar_http_iface_client:get_info(ar_test_node:peer_ip(peer1), recent)). + get_recent(ar_test_node:peer_ip(peer1), blocks)). expected_blocks(Node, BI) -> expected_blocks(Node, BI, false). @@ -72,10 +74,10 @@ expected_blocks(Node, BI, ForcePending) -> fun({H, _WeaveSize, _TXRoot}, Acc) -> B = ar_test_node:remote_call(Node, ar_block_cache, get, [block_cache, H]), Timestamp = case ForcePending of - true -> "pending"; + true -> <<"pending">>; false -> - case length(Acc) >= (?INFO_BLOCKS - ?INFO_BLOCKS_WITHOUT_TIMESTAMP - 1) of - true -> "pending"; + case length(Acc) >= (?RECENT_BLOCKS - ?RECENT_BLOCKS_WITHOUT_TIMESTAMP - 1) of + true -> <<"pending">>; false -> ar_util:timestamp_to_seconds(B#block.receive_timestamp) end end, @@ -85,5 +87,31 @@ expected_blocks(Node, BI, ForcePending) -> } | Acc] end, [], - lists:reverse(lists:sublist(BI, ?INFO_BLOCKS)) - ). \ No newline at end of file + lists:reverse(lists:sublist(BI, ?RECENT_BLOCKS)) + ). + +get_recent(Peer, Type) -> + case get_recent(Peer) of + info_unavailable -> info_unavailable; + Info -> + maps:get(atom_to_binary(Type), Info) + end. +get_recent(Peer) -> + case + ar_http:req(#{ + method => get, + peer => Peer, + path => "/recent", + connect_timeout => 1000, + timeout => 2 * 1000 + }) + of + {ok, {{<<"200">>, _}, _, JSON, _, _}} -> + case ar_serialize:json_decode(JSON, [return_maps]) of + {ok, JsonMap} -> + JsonMap; + {error, _} -> + info_unavailable + end; + _ -> info_unavailable + end. \ No newline at end of file