Skip to content

Commit 31d4907

Browse files
authored
Merge pull request #77 from Blobscan/chore/alloy-migration
chore: migrate from `ethers-rs` to `alloy`
2 parents 57fc30c + e96d25f commit 31d4907

File tree

13 files changed

+2400
-1923
lines changed

13 files changed

+2400
-1923
lines changed

Diff for: Cargo.lock

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

Diff for: Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ async-trait = "0.1.80"
1010
dyn-clone = "1.0.17"
1111
dotenv = "0.15.0"
1212
envy = "0.4.2"
13-
ethers = "1.0.2"
13+
alloy = { version = "0.5.3", features = ["provider-http", "rpc-types"] }
14+
sha2 = "0.10.8"
1415
futures = "0.3.25"
1516
hex = "0.4.3"
1617
reqwest = { version = "0.11.13", features = ["json"] }
@@ -36,5 +37,6 @@ thiserror = "1.0.40"
3637
sentry = { version = "0.31.2", features = ["debug-images"] }
3738
sentry-tracing = "0.31.2"
3839

40+
3941
[dev-dependencies]
4042
mockall = "0.12.1"

Diff for: src/clients/beacon/types.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use std::{fmt, str::FromStr};
22

3-
use ethers::types::{Bytes, H256};
3+
use alloy::primitives::{Bytes, B256};
44
use serde::{Deserialize, Serialize};
55

66
#[derive(Serialize, Debug, Clone, PartialEq)]
77
pub enum BlockId {
88
Head,
99
Finalized,
1010
Slot(u32),
11-
Hash(H256),
11+
Hash(B256),
1212
}
1313

1414
#[derive(Serialize, Debug)]
@@ -20,7 +20,7 @@ pub enum Topic {
2020

2121
#[derive(Deserialize, Debug)]
2222
pub struct ExecutionPayload {
23-
pub block_hash: H256,
23+
pub block_hash: B256,
2424
#[serde(deserialize_with = "deserialize_number")]
2525
pub block_number: u32,
2626
}
@@ -64,7 +64,7 @@ pub struct BlockHeaderResponse {
6464

6565
#[derive(Deserialize, Debug)]
6666
pub struct BlockHeader {
67-
pub root: H256,
67+
pub root: B256,
6868
pub header: InnerBlockHeader,
6969
}
7070
#[derive(Deserialize, Debug)]
@@ -74,7 +74,7 @@ pub struct InnerBlockHeader {
7474

7575
#[derive(Deserialize, Debug)]
7676
pub struct BlockHeaderMessage {
77-
pub parent_root: H256,
77+
pub parent_root: B256,
7878
#[serde(deserialize_with = "deserialize_number")]
7979
pub slot: u32,
8080
}
@@ -83,12 +83,12 @@ pub struct BlockHeaderMessage {
8383
pub struct HeadEventData {
8484
#[serde(deserialize_with = "deserialize_number")]
8585
pub slot: u32,
86-
pub block: H256,
86+
pub block: B256,
8787
}
8888

8989
#[derive(Deserialize, Debug)]
9090
pub struct FinalizedCheckpointEventData {
91-
pub block: H256,
91+
pub block: B256,
9292
}
9393

9494
fn deserialize_number<'de, D>(deserializer: D) -> Result<u32, D::Error>
@@ -133,7 +133,7 @@ impl FromStr for BlockId {
133133
Ok(num) => Ok(BlockId::Slot(num)),
134134
Err(_) => {
135135
if s.starts_with("0x") {
136-
match H256::from_str(s) {
136+
match B256::from_str(s) {
137137
Ok(hash) => Ok(BlockId::Hash(hash)),
138138
Err(_) => Err(format!("Invalid block ID hash: {s}")),
139139
}

Diff for: src/clients/blobscan/types.rs

+87-87
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
use core::fmt;
22

3+
use alloy::primitives::{Address, BlockNumber, BlockTimestamp, Bytes, TxIndex, B256, U256};
4+
use alloy::rpc::types::{Block as ExecutionBlock, Transaction as ExecutionTransaction};
35
use anyhow::{Context, Result};
4-
use ethers::types::{
5-
Address, Block as EthersBlock, Bytes, Transaction as EthersTransaction, H256, U256, U64,
6-
};
6+
77
use serde::{Deserialize, Serialize};
88

99
use crate::{clients::beacon::types::Blob as BeaconBlob, utils::web3::calculate_versioned_hash};
1010

1111
#[derive(Serialize, Deserialize, Debug)]
1212
#[serde(rename_all = "camelCase")]
1313
pub struct Block {
14-
pub number: U64,
15-
pub hash: H256,
16-
pub timestamp: U256,
14+
pub number: BlockNumber,
15+
pub hash: B256,
16+
pub timestamp: BlockTimestamp,
1717
pub slot: u32,
1818
pub blob_gas_used: U256,
1919
pub excess_blob_gas: U256,
@@ -22,24 +22,24 @@ pub struct Block {
2222
#[derive(Serialize, Deserialize, Debug)]
2323
#[serde(rename_all = "camelCase")]
2424
pub struct Transaction {
25-
pub hash: H256,
25+
pub hash: B256,
2626
pub from: Address,
2727
#[serde(default, skip_serializing_if = "Option::is_none")]
2828
pub to: Option<Address>,
29-
pub block_number: U64,
30-
pub index: U64,
29+
pub block_number: BlockNumber,
30+
pub index: TxIndex,
3131
pub gas_price: U256,
3232
pub max_fee_per_blob_gas: U256,
3333
}
3434

3535
#[derive(Serialize, Deserialize)]
3636
#[serde(rename_all = "camelCase")]
3737
pub struct Blob {
38-
pub versioned_hash: H256,
38+
pub versioned_hash: B256,
3939
pub commitment: String,
4040
pub proof: String,
4141
pub data: Bytes,
42-
pub tx_hash: H256,
42+
pub tx_hash: B256,
4343
pub index: u32,
4444
}
4545

@@ -118,106 +118,106 @@ impl From<(u32, u32)> for FailedSlotsChunk {
118118
}
119119
}
120120

121-
impl<'a> TryFrom<(&'a EthersBlock<EthersTransaction>, u32)> for Block {
121+
impl<'a> TryFrom<(&'a ExecutionBlock<ExecutionTransaction>, u32)> for Block {
122122
type Error = anyhow::Error;
123123

124124
fn try_from(
125-
(ethers_block, slot): (&'a EthersBlock<EthersTransaction>, u32),
125+
(execution_block, slot): (&'a ExecutionBlock<ExecutionTransaction>, u32),
126126
) -> Result<Self, Self::Error> {
127-
let number = ethers_block
128-
.number
129-
.with_context(|| "Missing block number field in execution block".to_string())?;
127+
let number = execution_block.header.number;
128+
let hash = execution_block.header.hash;
129+
let timestamp = execution_block.header.timestamp;
130+
let blob_gas_used = match execution_block.header.blob_gas_used {
131+
Some(blob_gas_used) => U256::from::<u64>(blob_gas_used),
132+
None => {
133+
return Err(anyhow::anyhow!(
134+
"Missing `blob_gas_used` field in execution block {hash} with number {number}",
135+
hash = hash,
136+
number = number
137+
))
138+
}
139+
};
140+
let excess_blob_gas = match execution_block.header.excess_blob_gas {
141+
Some(excess_blob_gas) => U256::from::<u64>(excess_blob_gas),
142+
None => {
143+
return Err(anyhow::anyhow!(
144+
"Missing `excess_blob_gas` field in execution block {hash} with number {number}",
145+
hash = hash,
146+
number = number
147+
))
148+
}
149+
};
130150

131151
Ok(Self {
132152
number,
133-
hash: ethers_block
134-
.hash
135-
.with_context(|| format!("Missing block hash field in execution block {number}"))?,
136-
timestamp: ethers_block.timestamp,
153+
hash,
154+
timestamp,
137155
slot,
138-
blob_gas_used: match ethers_block.other.get("blobGasUsed") {
139-
Some(blob_gas_used) => {
140-
let blob_gas_used = blob_gas_used.as_str().with_context(|| {
141-
format!("Failed to convert `blobGasUsed` field in execution block {number}")
142-
})?;
143-
144-
U256::from_str_radix(blob_gas_used, 16)?
145-
}
146-
None => {
147-
return Err(anyhow::anyhow!(
148-
"Missing `blobGasUsed` field in execution block {number}"
149-
))
150-
}
151-
},
152-
excess_blob_gas: match ethers_block.other.get("excessBlobGas") {
153-
Some(excess_gas_gas) => {
154-
let excess_blob_gas = excess_gas_gas.as_str().with_context(|| {
155-
format!(
156-
"Failed to convert excess blob gas field in execution block {number}"
157-
)
158-
})?;
159-
160-
U256::from_str_radix(excess_blob_gas, 16)?
161-
}
162-
None => {
163-
return Err(anyhow::anyhow!(
164-
"Missing `excessBlobGas` field in execution block {number}"
165-
))
166-
}
167-
},
156+
blob_gas_used,
157+
excess_blob_gas,
168158
})
169159
}
170160
}
171161

172-
impl<'a> TryFrom<(&'a EthersTransaction, &'a EthersBlock<EthersTransaction>)> for Transaction {
162+
impl<'a>
163+
TryFrom<(
164+
&'a ExecutionTransaction,
165+
&'a ExecutionBlock<ExecutionTransaction>,
166+
)> for Transaction
167+
{
173168
type Error = anyhow::Error;
174169

175170
fn try_from(
176-
(ethers_tx, ethers_block): (&'a EthersTransaction, &'a EthersBlock<EthersTransaction>),
171+
(execution_tx, execution_block): (
172+
&'a ExecutionTransaction,
173+
&'a ExecutionBlock<ExecutionTransaction>,
174+
),
177175
) -> Result<Self, Self::Error> {
178-
let hash = ethers_tx.hash;
176+
let hash = execution_tx.hash;
177+
let block_number = execution_block.header.number;
178+
let index = execution_tx
179+
.transaction_index
180+
.with_context(|| format!("Missing `transaction_index` field in tx {hash}"))?;
181+
let from = execution_tx.from;
182+
let to = execution_tx.to;
183+
let gas_price = match execution_tx.gas_price {
184+
Some(gas_price) => U256::from::<u128>(gas_price),
185+
None => {
186+
return Err(anyhow::anyhow!(
187+
"Missing `gas_price` field in tx {hash} in block {block_number}",
188+
hash = hash,
189+
block_number = block_number
190+
))
191+
}
192+
};
193+
let max_fee_per_blob_gas = match execution_tx.max_fee_per_blob_gas {
194+
Some(max_fee_per_blob_gas) => U256::from::<u128>(max_fee_per_blob_gas),
195+
None => {
196+
return Err(anyhow::anyhow!(
197+
"Missing `max_fee_per_blob_gas` field in tx {hash} in block {block_number}",
198+
hash = hash,
199+
block_number = block_number
200+
))
201+
}
202+
};
179203

180204
Ok(Self {
181-
block_number: ethers_block
182-
.number
183-
.with_context(|| "Missing block number field in execution block".to_string())?,
184-
index: ethers_tx
185-
.transaction_index
186-
.with_context(|| "Missing transaction index field".to_string())?,
205+
block_number,
206+
index,
187207
hash,
188-
from: ethers_tx.from,
189-
to: ethers_tx.to,
190-
gas_price: ethers_tx.gas_price.with_context(|| {
191-
format!("Missing gas price field in transaction {hash}", hash = hash)
192-
})?,
193-
max_fee_per_blob_gas: match ethers_tx.other.get("maxFeePerBlobGas") {
194-
Some(max_fee_per_blob_gas) => {
195-
let max_fee_per_blob_gas =
196-
max_fee_per_blob_gas.as_str().with_context(|| {
197-
format!(
198-
"Failed to convert `maxFeePerBlobGas` field in transaction {hash}",
199-
hash = hash
200-
)
201-
})?;
202-
203-
U256::from_str_radix(max_fee_per_blob_gas, 16)?
204-
}
205-
None => {
206-
return Err(anyhow::anyhow!(
207-
"Missing `maxFeePerBlobGas` field in transaction {hash}",
208-
hash = hash
209-
))
210-
}
211-
},
208+
from,
209+
to,
210+
gas_price,
211+
max_fee_per_blob_gas,
212212
})
213213
}
214214
}
215215

216-
impl<'a> TryFrom<(&'a BeaconBlob, u32, H256)> for Blob {
216+
impl<'a> TryFrom<(&'a BeaconBlob, u32, B256)> for Blob {
217217
type Error = anyhow::Error;
218218

219219
fn try_from(
220-
(blob_data, index, tx_hash): (&'a BeaconBlob, u32, H256),
220+
(blob_data, index, tx_hash): (&'a BeaconBlob, u32, B256),
221221
) -> Result<Self, Self::Error> {
222222
Ok(Self {
223223
tx_hash,
@@ -230,9 +230,9 @@ impl<'a> TryFrom<(&'a BeaconBlob, u32, H256)> for Blob {
230230
}
231231
}
232232

233-
impl<'a> From<(&'a BeaconBlob, &'a H256, usize, &'a H256)> for Blob {
233+
impl<'a> From<(&'a BeaconBlob, &'a B256, usize, &'a B256)> for Blob {
234234
fn from(
235-
(blob_data, versioned_hash, index, tx_hash): (&'a BeaconBlob, &'a H256, usize, &'a H256),
235+
(blob_data, versioned_hash, index, tx_hash): (&'a BeaconBlob, &'a B256, usize, &'a B256),
236236
) -> Self {
237237
Self {
238238
tx_hash: *tx_hash,

0 commit comments

Comments
 (0)