Skip to content

Commit 4d43c22

Browse files
committed
chain, graph: Use a Result type when checking for transaction success
1 parent 88d7c43 commit 4d43c22

File tree

5 files changed

+56
-23
lines changed

5 files changed

+56
-23
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

chain/ethereum/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ ethabi = { git = "https://github.com/graphprotocol/ethabi.git", branch = "master
2828

2929
# We have a couple custom patches to web3.
3030
web3 = { git = "https://github.com/graphprotocol/rust-web3", branch = "master" }
31+
itertools = "0.10.0"
3132

3233
[dev-dependencies]
3334
diesel = { version = "1.4.6", features = ["postgres", "serde_json", "numeric", "r2d2"] }

chain/ethereum/src/chain.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ impl TriggersAdapterTrait<Chain> for TriggersAdapter {
338338
&filter.log,
339339
&full_block.ethereum_block,
340340
));
341-
triggers.append(&mut parse_call_triggers(&filter.call, &full_block));
341+
triggers.append(&mut parse_call_triggers(&filter.call, &full_block)?);
342342
triggers.append(&mut parse_block_triggers(filter.block.clone(), &full_block));
343343
Ok(BlockWithTriggers::new(
344344
WrappedBlockFinality(block),

chain/ethereum/src/ethereum_adapter.rs

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
1+
use ethabi::ParamType;
12
use ethabi::Token;
23
use futures::future;
34
use futures::prelude::*;
4-
use lazy_static::lazy_static;
5-
use std::collections::{HashMap, HashSet};
6-
use std::convert::TryFrom;
7-
use std::iter::FromIterator;
8-
use std::sync::Arc;
9-
use std::time::Instant;
10-
11-
use ethabi::ParamType;
125
use graph::{
136
blockchain::{block_stream::BlockWithTriggers, BlockPtr, IngestorError},
147
prelude::{
@@ -30,6 +23,13 @@ use graph::{
3023
components::ethereum::*,
3124
prelude::web3::types::{Trace, TraceFilter, TraceFilterBuilder, H160},
3225
};
26+
use itertools::Itertools;
27+
use lazy_static::lazy_static;
28+
use std::collections::{HashMap, HashSet};
29+
use std::convert::TryFrom;
30+
use std::iter::FromIterator;
31+
use std::sync::Arc;
32+
use std::time::Instant;
3333
use web3::api::Web3;
3434
use web3::transports::batch::Batch;
3535
use web3::types::Filter;
@@ -1588,15 +1588,21 @@ pub(crate) fn parse_log_triggers(
15881588
pub(crate) fn parse_call_triggers(
15891589
call_filter: &EthereumCallFilter,
15901590
block: &EthereumBlockWithCalls,
1591-
) -> Vec<EthereumTrigger> {
1591+
) -> anyhow::Result<Vec<EthereumTrigger>> {
15921592
match &block.calls {
15931593
Some(calls) => calls
15941594
.iter()
15951595
.filter(move |call| call_filter.matches(call))
1596-
.filter(move |call| block.transaction_for_call_succeeded(call))
1597-
.map(move |call| EthereumTrigger::Call(Arc::new(call.clone())))
1596+
.map(
1597+
move |call| match block.transaction_for_call_succeeded(call) {
1598+
Ok(true) => Ok(Some(EthereumTrigger::Call(Arc::new(call.clone())))),
1599+
Ok(false) => Ok(None),
1600+
Err(e) => Err(e),
1601+
},
1602+
)
1603+
.filter_map_ok(|some_trigger| some_trigger)
15981604
.collect(),
1599-
None => vec![],
1605+
None => Ok(vec![]),
16001606
}
16011607
}
16021608

graph/src/components/ethereum/types.rs

+35-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use crate::{
1111
prelude::{BlockNumber, DeploymentHash, EntityKey, ToEntityKey},
1212
};
1313

14+
const BYZANTIUM_FORK_BLOCK_NUMBER: u64 = 4_370_000;
15+
1416
pub type LightEthereumBlock = Block<Transaction>;
1517

1618
pub trait LightEthereumBlockExt {
@@ -113,29 +115,52 @@ pub struct EthereumBlockWithCalls {
113115

114116
impl EthereumBlockWithCalls {
115117
/// Given an `EthereumCall`, check within receipts if that transaction was successful.
116-
pub fn transaction_for_call_succeeded(&self, call: &EthereumCall) -> bool {
118+
pub fn transaction_for_call_succeeded(&self, call: &EthereumCall) -> anyhow::Result<bool> {
117119
// return true if call does not have a transaction hash.
118120
// TODO: should we return `false` instead?
119121
let call_transaction_hash = match call.transaction_hash {
120122
Some(transaction_hash) => transaction_hash,
121-
None => return true,
123+
None => return Ok(true),
122124
};
123125

124126
// TODO: if there is no transaction receipt, should we return `true` instead?
125-
let receipt = match self
127+
let receipt = self
126128
.ethereum_block
127129
.transaction_receipts
128130
.iter()
129131
.find(|txn| txn.transaction_hash == call_transaction_hash)
130-
{
131-
Some(receipt) => receipt,
132-
None => return false,
133-
};
132+
.ok_or(anyhow::anyhow!(
133+
"failed to find the receipt for this transaction"
134+
))?;
135+
136+
let transaction = self
137+
.ethereum_block
138+
.block
139+
.transaction_for_call(&call)
140+
.ok_or(anyhow::anyhow!(
141+
"failed to find the transaction for this call"
142+
))?;
143+
144+
let pre_byzantium = self
145+
.ethereum_block
146+
.block
147+
.number
148+
.ok_or(anyhow::anyhow!("Pending block number"))?
149+
.as_u64()
150+
< BYZANTIUM_FORK_BLOCK_NUMBER;
151+
152+
let used_all_gas = receipt
153+
.gas_used
154+
.ok_or(anyhow::anyhow!("Running in light client mode)"))?
155+
>= transaction.gas;
156+
157+
if pre_byzantium && used_all_gas {
158+
return Ok(false);
159+
}
134160

135-
// TODO: should we handle None differently than Some(0)?
136161
match receipt.status {
137-
Some(x) if x == web3::types::U64::from(1) => true,
138-
Some(_) | None => false,
162+
Some(x) if x == web3::types::U64::from(1) => Ok(true),
163+
Some(_) | None => Ok(false),
139164
}
140165
}
141166
}

0 commit comments

Comments
 (0)