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

Add a loadInBlock host function for mappings #3459

Closed
lutter opened this issue Apr 12, 2022 · 7 comments
Closed

Add a loadInBlock host function for mappings #3459

lutter opened this issue Apr 12, 2022 · 7 comments
Assignees

Comments

@lutter
Copy link
Collaborator

lutter commented Apr 12, 2022

In some cases, subgraphs use entities to communicate some information between handlers in the same block (e.g., the Transaction entity in Uniswap-like subgraphs) They use them by following the pattern of 'try to load the entity, if it doesn't exist yet, create it'. That leads to considerable slowdowns since graph-node has to go to the database every time to confirm that the entity does indeed not exist yet, even though the subgraph author knows that that is futile. In one case, this pattern caused 20 lookups per second, and the roundtrips to the database took a considerable amount of time (about 10-15% of the overall processing time) even though the actual query takes very little time (under a millisecond). An experiment showed that avoiding these lookups increased block processing speed from 700ms/block to about 500ms/block.

We should therefore add a way for subgraph authors to express that an entity is only ever used by the indexing process for the duration of a block. That only makes sense for immutable entities, and we should therefore add another annotation writeonly: true for entity declarations which implies immutable: true. The subgraph schema would then look like

type Transaction @entity(writeonly: true) {
  id Bytes!
  ...
}

There might be better ways to express that than saying writeonly since it is legal to look these entities up with store.get in any handler that runs in the same block as the handler that creates the entity; it's only cross-block lookups that would be disabled by this annotation.

@leoyvens
Copy link
Collaborator

I'd would not even call these types "entities", since they are not meant to be queried by graphql.

Other things we could call them: type Transaction @ephemeral, type Transaction @temporary...

@lutter
Copy link
Collaborator Author

lutter commented Apr 12, 2022

I'd would not even call these types "entities", since they are not meant to be queried by graphql.

Other things we could call them: type Transaction @ephemeral, type Transaction @temporary...

At least as things are right now, they can be queried from GraphQL just fine; it's just that mappings won't be able to get to them after a block has been processed.

@azf20
Copy link
Contributor

azf20 commented Apr 29, 2022

Rather than creating a new entity-type annotation, would another approach be to introduce a way in the mappings to look into the entity cache for the block (kind of cache.get rather than store.get). This would then never need to go to the store, and it's slightly more intuitive as it is changing the runtime behaviour (do or don't go to the database) rather than the nature of the resulting entity (which is still a regular, queryable entry in postgres)
Perhaps would need to think through the interface (maybe it extends to store.get(id, database=true), where the second parameter defaults to true, but if set to false it doesn't go to the database, though I guess I don't love bastardising store

@lutter
Copy link
Collaborator Author

lutter commented Apr 29, 2022

Yes, that would be a good approach, too, and I think preferable to yet another annotation. We could call it something like store.get_in_block(id) to emphasize that the result must be from within processing the current block.

@azf20
Copy link
Contributor

azf20 commented Apr 29, 2022

What about the (more recommended I think?) EntityName.load syntax, that could be EntityName.loadInBlock?

@lutter
Copy link
Collaborator Author

lutter commented Apr 29, 2022

We still need a primitive for that, but wrapping that with EntityName.loadInBlock similar to how EntityName.load wraps store.get would be really good.

@lutter lutter changed the title Introduce a notion of a writeonly entity Add a loadInBlock host function for mappings Mar 28, 2023
@azf20
Copy link
Contributor

azf20 commented Apr 17, 2023

PR: #4540

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

No branches or pull requests

3 participants