11use failure:: * ;
2- use futures:: sync:: mpsc:: { channel, Receiver , Sender } ;
2+ use futures:: sync:: mpsc:: { channel, Sender } ;
33use futures:: sync:: oneshot;
4- use std:: str:: FromStr ;
54use std:: thread;
6- use uuid:: Uuid ;
75
86use graph:: components:: ethereum:: * ;
97use graph:: components:: store:: Store ;
108use graph:: data:: subgraph:: DataSource ;
9+ use graph:: ethabi:: Contract ;
10+ use graph:: ethabi:: LogParam ;
11+ use graph:: ethabi:: RawLog ;
1112use graph:: prelude:: {
12- RuntimeHost as RuntimeHostTrait , RuntimeHostBuilder as RuntimeHostBuilderTrait , * ,
13+ MappingABI , RuntimeHost as RuntimeHostTrait , RuntimeHostBuilder as RuntimeHostBuilderTrait , * ,
1314} ;
1415use graph:: util;
15- use graph:: web3:: types:: Address ;
16+ use graph:: web3:: types:: { Log , Transaction } ;
1617
1718use module:: { WasmiModule , WasmiModuleConfig } ;
1819
@@ -90,11 +91,15 @@ where
9091
9192type 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
99104pub 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