Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit efae4e9

Browse files
author
Jannis Pohlmann
committed
runtime/wasm: Implement new event processing in RuntimeHost
1 parent d369750 commit efae4e9

File tree

1 file changed

+167
-63
lines changed

1 file changed

+167
-63
lines changed

runtime/wasm/src/host.rs

Lines changed: 167 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
use failure::*;
2-
use futures::sync::mpsc::{channel, Receiver, Sender};
2+
use futures::sync::mpsc::{channel, Sender};
33
use futures::sync::oneshot;
4-
use std::str::FromStr;
54
use std::thread;
6-
use uuid::Uuid;
75

86
use graph::components::ethereum::*;
97
use graph::components::store::Store;
108
use graph::data::subgraph::DataSource;
9+
use graph::ethabi::Contract;
10+
use graph::ethabi::LogParam;
11+
use graph::ethabi::RawLog;
1112
use graph::prelude::{
12-
RuntimeHost as RuntimeHostTrait, RuntimeHostBuilder as RuntimeHostBuilderTrait, *,
13+
MappingABI, RuntimeHost as RuntimeHostTrait, RuntimeHostBuilder as RuntimeHostBuilderTrait, *,
1314
};
1415
use graph::util;
15-
use graph::web3::types::Address;
16+
use graph::web3::types::{Log, Transaction};
1617

1718
use module::{WasmiModule, WasmiModuleConfig};
1819

@@ -90,11 +91,15 @@ where
9091

9192
type HandleEventResponse = Result<Vec<EntityOperation>, Error>;
9293

93-
type HandleEventRequest = (
94-
EthereumEvent,
95-
MappingEventHandler,
96-
oneshot::Sender<HandleEventResponse>,
97-
);
94+
struct HandleEventRequest {
95+
handler: MappingEventHandler,
96+
block: Arc<EthereumBlock>,
97+
transaction: Arc<Transaction>,
98+
log: Arc<Log>,
99+
params: Vec<LogParam>,
100+
entity_operations: Vec<EntityOperation>,
101+
result_sender: oneshot::Sender<HandleEventResponse>,
102+
}
98103

99104
pub struct RuntimeHost {
100105
config: RuntimeHostConfig,
@@ -164,14 +169,29 @@ impl RuntimeHost {
164169
.select(cancel_receiver.into_stream().map(|_| None).map_err(|_| ()))
165170
.for_each(move |request: Option<HandleEventRequest>| {
166171
if let Some(request) = request {
167-
let (event, handler, response_sender) = request;
172+
let HandleEventRequest {
173+
handler,
174+
block,
175+
transaction,
176+
log,
177+
params,
178+
entity_operations,
179+
result_sender,
180+
} = request;
168181

169182
debug!(event_logger, " Call event handler";
170183
"name" => &handler.handler,
171184
"signature" => &handler.event);
172185

173-
let result = module.handle_ethereum_event(handler.handler.as_str(), event);
174-
future::result(response_sender.send(result).map_err(|_| ()))
186+
let result = module.handle_ethereum_event(
187+
handler.handler.as_str(),
188+
block,
189+
transaction,
190+
log,
191+
params,
192+
entity_operations,
193+
);
194+
future::result(result_sender.send(result).map_err(|_| ()))
175195
} else {
176196
future::err(())
177197
}
@@ -186,72 +206,156 @@ impl RuntimeHost {
186206
_guard: cancel_sender,
187207
}
188208
}
189-
}
190209

191-
impl RuntimeHostTrait for RuntimeHost {
192-
fn subgraph_manifest(&self) -> &SubgraphManifest {
193-
&self.config.subgraph_manifest
210+
fn matches_log_address(&self, log: &Log) -> bool {
211+
self.config.data_source.source.address == log.address
194212
}
195213

196-
fn matches_event(&self, event: &EthereumEvent) -> bool {
214+
fn matches_log_signature(&self, log: &Log) -> bool {
215+
let signature = if log.topics.len() > 0 {
216+
log.topics[0]
217+
} else {
218+
return false;
219+
};
220+
197221
self.config
198222
.data_source
199223
.mapping
200224
.event_handlers
201225
.iter()
202226
.find(|event_handler| {
203-
event.event_signature
204-
== util::ethereum::string_to_h256(event_handler.event.as_str())
227+
signature == util::ethereum::string_to_h256(event_handler.event.as_str())
205228
}).is_some()
206229
}
207230

208-
fn process_event(
209-
&self,
210-
event: EthereumEvent,
211-
) -> Box<Future<Item = Vec<EntityOperation>, Error = Error> + Send> {
212-
let handler = self
213-
.config
231+
fn source_contract(&self) -> Result<&MappingABI, Error> {
232+
self.config
233+
.data_source
234+
.mapping
235+
.abis
236+
.iter()
237+
.find(|abi| abi.name == self.config.data_source.source.abi)
238+
.ok_or(format_err!(
239+
"No ABI entry found for the main contract of data source \"{}\": {}",
240+
self.config.data_source.name,
241+
self.config.data_source.source.abi,
242+
))
243+
}
244+
245+
fn event_handler_for_log(&self, log: &Arc<Log>) -> Result<&MappingEventHandler, Error> {
246+
// Get signature from the log
247+
let signature = if log.topics.len() > 0 {
248+
log.topics[0]
249+
} else {
250+
return Err(format_err!("Ethereum event has no topics"));
251+
};
252+
253+
self.config
214254
.data_source
215255
.mapping
216256
.event_handlers
217257
.iter()
218-
.find(|event_handler| {
219-
event.event_signature
220-
== util::ethereum::string_to_h256(event_handler.event.as_str())
221-
});
222-
223-
match handler {
224-
Some(handler) => {
225-
debug!(self.logger, "Process Ethereum event"; "signature" => &handler.event);
226-
227-
let (result_sender, result_receiver) = oneshot::channel();
228-
229-
let before_event_signature = handler.event.clone();
230-
let event_signature = handler.event.clone();
231-
232-
Box::new(
233-
self.handle_event_sender
234-
.clone()
235-
.send((event, handler.clone(), result_sender))
236-
.map_err(move |_| {
237-
format_err!(
238-
"Mapping terminated before passing in Ethereum event: {}",
239-
before_event_signature
240-
)
241-
}).and_then(|_| {
242-
result_receiver.map_err(move |_| {
243-
format_err!(
244-
"Mapping terminated before finishing to handle \
245-
Ethereum event: {}",
246-
event_signature,
247-
)
248-
})
249-
}).and_then(|result| result),
250-
)
258+
.find(|handler| signature == util::ethereum::string_to_h256(handler.event.as_str()))
259+
.ok_or(format_err!(
260+
"No event handler found for event in data source \"{}\"",
261+
self.config.data_source.name,
262+
))
263+
}
264+
}
265+
266+
impl RuntimeHostTrait for RuntimeHost {
267+
fn subgraph_manifest(&self) -> &SubgraphManifest {
268+
&self.config.subgraph_manifest
269+
}
270+
271+
fn matches_log(&self, log: &Log) -> bool {
272+
self.matches_log_address(log) && self.matches_log_signature(log)
273+
}
274+
275+
fn process_log(
276+
&self,
277+
block: Arc<EthereumBlock>,
278+
transaction: Arc<Transaction>,
279+
log: Arc<Log>,
280+
entity_operations: Vec<EntityOperation>,
281+
) -> Box<Future<Item = Vec<EntityOperation>, Error = Error> + Send> {
282+
// Identify the contract that the log belongs to
283+
let abi = match self.source_contract() {
284+
Ok(abi) => abi,
285+
Err(e) => return Box::new(future::err(e)),
286+
};
287+
288+
// Identify event handler for this log
289+
let event_handler = match self.event_handler_for_log(&log) {
290+
Ok(handler) => handler,
291+
Err(e) => return Box::new(future::err(e)),
292+
};
293+
294+
// Identify the event ABI in the contract
295+
let event_abi = match util::ethereum::contract_event_with_signature(
296+
&abi.contract,
297+
event_handler.event.as_str(),
298+
) {
299+
Some(event_abi) => event_abi,
300+
None => {
301+
return Box::new(future::err(format_err!(
302+
"Event with the signature \"{}\" not found in \
303+
contract \"{}\" of data source \"{}\"",
304+
event_handler.event,
305+
abi.name,
306+
self.config.data_source.name
307+
)))
251308
}
252-
None => Box::new(future::err(format_err!(
253-
"Ethereum event not mentioned in the data source"
254-
))),
255-
}
309+
};
310+
311+
// Parse the log into an event
312+
let params = match event_abi.parse_log(RawLog {
313+
topics: log.topics.clone(),
314+
data: log.data.clone().0,
315+
}) {
316+
Ok(log) => log.params,
317+
Err(e) => {
318+
return Box::new(future::err(format_err!(
319+
"Failed to parse parameters of event: {}: {}",
320+
event_handler.event,
321+
e
322+
)))
323+
}
324+
};
325+
326+
debug!(self.logger, "Process Ethereum event"; "signature" => &event_handler.event);
327+
328+
// Call the event handler and asynchronously wait for the result
329+
let (result_sender, result_receiver) = oneshot::channel();
330+
331+
let before_event_signature = event_handler.event.clone();
332+
let event_signature = event_handler.event.clone();
333+
334+
Box::new(
335+
self.handle_event_sender
336+
.clone()
337+
.send(HandleEventRequest {
338+
handler: event_handler.clone(),
339+
block: block.clone(),
340+
transaction: transaction.clone(),
341+
log: log.clone(),
342+
params,
343+
entity_operations,
344+
result_sender,
345+
}).map_err(move |_| {
346+
format_err!(
347+
"Mapping terminated before passing in Ethereum event: {}",
348+
before_event_signature
349+
)
350+
}).and_then(|_| {
351+
result_receiver.map_err(move |_| {
352+
format_err!(
353+
"Mapping terminated before finishing to handle \
354+
Ethereum event: {}",
355+
event_signature,
356+
)
357+
})
358+
}).and_then(|result| result),
359+
)
256360
}
257361
}

0 commit comments

Comments
 (0)