Skip to content

Commit fb51bf1

Browse files
committed
graph: enable ethereum host fns for subgraph datasource
1 parent 0216822 commit fb51bf1

File tree

13 files changed

+225
-151
lines changed

13 files changed

+225
-151
lines changed

chain/ethereum/src/data_source.rs

Lines changed: 2 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use graph::components::store::{EthereumCallCache, StoredDynamicDataSource};
66
use graph::components::subgraph::{HostMetrics, InstanceDSTemplateInfo, MappingError};
77
use graph::components::trigger_processor::RunnableTriggers;
88
use graph::data::value::Word;
9+
use graph::data_source::common::{MappingABI, UnresolvedMappingABI};
910
use graph::data_source::CausalityRegion;
1011
use graph::env::ENV_VARS;
1112
use graph::futures03::future::try_join;
@@ -33,7 +34,7 @@ use graph::{
3334
derive::CheapClone,
3435
prelude::{
3536
async_trait,
36-
ethabi::{Address, Contract, Event, Function, LogParam, ParamType, RawLog},
37+
ethabi::{Address, Event, Function, LogParam, ParamType, RawLog},
3738
serde_json, warn,
3839
web3::types::{Log, Transaction, H256},
3940
BlockNumber, CheapClone, EthereumCall, LightEthereumBlock, LightEthereumBlockExt,
@@ -1436,82 +1437,6 @@ impl UnresolvedMapping {
14361437
}
14371438
}
14381439

1439-
#[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)]
1440-
pub struct UnresolvedMappingABI {
1441-
pub name: String,
1442-
pub file: Link,
1443-
}
1444-
1445-
impl UnresolvedMappingABI {
1446-
pub async fn resolve(
1447-
self,
1448-
resolver: &Arc<dyn LinkResolver>,
1449-
logger: &Logger,
1450-
) -> Result<MappingABI, anyhow::Error> {
1451-
let contract_bytes = resolver.cat(logger, &self.file).await.with_context(|| {
1452-
format!(
1453-
"failed to resolve ABI {} from {}",
1454-
self.name, self.file.link
1455-
)
1456-
})?;
1457-
let contract = Contract::load(&*contract_bytes)?;
1458-
Ok(MappingABI {
1459-
name: self.name,
1460-
contract,
1461-
})
1462-
}
1463-
}
1464-
1465-
#[derive(Clone, Debug, PartialEq)]
1466-
pub struct MappingABI {
1467-
pub name: String,
1468-
pub contract: Contract,
1469-
}
1470-
1471-
impl MappingABI {
1472-
pub fn function(
1473-
&self,
1474-
contract_name: &str,
1475-
name: &str,
1476-
signature: Option<&str>,
1477-
) -> Result<&Function, Error> {
1478-
let contract = &self.contract;
1479-
let function = match signature {
1480-
// Behavior for apiVersion < 0.0.4: look up function by name; for overloaded
1481-
// functions this always picks the same overloaded variant, which is incorrect
1482-
// and may lead to encoding/decoding errors
1483-
None => contract.function(name).with_context(|| {
1484-
format!(
1485-
"Unknown function \"{}::{}\" called from WASM runtime",
1486-
contract_name, name
1487-
)
1488-
})?,
1489-
1490-
// Behavior for apiVersion >= 0.0.04: look up function by signature of
1491-
// the form `functionName(uint256,string) returns (bytes32,string)`; this
1492-
// correctly picks the correct variant of an overloaded function
1493-
Some(ref signature) => contract
1494-
.functions_by_name(name)
1495-
.with_context(|| {
1496-
format!(
1497-
"Unknown function \"{}::{}\" called from WASM runtime",
1498-
contract_name, name
1499-
)
1500-
})?
1501-
.iter()
1502-
.find(|f| signature == &f.signature())
1503-
.with_context(|| {
1504-
format!(
1505-
"Unknown function \"{}::{}\" with signature `{}` \
1506-
called from WASM runtime",
1507-
contract_name, name, signature,
1508-
)
1509-
})?,
1510-
};
1511-
Ok(function)
1512-
}
1513-
}
1514-
15151440
#[derive(Clone, Debug, Hash, Eq, PartialEq, Deserialize)]
15161441
pub struct MappingBlockHandler {
15171442
pub handler: String,

chain/ethereum/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use buffered_call_cache::BufferedCallCache;
1919

2020
// ETHDEP: These concrete types should probably not be exposed.
2121
pub use data_source::{
22-
BlockHandlerFilter, DataSource, DataSourceTemplate, Mapping, MappingABI, TemplateSource,
22+
BlockHandlerFilter, DataSource, DataSourceTemplate, Mapping, TemplateSource,
2323
};
2424

2525
pub mod chain;

chain/ethereum/src/runtime/runtime_adapter.rs

Lines changed: 87 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use std::{sync::Arc, time::Instant};
22

33
use crate::adapter::EthereumRpcError;
4-
use crate::data_source::MappingABI;
54
use crate::{
65
capabilities::NodeCapabilities, network::EthereumNetworkAdapters, Chain, ContractCall,
7-
ContractCallError, DataSource, EthereumAdapter, EthereumAdapterTrait, ENV_VARS,
6+
ContractCallError, EthereumAdapter, EthereumAdapterTrait, ENV_VARS,
87
};
98
use anyhow::{anyhow, Context, Error};
109
use blockchain::HostFn;
@@ -13,6 +12,8 @@ use graph::components::subgraph::HostMetrics;
1312
use graph::data::store::ethereum::call;
1413
use graph::data::store::scalar::BigInt;
1514
use graph::data::subgraph::API_VERSION_0_0_9;
15+
use graph::data_source;
16+
use graph::data_source::common::MappingABI;
1617
use graph::futures03::compat::Future01CompatExt;
1718
use graph::prelude::web3::types::H160;
1819
use graph::runtime::gas::Gas;
@@ -80,58 +81,93 @@ pub fn eth_call_gas(chain_identifier: &ChainIdentifier) -> Option<u32> {
8081
}
8182

8283
impl blockchain::RuntimeAdapter<Chain> for RuntimeAdapter {
83-
fn host_fns(&self, ds: &DataSource) -> Result<Vec<HostFn>, Error> {
84-
let abis = ds.mapping.abis.clone();
85-
let call_cache = self.call_cache.cheap_clone();
86-
let eth_adapters = self.eth_adapters.cheap_clone();
87-
let archive = ds.mapping.requires_archive()?;
88-
let eth_call_gas = eth_call_gas(&self.chain_identifier);
89-
90-
let ethereum_call = HostFn {
91-
name: "ethereum.call",
92-
func: Arc::new(move |ctx, wasm_ptr| {
93-
// Ethereum calls should prioritise call-only adapters if one is available.
94-
let eth_adapter = eth_adapters.call_or_cheapest(Some(&NodeCapabilities {
95-
archive,
96-
traces: false,
97-
}))?;
98-
ethereum_call(
99-
&eth_adapter,
100-
call_cache.cheap_clone(),
101-
ctx,
102-
wasm_ptr,
103-
&abis,
104-
eth_call_gas,
105-
)
106-
.map(|ptr| ptr.wasm_ptr())
107-
}),
108-
};
109-
110-
let eth_adapters = self.eth_adapters.cheap_clone();
111-
let ethereum_get_balance = HostFn {
112-
name: "ethereum.getBalance",
113-
func: Arc::new(move |ctx, wasm_ptr| {
114-
let eth_adapter = eth_adapters.unverified_cheapest_with(&NodeCapabilities {
115-
archive,
116-
traces: false,
117-
})?;
118-
eth_get_balance(&eth_adapter, ctx, wasm_ptr).map(|ptr| ptr.wasm_ptr())
119-
}),
120-
};
84+
fn host_fns(&self, ds: &data_source::DataSource<Chain>) -> Result<Vec<HostFn>, Error> {
85+
fn create_host_fns(
86+
abis: Arc<Vec<Arc<MappingABI>>>, // Use Arc to ensure `'static` lifetimes.
87+
archive: bool,
88+
call_cache: Arc<dyn EthereumCallCache>,
89+
eth_adapters: Arc<EthereumNetworkAdapters>,
90+
eth_call_gas: Option<u32>,
91+
) -> Vec<HostFn> {
92+
vec![
93+
HostFn {
94+
name: "ethereum.call",
95+
func: Arc::new({
96+
let eth_adapters = eth_adapters.clone();
97+
let call_cache = call_cache.clone();
98+
let abis = abis.clone();
99+
move |ctx, wasm_ptr| {
100+
let eth_adapter =
101+
eth_adapters.call_or_cheapest(Some(&NodeCapabilities {
102+
archive,
103+
traces: false,
104+
}))?;
105+
ethereum_call(
106+
&eth_adapter,
107+
call_cache.clone(),
108+
ctx,
109+
wasm_ptr,
110+
&abis,
111+
eth_call_gas,
112+
)
113+
.map(|ptr| ptr.wasm_ptr())
114+
}
115+
}),
116+
},
117+
HostFn {
118+
name: "ethereum.getBalance",
119+
func: Arc::new({
120+
let eth_adapters = eth_adapters.clone();
121+
move |ctx, wasm_ptr| {
122+
let eth_adapter =
123+
eth_adapters.unverified_cheapest_with(&NodeCapabilities {
124+
archive,
125+
traces: false,
126+
})?;
127+
eth_get_balance(&eth_adapter, ctx, wasm_ptr).map(|ptr| ptr.wasm_ptr())
128+
}
129+
}),
130+
},
131+
HostFn {
132+
name: "ethereum.hasCode",
133+
func: Arc::new({
134+
let eth_adapters = eth_adapters.clone();
135+
move |ctx, wasm_ptr| {
136+
let eth_adapter =
137+
eth_adapters.unverified_cheapest_with(&NodeCapabilities {
138+
archive,
139+
traces: false,
140+
})?;
141+
eth_has_code(&eth_adapter, ctx, wasm_ptr).map(|ptr| ptr.wasm_ptr())
142+
}
143+
}),
144+
},
145+
]
146+
}
121147

122-
let eth_adapters = self.eth_adapters.cheap_clone();
123-
let ethereum_get_code = HostFn {
124-
name: "ethereum.hasCode",
125-
func: Arc::new(move |ctx, wasm_ptr| {
126-
let eth_adapter = eth_adapters.unverified_cheapest_with(&NodeCapabilities {
127-
archive,
128-
traces: false,
129-
})?;
130-
eth_has_code(&eth_adapter, ctx, wasm_ptr).map(|ptr| ptr.wasm_ptr())
131-
}),
148+
let host_fns = match ds {
149+
data_source::DataSource::Onchain(onchain_ds) => {
150+
let abis = Arc::new(onchain_ds.mapping.abis.clone());
151+
let archive = onchain_ds.mapping.requires_archive()?;
152+
let call_cache = self.call_cache.cheap_clone();
153+
let eth_adapters = self.eth_adapters.cheap_clone();
154+
let eth_call_gas = eth_call_gas(&self.chain_identifier);
155+
156+
create_host_fns(abis, archive, call_cache, eth_adapters, eth_call_gas)
157+
}
158+
data_source::DataSource::Subgraph(subgraph_ds) => {
159+
let abis = Arc::new(subgraph_ds.mapping.abis.clone());
160+
let archive = subgraph_ds.mapping.requires_archive()?;
161+
let call_cache = self.call_cache.cheap_clone();
162+
let eth_adapters = self.eth_adapters.cheap_clone();
163+
let eth_call_gas = eth_call_gas(&self.chain_identifier);
164+
165+
create_host_fns(abis, archive, call_cache, eth_adapters, eth_call_gas)
166+
}
167+
data_source::DataSource::Offchain(_) => vec![],
132168
};
133169

134-
Ok(vec![ethereum_call, ethereum_get_balance, ethereum_get_code])
170+
Ok(host_fns)
135171
}
136172
}
137173

graph/src/blockchain/mock.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::{
66
subgraph::InstanceDSTemplateInfo,
77
},
88
data::subgraph::UnifiedMappingApiVersion,
9+
data_source,
910
prelude::{
1011
transaction_receipt::LightTransactionReceipt, BlockHash, ChainStore,
1112
DataSourceTemplateInfo, StoreError,
@@ -352,7 +353,7 @@ impl<C: Blockchain> TriggerFilter<C> for MockTriggerFilter {
352353
pub struct MockRuntimeAdapter;
353354

354355
impl<C: Blockchain> RuntimeAdapter<C> for MockRuntimeAdapter {
355-
fn host_fns(&self, _ds: &C::DataSource) -> Result<Vec<HostFn>, Error> {
356+
fn host_fns(&self, _ds: &data_source::DataSource<C>) -> Result<Vec<HostFn>, Error> {
356357
todo!()
357358
}
358359
}

graph/src/blockchain/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,6 @@ where
458458
}
459459
}
460460

461-
// TODO(krishna): Proper ordering for triggers
462461
impl<C: Blockchain> Ord for Trigger<C>
463462
where
464463
C::TriggerData: Ord,
@@ -468,7 +467,7 @@ where
468467
(Trigger::Chain(data1), Trigger::Chain(data2)) => data1.cmp(data2),
469468
(Trigger::Subgraph(_), Trigger::Chain(_)) => std::cmp::Ordering::Greater,
470469
(Trigger::Chain(_), Trigger::Subgraph(_)) => std::cmp::Ordering::Less,
471-
(Trigger::Subgraph(_), Trigger::Subgraph(_)) => std::cmp::Ordering::Equal,
470+
(Trigger::Subgraph(t1), Trigger::Subgraph(t2)) => t1.entity.vid.cmp(&t2.entity.vid),
472471
}
473472
}
474473
}
@@ -545,7 +544,7 @@ pub struct HostFn {
545544
}
546545

547546
pub trait RuntimeAdapter<C: Blockchain>: Send + Sync {
548-
fn host_fns(&self, ds: &C::DataSource) -> Result<Vec<HostFn>, Error>;
547+
fn host_fns(&self, ds: &data_source::DataSource<C>) -> Result<Vec<HostFn>, Error>;
549548
}
550549

551550
pub trait NodeCapabilities<C: Blockchain> {

graph/src/blockchain/noop_runtime_adapter.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::marker::PhantomData;
22

3+
use crate::data_source;
4+
35
use super::{Blockchain, HostFn, RuntimeAdapter};
46

57
/// A [`RuntimeAdapter`] that does not expose any host functions.
@@ -16,7 +18,7 @@ impl<C> RuntimeAdapter<C> for NoopRuntimeAdapter<C>
1618
where
1719
C: Blockchain,
1820
{
19-
fn host_fns(&self, _ds: &C::DataSource) -> anyhow::Result<Vec<HostFn>> {
21+
fn host_fns(&self, _ds: &data_source::DataSource<C>) -> anyhow::Result<Vec<HostFn>> {
2022
Ok(vec![])
2123
}
2224
}

0 commit comments

Comments
 (0)