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

feat: filter internal calls by contract and function #1330

Merged
merged 2 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
124 changes: 87 additions & 37 deletions lib/ae_mdw/contracts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ defmodule AeMdw.Contracts do
@int_contract_call_table Model.IntContractCall
@grp_int_contract_call_table Model.GrpIntContractCall
@fname_int_contract_call_table Model.FnameIntContractCall
@fname_grp_contract_call_table Model.FnameGrpIntContractCall
@id_int_contract_call_table Model.IdIntContractCall
@grp_id_int_contract_call_table Model.GrpIdIntContractCall

Expand Down Expand Up @@ -120,8 +121,7 @@ defmodule AeMdw.Contracts do
{prev_cursor, calls, next_cursor} =
query
|> Map.drop(@pagination_params)
|> Enum.map(&convert_param(state, &1))
|> Enum.sort()
|> Enum.into(%{}, &convert_param(state, &1))
|> build_calls_pagination(state, scope, cursor)
|> Collection.paginate(pagination)

Expand Down Expand Up @@ -290,10 +290,15 @@ defmodule AeMdw.Contracts do
end
end

defp build_calls_pagination([fname: fname_prefix], state, scope, cursor) do
defp build_calls_pagination(
%{create_txi: create_txi, fname: fname_prefix},
state,
scope,
cursor
) do
cursor =
with {call_txi, local_idx, _create_txi, _pk, fname, _pos} <- cursor do
{fname, call_txi, local_idx}
{fname, create_txi, call_txi, local_idx}
end

fnames =
Expand All @@ -309,52 +314,37 @@ defmodule AeMdw.Contracts do

fn direction ->
fnames
|> Enum.map(&build_calls_fname_stream(state, &1, direction, scope, cursor))
|> Enum.map(&build_calls_grp_fname_stream(state, &1, direction, scope, cursor, create_txi))
|> Collection.merge(direction)
end
end

defp build_calls_pagination(
[create_txi: create_txi],
state,
{first_call_txi, last_call_txi},
cursor
) do
key_boundary = {{create_txi, first_call_txi, @min_idx}, {create_txi, last_call_txi, @max_idx}}

defp build_calls_pagination(%{fname: fname_prefix}, state, scope, cursor) do
cursor =
with {call_txi, local_idx, _create_txi, _pk, _fname, _pos} <- cursor do
{create_txi, call_txi, local_idx}
with {call_txi, local_idx, _create_txi, _pk, fname, _pos} <- cursor do
{fname, call_txi, local_idx}
end

fn direction ->
state
|> Collection.stream(@grp_int_contract_call_table, direction, key_boundary, cursor)
|> Stream.map(fn {create_txi, call_txi, local_idx} ->
{call_txi, local_idx, create_txi, @min_pubkey, @min_fname, @min_id_pos}
fnames =
fname_prefix
|> Stream.unfold(fn prefix ->
case State.next(state, @fname_int_contract_call_table, {prefix, @min_txi, @min_idx}) do
{:ok, {next_fname, _txi, _idx}} -> {next_fname, next_fname <> @max_256bit_bin}
:none -> nil
end
end)
end
end

defp build_calls_pagination([], state, {first_call_txi, last_call_txi}, cursor) do
key_boundary = {{first_call_txi, @min_idx}, {last_call_txi, @max_idx}}

cursor =
with {call_txi, local_idx, _create_txi, _pk, _fname, _pos} <- cursor do
{call_txi, local_idx}
end
|> Stream.take_while(&String.starts_with?(&1, fname_prefix))
|> Enum.to_list()

fn direction ->
state
|> Collection.stream(@int_contract_call_table, direction, key_boundary, cursor)
|> Stream.map(fn {call_txi, local_idx} ->
{call_txi, local_idx, @min_txi, @min_pubkey, @min_fname, @min_id_pos}
end)
fnames
|> Enum.map(&build_calls_fname_stream(state, &1, direction, scope, cursor))
|> Collection.merge(direction)
end
end

defp build_calls_pagination(
[create_txi: create_txi, type_pos: {pos_types, pk}],
%{create_txi: create_txi, type_pos: {pos_types, pk}},
state,
{first_call_txi, last_call_txi},
cursor
Expand Down Expand Up @@ -387,7 +377,29 @@ defmodule AeMdw.Contracts do
end

defp build_calls_pagination(
[type_pos: {pos_types, pk}],
%{create_txi: create_txi},
state,
{first_call_txi, last_call_txi},
cursor
) do
key_boundary = {{create_txi, first_call_txi, @min_idx}, {create_txi, last_call_txi, @max_idx}}

cursor =
with {call_txi, local_idx, _create_txi, _pk, _fname, _pos} <- cursor do
{create_txi, call_txi, local_idx}
end

fn direction ->
state
|> Collection.stream(@grp_int_contract_call_table, direction, key_boundary, cursor)
|> Stream.map(fn {create_txi, call_txi, local_idx} ->
{call_txi, local_idx, create_txi, @min_pubkey, @min_fname, @min_id_pos}
end)
end
end

defp build_calls_pagination(
%{type_pos: {pos_types, pk}},
state,
{first_call_txi, last_call_txi},
cursor
Expand Down Expand Up @@ -417,6 +429,24 @@ defmodule AeMdw.Contracts do
end
end

defp build_calls_pagination(query, state, {first_call_txi, last_call_txi}, cursor)
when map_size(query) == 0 do
key_boundary = {{first_call_txi, @min_idx}, {last_call_txi, @max_idx}}

cursor =
with {call_txi, local_idx, _create_txi, _pk, _fname, _pos} <- cursor do
{call_txi, local_idx}
end

fn direction ->
state
|> Collection.stream(@int_contract_call_table, direction, key_boundary, cursor)
|> Stream.map(fn {call_txi, local_idx} ->
{call_txi, local_idx, @min_txi, @min_pubkey, @min_fname, @min_id_pos}
end)
end
end

defp build_calls_pagination(query, _scope, _state, _cursor),
do: raise(ErrInput.Query, value: query)

Expand Down Expand Up @@ -448,6 +478,26 @@ defmodule AeMdw.Contracts do
end)
end

defp build_calls_grp_fname_stream(
state,
fname,
direction,
{first_txi, last_txi},
cursor,
create_txi
) do
key_boundary = {
{fname, create_txi, first_txi, @min_idx},
{fname, create_txi, last_txi, @max_idx}
}

state
|> Collection.stream(@fname_grp_contract_call_table, direction, key_boundary, cursor)
|> Stream.map(fn {^fname, ^create_txi, call_txi, local_idx} ->
{call_txi, local_idx, create_txi, @min_pubkey, fname, @min_id_pos}
end)
end

defp build_calls_fname_stream(state, fname, direction, {first_txi, last_txi}, cursor) do
key_boundary = {{fname, first_txi, @min_idx}, {fname, last_txi, @max_idx}}

Expand Down
56 changes: 56 additions & 0 deletions test/ae_mdw_web/controllers/contract_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,62 @@ defmodule AeMdwWeb.Controllers.ContractControllerTest do
assert %{"data" => ^calls} =
conn |> with_store(store) |> get(prev_calls) |> json_response(200)
end

test "returns internal calls filtered by function and contract", %{
conn: conn,
contract_pk: contract_pk,
store: store
} do
fname_prefix = "Chain.sp"
contract_id = encode_contract(contract_pk)
create_txi = Origin.tx_index!(State.new(store), {:contract, contract_pk})

assert %{"data" => calls, "next" => next} =
conn
|> with_store(store)
|> get("/v2/contracts/calls", function: fname_prefix, contract: contract_id)
|> json_response(200)

assert Enum.each(calls, fn %{
"function" => function,
"call_txi" => call_txi,
"contract_txi" => contract_txi,
"height" => height,
"micro_index" => micro_index,
"block_hash" => block_hash
} ->
assert String.starts_with?(function, fname_prefix)
assert call_txi in @call_txis and contract_txi == create_txi
assert height == @call_kbi

assert micro_index == @call_mbi and
assert(block_hash == encode(:micro_block_hash, @call_block_hash))
end)

assert 10 = length(calls)

assert %{"data" => next_calls, "prev" => prev_calls} =
conn |> with_store(store) |> get(next) |> json_response(200)

assert Enum.each(next_calls, fn %{
"function" => function,
"call_txi" => call_txi,
"contract_txi" => contract_txi,
"height" => height,
"micro_index" => micro_index,
"block_hash" => block_hash
} ->
assert String.starts_with?(function, fname_prefix)
assert call_txi in @call_txis and contract_txi == create_txi
assert height == @call_kbi

assert micro_index == @call_mbi and
assert(block_hash == encode(:micro_block_hash, @call_block_hash))
end)

assert %{"data" => ^calls} =
conn |> with_store(store) |> get(prev_calls) |> json_response(200)
end
end

describe "contracts" do
Expand Down
Loading