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

refactor historical API #1930

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open

refactor historical API #1930

wants to merge 12 commits into from

Conversation

tsachiherman
Copy link
Contributor

@tsachiherman tsachiherman commented Feb 14, 2025

What ?

This PR is the first refactor ovehaul for the hyper sdk indexer.
The PR addresses consistency and interface functionality.

Changes

  • Unify the three grpc block request endpoints into a single endpoint (GetBlockByHeight, GetBlockByHash, GetLatestBlock) into GetBlock. The structure parameter for GetBlock would provide the same functionality previously provided by the individual endpoints.
  • The query for the transaction information would now be capable of returning more details about the transaction.
  • The indexer block storage and in-memory cache are now always aligned.
  • The indexer internal variables are now correctly synchronized.

Issue

#1923

@tsachiherman tsachiherman self-assigned this Feb 14, 2025
@tsachiherman tsachiherman marked this pull request as ready for review February 17, 2025 15:22
Comment on lines +95 to +96
// the following should not happen, as we maintain only blockWindow entries; however,
// if it does, the following would correct that.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since the block window can change on restart, this comment is not accurate ie. we may hit this when the block window shortens such that we should remove blocks

Comment on lines +149 to +150
// ensure that lastHeight always contains the highest height we've seen.
i.lastHeight = max(i.lastHeight, blk.Block.Hght)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we use this here? We should only ever receive blocks in order.

return nil
}

func (i *Indexer) Notify(_ context.Context, blk *chain.ExecutedBlock) error {
i.mu.Lock()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we really need to grab the lock while writing to the database?

I believe using an atomic should be sufficient and removes the need to hold the lock during database operations.

We only read the last height during GetLatestBlock, if it's updated during that time, it should be fine to return a slightly outdated latest block. If a client performs sequential calls, this should still provide them a monotonically increasing view of the latest block.

return nil
}

func (i *Indexer) Notify(_ context.Context, blk *chain.ExecutedBlock) error {
i.mu.Lock()
defer i.mu.Unlock()
Copy link
Collaborator

Choose a reason for hiding this comment

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

let's add a blank line after grab and defer releasing the lock for consistent style

Comment on lines +155 to +157
i.mu.RLock()
defer i.mu.RUnlock()
return i.GetBlockByHeight(i.lastHeight)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comment here for empty line after deferring the lock

@@ -55,4 +63,5 @@ func (f *FIFO[K, V]) Get(key K) (V, bool) {
// [WriteLock] is held when this is accessed.
func (f *FIFO[K, V]) remove(key K) {
delete(f.m, key)
f.removedKey = &key
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm it seems fairly odd to pass around this data via an internal pointer modified via the callback in the bounded buffer.

It seems that we added this to return the removed key for the indexer, but I don't think we should modify the fifo cache with this hack to support that specific case. Is there a reason not to use DeleteRange to make sure that we've removed everything below our desired height?

type GetBlockByHeightRequest struct {
Height uint64 `json:"height"`
BlockID ids.ID `json:"blockID"`
BlockNumber uint64 `json:"blockNumber"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

(out of scope for this PR) Can we add an Encoding argument that can be either json or hex, defaults to hex, and specifies which field in the response to fill out ie. we populate either the block bytes or block field, but not both?

Can we apply the same to the transaction and either populate the JSON of the transaction or the transaction bytes?

@@ -53,8 +56,8 @@ func (c *Client) GetBlockByHeight(ctx context.Context, height uint64, parser cha
resp := GetBlockClientResponse{}
err := c.requester.SendRequest(
ctx,
"getBlockByHeight",
&GetBlockByHeightRequest{Height: height},
"getBlock",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Out of scope for this PR - we should move the parser from an argument to each function to an argument to construct the client instance, so that we don't need to pass it around each time

Comment on lines +119 to +122
if found && response.Result != nil {
success = response.Result.Success
fee = response.Result.Fee
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need the check for result to be nil? We should guarantee this is never the case

Comment on lines +44 to +47
f.removedKey = nil
f.buffer.Push(key) // Push removes the oldest [K] if we are at the [limit]
removedKey = f.removedKey
f.removedKey = nil
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do we add f.removedKey = nil both before and after? It seems we should only ever need one.

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.

2 participants