Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat: query channel reserve at a hash (#1106)
  • Loading branch information
jyeshe committed Jan 4, 2023
1 parent 15bd964 commit e595f0b
Show file tree
Hide file tree
Showing 4 changed files with 379 additions and 66 deletions.
95 changes: 68 additions & 27 deletions lib/ae_mdw/channels.ex
Expand Up @@ -7,8 +7,10 @@ defmodule AeMdw.Channels do
alias AeMdw.Collection
alias AeMdw.Db.Model
alias AeMdw.Db.State
alias AeMdw.Db.Util, as: DbUtil
alias AeMdw.Error
alias AeMdw.Error.Input, as: ErrInput
alias AeMdw.Node.Db
alias AeMdw.Txs
alias AeMdw.Util
alias AeMdw.Validate
Expand All @@ -18,7 +20,8 @@ defmodule AeMdw.Channels do
require Model

@typep state() :: State.t()
@typep pubkey() :: AeMdw.Node.Db.pubkey()
@typep pubkey() :: Db.pubkey()
@typep type_block_hash() :: {Db.hash_type(), Db.hash()}
@typep pagination() :: Collection.direction_limit()
@typep range() :: {:gen, Range.t()} | nil
@typep cursor() :: Collection.pagination_cursor()
Expand Down Expand Up @@ -63,15 +66,13 @@ defmodule AeMdw.Channels do
type_count(state, :channel_settle_tx, from_txi, next_txi)
end

@spec fetch_channel(state(), pubkey()) :: {:ok, channel()} | {:error, Error.t()}
def fetch_channel(state, channel_pk) do
@spec fetch_channel(state(), pubkey(), type_block_hash() | nil) ::
{:ok, channel()} | {:error, Error.t()}
def fetch_channel(state, channel_pk, type_block_hash \\ nil) do
case locate(state, channel_pk) do
{:ok, channel, source} ->
{:ok,
render_channel(state, channel,
is_active?: source == Model.ActiveChannel,
node_details?: true
)}
{:ok, m_channel, source} ->
is_active? = source == Model.ActiveChannel
{:ok, render_channel(state, m_channel, is_active?, type_block_hash)}

:not_found ->
{:error, ErrInput.NotFound.exception(value: encode(:channel, channel_pk))}
Expand Down Expand Up @@ -103,10 +104,8 @@ defmodule AeMdw.Channels do

defp render_active_channels(state, keys) do
Enum.map(keys, fn {_exp, channel_pk} ->
render_channel(state, State.fetch!(state, @table_active, channel_pk),
is_active?: true,
node_details?: false
)
m_channel = State.fetch!(state, @table_active, channel_pk)
render_channel(state, m_channel, true)
end)
end

Expand All @@ -118,12 +117,14 @@ defmodule AeMdw.Channels do
responder: responder_pk,
state_hash: state_hash,
amount: amount,
updates: [{{last_updated_height, _mbi}, last_updated_txi} | _rest] = updates
updates:
[{{last_updated_height, _mbi} = update_block_index, last_updated_txi} | _rest] =
updates
),
is_active?: is_active?,
node_details?: node_details?
is_active?,
type_block_hash \\ nil
) do
%{"block_hash" => block_hash, "hash" => tx_hash, "tx" => %{"type" => tx_type}} =
%{"block_hash" => update_block_hash, "hash" => tx_hash, "tx" => %{"type" => tx_type}} =
Txs.fetch!(state, last_updated_txi)

channel = %{
Expand All @@ -138,17 +139,24 @@ defmodule AeMdw.Channels do
active: is_active?
}

with true <- node_details?,
{:ok, node_channel} <-
:aec_chain.get_channel_at_hash(channel_pk, Validate.id!(block_hash)) do
node_details = :aesc_channels.serialize_for_client(node_channel)
block_hash =
get_oldest_block_hash(
state,
type_block_hash,
Validate.id!(update_block_hash),
update_block_index
)

case :aec_chain.get_channel_at_hash(channel_pk, block_hash) do
{:ok, node_channel} ->
node_details = :aesc_channels.serialize_for_client(node_channel)

channel
|> Map.merge(node_details)
|> Map.drop(~w(id initiator_id responder_id channel_amount))
|> Map.put(:amount, node_details["channel_amount"])
else
_no_details ->
channel
|> Map.merge(node_details)
|> Map.drop(~w(id initiator_id responder_id channel_amount))
|> Map.put(:amount, node_details["channel_amount"])

{:error, _reason} ->
Map.put(channel, :amount, amount)
end
end
Expand All @@ -175,4 +183,37 @@ defmodule AeMdw.Channels do
end

defp deserialize_scope(_nil_or_txis_scope), do: nil

# Gets from the oldest block state tree since some channels might be absent from newer blocks
defp get_oldest_block_hash(_state, nil, update_block_hash, _update_block_index),
do: update_block_hash

defp get_oldest_block_hash(
state,
{block_type, block_hash},
update_block_hash,
update_block_index
) do
case get_block_index(state, block_type, block_hash) do
{:ok, height, mbi} ->
if update_block_index < {height, mbi} do
update_block_hash
else
block_hash
end

{:error, _reason} ->
update_block_hash
end
end

defp get_block_index(state, :key, block_hash) do
with {:ok, height} <- DbUtil.key_block_height(state, block_hash) do
{:ok, height, -1}
end
end

defp get_block_index(state, :micro, block_hash) do
DbUtil.micro_block_height_index(state, block_hash)
end
end
1 change: 1 addition & 0 deletions lib/ae_mdw/node/db.ex
Expand Up @@ -14,6 +14,7 @@ defmodule AeMdw.Node.Db do

@type pubkey() :: <<_::256>>
@type hash_type() :: nil | :key | :micro
@type hash() :: <<_::256>>
@type height_hash() :: {hash_type(), pos_integer(), binary()}
@type balances_map() :: %{{:address, pubkey()} => integer()}
@type account_balance() :: {integer() | nil, height_hash()}
Expand Down
19 changes: 17 additions & 2 deletions lib/ae_mdw_web/controllers/channel_controller.ex
Expand Up @@ -22,10 +22,25 @@ defmodule AeMdwWeb.ChannelController do
end

@spec channel(Conn.t(), map()) :: Conn.t()
def channel(%Conn{assigns: %{state: state}} = conn, %{"id" => id}) do
def channel(%Conn{assigns: %{state: state}} = conn, %{"id" => id} = params) do
block_hash = params["block_hash"]

with {:ok, channel_pk} <- Validate.id(id, [:channel]),
{:ok, channel} <- Channels.fetch_channel(state, channel_pk) do
{:ok, type_block_hash} <- valid_optional_block_hash?(block_hash),
{:ok, channel} <- Channels.fetch_channel(state, channel_pk, type_block_hash) do
json(conn, channel)
end
end

defp valid_optional_block_hash?(nil), do: {:ok, nil}

defp valid_optional_block_hash?(block_hash) do
with {:ok, hash} <- Validate.id(block_hash) do
if String.starts_with?(block_hash, "kh") do
{:ok, {:key, hash}}
else
{:ok, {:micro, hash}}
end
end
end
end

0 comments on commit e595f0b

Please sign in to comment.