Repository navigation
Declarative calls #5264
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
Merged
Merged
Declarative calls #5264
Changes from all commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
13617c5
all: Expose match_and_decode as a TriggerProcessor method
lutter dbedcc4
all: Introduce a name for a host and a trigger
lutter ea98c2b
all: Lift calling match_and_decode out of TriggerProcessor
lutter a60f36f
core: Refactor how IndexingContext.process_trigger_in_hosts is called
lutter 75b6539
core: Assign the result of calling process_trigger_in_hosts to a vari…
lutter d277348
core: Inline all calls to IndexingContext.process_trigger_in_hosts
lutter 7d247da
core: Restructure the loop in SubgraphRunner.process_block
lutter cbf5520
core: Split match_and_decode and processing into separate loops
lutter a025ad0
test: Use substreams::TriggerProcessor for substreams
lutter 5859c21
chain, core, graph: Put match_and_decode into a different trait
lutter bb639c0
core: Split match_and_decode and processing for new data sources
lutter beff28b
core, graph: Simplify handling of match_and_decode result
lutter ce15f1f
core, graph: Decoder doesn't need to be a trait
lutter 27d62be
all: Pass the spec version to DataSource.validate
lutter b01c1aa
chain/ethereum: Factor function look up into MappingABI
lutter dd9f6ec
all: Allow declaring eth calls on ethereum event handlers
lutter cbfbacb
all: Introduce a Blockchain::DecoderHook
lutter a293fd8
chain/ethereum: Add a buffered call cache
lutter a502528
graph, runtime: Expose the HostMetrics of a RuntimeHost
lutter cf94cf9
all: Add a decoder hook for ethereum
lutter f25610a
chain, graph: Allow turning off declared calls
lutter daa25f5
chain: Make eth calls in parallel
lutter 1003ab8
chain/ethereum: Asyncify EthereumAdapter.contract_call
lutter 3e40cbd
chain/ethereum: Pass EthereumCall by reference
lutter 2a54222
chain/ethereum: Report time for declared eth calls in their own section
lutter b613148
all: Clarify whether an eth call was never made or had no result
lutter 8bfc61e
chain, graph, store: Use Bytes instad of Vec<u8> for eth_call results
lutter 7f5a671
chain/ethereum: Cache failed call results
lutter 2581185
chain/ethereum, graph, store: Avoid double-counting declared calls
lutter d94916a
chain/ethereum: Deduplicate declared eth calls
lutter 5681367
chain/ethereum: Provide the correct amount of gas for declared calls
lutter 1910a11
chain, graph, store: Address race condition in caching eth calls
lutter c74cbba
chain, graph: Change how we log eth calls
lutter 7405863
chain: Log failures of declared calls
lutter b37e583
docs: Add declared calls to the manifest spec
lutter 272aa36
all: Introduce a struct for the data needed for an eth_call
lutter 02bec43
all: Move some of the helper structs for handling eth calls around
lutter e4aa6f0
all: Struct for return value and source for a eth_call response
lutter 2703680
chain/ethereum: Factor out generating the eth_call request
lutter cb737f9
chain/ethereum: Further factor EthereumAdapter.contract_call
lutter 70f719f
chain, graph, store: Relate call requests to calls via an index
lutter e6c09c4
chain/ethereum: Return responses in the right order
lutter c8c8161
chain/ethereum: Add an EthereumAdapter.contract_calls
lutter 73e8e68
chain, graph, store: Lookup eth_calls in bulk
lutter 1ab4a66
chain/ethereum: Look up calls from the cache in bulk
lutter ce64824
chain/ethereum: Parallelize RPC calls in EthereumAapter.contract_calls
lutter 9f467bc
chain/ethereum: Strip the `Ethereum` prefix of a few types
lutter bd5ae84
chain/ethereum: Decoding call results never produces an error
lutter 4527ad7
chain/ethereum: Log errors for individual calls in EthereumAdapter
lutter ffd52c2
chain/ethereum: Change how we parallelize eth calls
lutter 1973985
all: Change initialization of RuntimeAdapter and DecoderHook
lutter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| use std::{ | ||
| collections::HashMap, | ||
| sync::{Arc, Mutex}, | ||
| }; | ||
|
|
||
| use graph::{ | ||
| cheap_clone::CheapClone, | ||
| components::store::EthereumCallCache, | ||
| data::store::ethereum::call, | ||
| prelude::{BlockPtr, CachedEthereumCall}, | ||
| slog::{error, Logger}, | ||
| }; | ||
|
|
||
| /// A wrapper around an Ethereum call cache that buffers call results in | ||
| /// memory for the duration of a block. If `get_call` or `set_call` are | ||
| /// called with a different block pointer than the one used in the previous | ||
| /// call, the buffer is cleared. | ||
| pub struct BufferedCallCache { | ||
| call_cache: Arc<dyn EthereumCallCache>, | ||
| buffer: Arc<Mutex<HashMap<call::Request, call::Retval>>>, | ||
| block: Arc<Mutex<Option<BlockPtr>>>, | ||
| } | ||
|
|
||
| impl BufferedCallCache { | ||
| pub fn new(call_cache: Arc<dyn EthereumCallCache>) -> Self { | ||
| Self { | ||
| call_cache, | ||
| buffer: Arc::new(Mutex::new(HashMap::new())), | ||
| block: Arc::new(Mutex::new(None)), | ||
| } | ||
| } | ||
|
|
||
| fn check_block(&self, block: &BlockPtr) { | ||
| let mut self_block = self.block.lock().unwrap(); | ||
| if self_block.as_ref() != Some(block) { | ||
| *self_block = Some(block.clone()); | ||
| self.buffer.lock().unwrap().clear(); | ||
| } | ||
| } | ||
|
|
||
| fn get(&self, call: &call::Request) -> Option<call::Response> { | ||
| let buffer = self.buffer.lock().unwrap(); | ||
| buffer.get(call).map(|retval| { | ||
| call.cheap_clone() | ||
| .response(retval.clone(), call::Source::Memory) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| impl EthereumCallCache for BufferedCallCache { | ||
| fn get_call( | ||
| &self, | ||
| call: &call::Request, | ||
| block: BlockPtr, | ||
| ) -> Result<Option<call::Response>, graph::prelude::Error> { | ||
| self.check_block(&block); | ||
|
|
||
| if let Some(value) = self.get(call) { | ||
| return Ok(Some(value)); | ||
| } | ||
|
|
||
| let result = self.call_cache.get_call(&call, block)?; | ||
|
|
||
| let mut buffer = self.buffer.lock().unwrap(); | ||
| if let Some(call::Response { | ||
| retval, | ||
| req: _, | ||
| source: _, | ||
| }) = &result | ||
| { | ||
| buffer.insert(call.cheap_clone(), retval.clone()); | ||
| } | ||
| Ok(result) | ||
| } | ||
|
|
||
| fn get_calls( | ||
| &self, | ||
| reqs: &[call::Request], | ||
| block: BlockPtr, | ||
| ) -> Result<(Vec<call::Response>, Vec<call::Request>), graph::prelude::Error> { | ||
| self.check_block(&block); | ||
|
|
||
| let mut missing = Vec::new(); | ||
| let mut resps = Vec::new(); | ||
|
|
||
| for call in reqs { | ||
| match self.get(call) { | ||
| Some(resp) => resps.push(resp), | ||
| None => missing.push(call.cheap_clone()), | ||
| } | ||
| } | ||
|
|
||
| let (stored, calls) = self.call_cache.get_calls(&missing, block)?; | ||
|
|
||
| { | ||
| let mut buffer = self.buffer.lock().unwrap(); | ||
| for resp in &stored { | ||
| buffer.insert(resp.req.cheap_clone(), resp.retval.clone()); | ||
| } | ||
| } | ||
|
|
||
| resps.extend(stored); | ||
| Ok((resps, calls)) | ||
| } | ||
|
|
||
| fn get_calls_in_block( | ||
| &self, | ||
| block: BlockPtr, | ||
| ) -> Result<Vec<CachedEthereumCall>, graph::prelude::Error> { | ||
| self.call_cache.get_calls_in_block(block) | ||
| } | ||
|
|
||
| fn set_call( | ||
| &self, | ||
| logger: &Logger, | ||
| call: call::Request, | ||
| block: BlockPtr, | ||
| return_value: call::Retval, | ||
| ) -> Result<(), graph::prelude::Error> { | ||
| self.check_block(&block); | ||
|
|
||
| // Enter the call into the in-memory cache immediately so that | ||
| // handlers will find it, but add it to the underlying cache in the | ||
| // background so we do not have to wait for that as it will be a | ||
| // cache backed by the database | ||
| { | ||
| let mut buffer = self.buffer.lock().unwrap(); | ||
| buffer.insert(call.cheap_clone(), return_value.clone()); | ||
| } | ||
|
|
||
| let cache = self.call_cache.cheap_clone(); | ||
| let logger = logger.cheap_clone(); | ||
| let _ = graph::spawn_blocking_allow_panic(move || { | ||
| cache | ||
| .set_call(&logger, call.cheap_clone(), block, return_value) | ||
| .map_err(|e| { | ||
| error!(logger, "BufferedCallCache: call cache set error"; | ||
| "contract_address" => format!("{:?}", call.address), | ||
| "error" => e.to_string()) | ||
| }) | ||
| }); | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think instead of "check_block" something like "clear_block_if_different" or something would make it more clear while reading callsites