Skip to content

Commit 1435fce

Browse files
author
Filippo Costa
authored
graphql, index-node: endpoint to get a hash from a block number (graphprotocol#3942)
* refactor(graphql): asyncify scalar value resolution We're marking the GraphQL resolver for scalar values as async, like some other resolvers are already. This is needed to .await some calls in the new `index-node` endpoint. * feat(index-node): new number -> hash endpoint
1 parent 4850b82 commit 1435fce

File tree

4 files changed

+76
-2
lines changed

4 files changed

+76
-2
lines changed

graphql/src/execution/execution.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,7 @@ async fn resolve_field_value_for_named_type(
645645
s::TypeDefinition::Scalar(t) => {
646646
ctx.resolver
647647
.resolve_scalar_value(object_type, field, t, field_value)
648+
.await
648649
}
649650

650651
s::TypeDefinition::Interface(i) => {

graphql/src/execution/resolver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub trait Resolver: Sized + Send + Sync + 'static {
5151
}
5252

5353
/// Resolves a scalar value for a given scalar type.
54-
fn resolve_scalar_value(
54+
async fn resolve_scalar_value(
5555
&self,
5656
_parent_object_type: &s::ObjectType,
5757
_field: &a::Field,

server/index-node/src/resolver.rs

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,75 @@ impl<S: Store> IndexNodeResolver<S> {
202202
})
203203
}
204204

205+
async fn resolve_block_hash_from_number(
206+
&self,
207+
field: &a::Field,
208+
) -> Result<r::Value, QueryExecutionError> {
209+
let network = field
210+
.get_required::<String>("network")
211+
.expect("Valid network required");
212+
let block_number = field
213+
.get_required::<BlockNumber>("blockNumber")
214+
.expect("Valid blockNumber required");
215+
216+
macro_rules! try_resolve_for_chain {
217+
( $typ:path ) => {
218+
let blockchain = self.blockchain_map.get::<$typ>(network.to_string()).ok();
219+
220+
if let Some(blockchain) = blockchain {
221+
debug!(
222+
self.logger,
223+
"Fetching block hash from number";
224+
"network" => &network,
225+
"block_number" => block_number,
226+
);
227+
228+
let block_ptr_res = blockchain
229+
.block_pointer_from_number(&self.logger, block_number)
230+
.await;
231+
232+
if let Err(e) = block_ptr_res {
233+
warn!(
234+
self.logger,
235+
"Failed to fetch block hash from number";
236+
"network" => &network,
237+
"chain" => <$typ as Blockchain>::KIND.to_string(),
238+
"block_number" => block_number,
239+
"error" => e.to_string(),
240+
);
241+
return Ok(r::Value::Null);
242+
}
243+
244+
let block_ptr = block_ptr_res.unwrap();
245+
return Ok(r::Value::String(block_ptr.hash_hex()));
246+
}
247+
};
248+
}
249+
250+
// Ugly, but we can't get back an object trait from the `BlockchainMap`,
251+
// so this seems like the next best thing.
252+
try_resolve_for_chain!(graph_chain_ethereum::Chain);
253+
try_resolve_for_chain!(graph_chain_arweave::Chain);
254+
try_resolve_for_chain!(graph_chain_cosmos::Chain);
255+
try_resolve_for_chain!(graph_chain_near::Chain);
256+
257+
// If you're adding support for a new chain and this `match` clause just
258+
// gave you a compiler error, then this message is for you! You need to
259+
// add a new `try_resolve!` macro invocation above for your new chain
260+
// type.
261+
match BlockchainKind::Ethereum {
262+
// Note: we don't actually care about substreams here.
263+
BlockchainKind::Substreams
264+
| BlockchainKind::Arweave
265+
| BlockchainKind::Ethereum
266+
| BlockchainKind::Cosmos
267+
| BlockchainKind::Near => (),
268+
}
269+
270+
// The given network does not exist.
271+
Ok(r::Value::Null)
272+
}
273+
205274
async fn resolve_cached_ethereum_calls(
206275
&self,
207276
field: &a::Field,
@@ -734,7 +803,7 @@ impl<S: Store> Resolver for IndexNodeResolver<S> {
734803
}
735804

736805
/// Resolves a scalar value for a given scalar type.
737-
fn resolve_scalar_value(
806+
async fn resolve_scalar_value(
738807
&self,
739808
parent_object_type: &s::ObjectType,
740809
field: &a::Field,
@@ -748,6 +817,9 @@ impl<S: Store> Resolver for IndexNodeResolver<S> {
748817
) {
749818
("Query", "proofOfIndexing", "Bytes") => self.resolve_proof_of_indexing(field),
750819
("Query", "blockData", "JSONObject") => self.resolve_block_data(field),
820+
("Query", "blockHashFromNumber", "Bytes") => {
821+
self.resolve_block_hash_from_number(field).await
822+
}
751823

752824
// Fallback to the same as is in the default trait implementation. There
753825
// is no way to call back into the default implementation for the trait.

server/index-node/src/schema.graphql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type Query {
3939
subgraphFeatures(subgraphId: String!): SubgraphFeatures!
4040
entityChangesInBlock(subgraphId: String!, blockNumber: Int!): EntityChanges!
4141
blockData(network: String!, blockHash: Bytes!): JSONObject
42+
blockHashFromNumber(network: String!, blockNumber: Int!): Bytes
4243
cachedEthereumCalls(
4344
network: String!
4445
blockHash: Bytes!

0 commit comments

Comments
 (0)