Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e2b6ade
fix: Add try/catch on hb_store_arweave
speeddragon Apr 21, 2026
76c1dfe
feat: Add L1 TX filtering with owner and tag support
charmful0x Mar 6, 2026
3885f27
feat: Add L1 TX offset loading and configuration
charmful0x Mar 7, 2026
9225c78
feat: Add block N depth indexing
charmful0x Mar 10, 2026
d040e29
test: Add tests and refactor copycat internals
JamesPiechota Mar 10, 2026
fc548e7
impr: Add indexer logging and response improvements
JamesPiechota Mar 12, 2026
93fff56
fix: Operational fixes for copycat indexer
JamesPiechota Mar 13, 2026
725c05b
feat: Add per-block item index with depth tracking
nikooo777 Apr 3, 2026
f9733ae
feat: Add parallel block processing with shared memory budget
nikooo777 Apr 9, 2026
bf770e7
feat: Add parent lookup endpoint at ~arweave@2.9/parent=<id>
nikooo777 Apr 9, 2026
d6dffff
fix: Stop latest_height from silently returning 0 on network errors
nikooo777 Apr 14, 2026
eba05bf
fix: Catch non UTF8 tags error
speeddragon Apr 28, 2026
1170302
impr: Missing try catch on non UTF8 tags
speeddragon Apr 29, 2026
4494696
impr: signed not needed
speeddragon May 1, 2026
9e48c3c
impr: Add overlay_count metrics from store LMDB to see if server is w…
speeddragon May 1, 2026
958d81a
impr: Check if write fails and throw fast in index write cases
speeddragon May 1, 2026
b4e831a
impr: Add a max retry limit to hb_copycat_budget
speeddragon May 1, 2026
08a61d9
impr: Remove dead code
speeddragon May 1, 2026
f4f6ce8
impr: Remove memory_safe_cap (redundant), to only use copycat_memory_…
speeddragon May 1, 2026
bbb28f8
impr: Do not return not_found where there is an error in dev_arweave:…
speeddragon May 3, 2026
813c63d
impr: Re-add warning before exit on hb_event
speeddragon May 3, 2026
8481881
impr: Minor fixes
speeddragon May 4, 2026
58bd0b4
impr: stop monitor in hb_store_lmdb
speeddragon May 4, 2026
77ab8f4
impr: Fix hb_store new structure for previous changes
speeddragon May 4, 2026
3d713d4
fix: tests in dev_copycat_arweave after edge rebase
speeddragon May 5, 2026
629a0dd
impr: Moving some functions to hb_store_arweave from dev_copycat_arwe…
speeddragon May 6, 2026
7003217
impr: Fix bug on index scope
speeddragon May 7, 2026
76cf109
impr: Use hb_opts instead of hb_maps
speeddragon May 7, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 99 additions & 4 deletions src/dev_arweave.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
%%% `/arweave` route in the node's configuration message.
-module(dev_arweave).
-export([info/0]).
-export([tx/3, raw/3, chunk/3, block/3, current/3, status/3, price/3, tx_anchor/3]).
-export([tx/3, raw/3, chunk/3, block/3, parent/3, current/3, status/3, price/3, tx_anchor/3]).
-export([pending/3]).
-export([post_tx_header/2, post_tx/3, post_tx/4, post_chunk/2]).
%%% Helper functions
Expand Down Expand Up @@ -173,7 +173,16 @@ head_raw(Base, Request, Opts) ->
<<"tx@1.0">> -> fun head_raw_tx/4;
_ -> throw({invalid_codec_device, CodecDevice})
end,
CodecFun(TXID, StartOffset, Length, Opts);
try CodecFun(TXID, StartOffset, Length, Opts)
catch _:Reason:Stacktrace ->
%% This can be prone to serialization error.
%% Catch and output as an error.
?event(store_error, {head_raw,
{txid, TXID},
{reason, Reason},
{stacktrace, Stacktrace}}),
{error, Reason}
end;
not_found ->
?event(
arweave,
Expand Down Expand Up @@ -793,6 +802,57 @@ block({height, Height}, Opts) ->
)
end.

%% @doc Look up the parent (block or bundle) that contains an item.
parent(Base, Request, Opts) ->
case find_key(<<"parent">>, Base, Request, Opts) of
not_found ->
{error, not_found};
ID ->
StoreOpts = hb_store_arweave:store_from_opts(Opts),
try hb_store_arweave:read_parent(StoreOpts, ID, Opts) of
{ok, [{Height, block} | _]} ->
Entry = #{
<<"type">> => <<"block">>,
<<"height">> => Height
},
{ok, #{
<<"content-type">> => <<"application/json">>,
<<"body">> =>
hb_json:encode(#{<<"parents">> => [Entry]})
}};
{ok, [{ParentID, bundle} | _]} ->
Entry = #{
<<"type">> => <<"bundle">>,
<<"id">> => hb_util:encode(ParentID)
},
{ok, #{
<<"content-type">> => <<"application/json">>,
<<"body">> =>
hb_json:encode(#{<<"parents">> => [Entry]})
}};
{error, Reason} ->
?event(warning,
{parent_read_error, {id, ID}, {reason, Reason}}),
{error, not_found};
not_found ->
{error, not_found}
catch
error:Reason:Stacktrace ->
?event(error,
{parent_read_error,
{id, ID},
{reason, Reason},
{stacktrace, Stacktrace}
}),
{failure,
#{
<<"status">> => 500,
<<"type">> => <<"parent_read_error">>
}
}
end
end.

%% @doc Retrieve the current block information from Arweave.
current(_Base, _Request, Opts) ->
request(<<"GET">>, <<"/block/current">>, Opts).
Expand Down Expand Up @@ -953,7 +1013,7 @@ to_message(Path = <<"/block/", _/binary>>, <<"GET">>, {ok, #{ <<"body">> := Body
Opts
),
CacheRes =
case hb_opts:get(arweave_index_blocks, true, Opts) of
case hb_opts:get(<<"arweave-index-blocks">>, true, Opts) of
true -> dev_arweave_block_cache:write(Block, Opts);
false -> skipped
end,
Expand Down Expand Up @@ -1357,7 +1417,8 @@ index_test_tx(TXID, IndexStore, Opts) ->
TXID,
<<"tx@1.0">>,
StartOffset,
Size
Size,
Opts
),
?assertMatch({ok, _}, hb_store_arweave:read_offset(IndexStore, TXID)),
ok.
Expand Down Expand Up @@ -1551,6 +1612,40 @@ head_raw_ans104_test_parallel() ->
hb_maps:find(<<"content-length">>, Result, Opts)
).

%% @doc Interior Arweave offset returns bytes that are not a valid ANS-104
%% header, so head_raw_ans104/4 throws inside do_head_raw_ans104/5. The
%% try-catch added to head_raw/3 must convert that throw into {error, _}.
head_raw_ans104_deserialize_throws_test_parallel() ->
TestStore = hb_test_utils:test_store(hb_store_volatile, <<"head-raw-throws">>),
IndexStore = #{
<<"module">> => hb_store_arweave,
<<"index-store">> => [TestStore]
},
Opts = #{
<<"store">> => [TestStore],
<<"arweave-index-ids">> => true,
<<"arweave-index-store">> => IndexStore
},
FakeID = <<"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC">>,
%% Same interior offset as bundle_header_garbage_guard_test_parallel.
ProbeOffset = 376836336327208,
Size = 4096,
ok = hb_store_arweave:write_offset(
IndexStore, FakeID, <<"ans104@1.0">>, ProbeOffset - 1, Size, Opts
),
?assertMatch(
{error, _},
hb_ao:resolve(
#{ <<"device">> => <<"arweave@2.9">> },
#{
<<"path">> => <<"raw">>,
<<"raw">> => FakeID,
<<"method">> => <<"HEAD">>
},
Opts
)
).

get_raw_range_tx_test_parallel() ->
DataItemID = <<"ptBC0UwDmrUTBQX3MqZ1lB57ex20ygwzkjjCrQjIx3o">>,
Opts = setup_arweave_index_opts([DataItemID]),
Expand Down
Loading