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: introduce now transaction hash range scoping #2096

Merged
merged 3 commits into from
Feb 17, 2025

Conversation

sborrazas
Copy link
Contributor

refs #2075

@sborrazas sborrazas self-assigned this Feb 12, 2025
@sborrazas sborrazas force-pushed the transaction-hash-scoping branch from 299c471 to f6f4ea4 Compare February 12, 2025 13:40
Comment on lines 588 to 607
def tx_hash_to_txi(state, tx_hash) do
encoded_tx_hash = :aeser_api_encoder.encode(:tx_hash, tx_hash)

with mb_hash when is_binary(mb_hash) <- :aec_db.find_tx_location(tx_hash),
{:ok, mb_height} <- Db.find_block_height(mb_hash) do
state
|> Blocks.fetch_txis_from_gen(mb_height)
|> Stream.map(&State.fetch!(state, @table, &1))
|> Enum.find_value(
{:error, ErrInput.NotFound.exception(value: encoded_tx_hash)},
fn
Model.tx(index: txi, id: ^tx_hash) -> {:ok, txi}
_tx -> nil
end
)
else
_no_block_or_header ->
{:error, ErrInput.NotFound.exception(value: encoded_tx_hash)}
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @sborrazas I was looking for the find_tx_location to catch up with the code again and came across with the fetch/3. It seems a good opportunity of reuse.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you mean here, you mean fetching the full tx with the rendering by calling fetch/3?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the difference to the fetch/3, it would be only on the line of the {:ok, txt} return.

def fetch(state, tx_hash, opts) when is_binary(tx_hash) do
    encoded_tx_hash = :aeser_api_encoder.encode(:tx_hash, tx_hash)

    with mb_hash when is_binary(mb_hash) <- :aec_db.find_tx_location(tx_hash),
         {:ok, mb_height} <- Db.find_block_height(mb_hash) do
      state
      |> Blocks.fetch_txis_from_gen(mb_height)
      |> Stream.map(&State.fetch!(state, @table, &1))
      |> Enum.find_value(
        {:error, ErrInput.NotFound.exception(value: encoded_tx_hash)},
        fn
          Model.tx(id: ^tx_hash) = tx -> {:ok, render(state, tx, opts)}
          _tx -> nil
        end
      )
    else
      _no_block_or_header ->
        {:error, ErrInput.NotFound.exception(value: encoded_tx_hash)}
    end
  end

There would be multiple ways to refactor to reuse most of it in a way that only the rendering varies. Maybe a good reason to decouple the rendering from the fetching or would consider just rendering in another way as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I extracted it into the function that returns {:ok, Model.tx()} so it can be reused in both places

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brilliant!

_txi_scope,
state
) do
with tx_hashes when length(tx_hashes) > 0 and length(tx_hashes) <= 2 <-
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an alternative suggest would be to pattern match with [_hash1, _hash2] = tx_hashes, similar, just another flavour

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't pattern-match on this since it's valid for it to be a single element array too

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean this format [_hash1 | _hash2] = tx_hashes for a more compact condition but it's fine the lengthy one (:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm, it would be lengthier checking the rest of the list

end

defp extract_direction_and_scope(
%{"scope_type" => scope_type} = params,
_txi_scope? = false,
state
)
when scope_type in ["gen", "time", "epoch"] do
when scope_type in ["gen", "time", "epoch", "transaction"] do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔆

{:ok, :backward, {scope_type, last..first}}
end

defp generate_range(_state, scope_type, first, last, params) do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is the match for first = last, maybe instead of calling first and last just call it smth like gen?
It made me thinking about it after looking at the

      {:ok, :forward, {scope_type, last..first}}

while above we have

    {:ok, :forward, {scope_type, first..last}}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not always a gen, it can be txis and I think time too

@sborrazas sborrazas requested a review from jyeshe February 14, 2025 11:31
@sborrazas sborrazas merged commit c3c1bda into master Feb 17, 2025
7 checks passed
@sborrazas sborrazas deleted the transaction-hash-scoping branch February 17, 2025 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants