Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
fix: ttd deserialize
Browse files Browse the repository at this point in the history
  • Loading branch information
mattsse committed Nov 4, 2023
1 parent 747bbe8 commit f80c610
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 25 deletions.
30 changes: 26 additions & 4 deletions ethers-core/src/utils/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,7 @@ pub struct ChainConfig {
pub cancun_time: Option<u64>,

/// Total difficulty reached that triggers the merge consensus upgrade.
#[serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_stringified_numeric_opt"
)]
#[serde(skip_serializing_if = "Option::is_none", deserialize_with = "deserialize_ttd")]
pub terminal_total_difficulty: Option<U256>,

/// A flag specifying that the network already passed the terminal total difficulty. Its
Expand Down Expand Up @@ -350,6 +347,31 @@ pub struct CliqueConfig {
pub epoch: Option<u64>,
}

fn deserialize_ttd<'de, D>(deserializer: D) -> Result<Option<U256>, D::Error>
where
D: serde::Deserializer<'de>,
{
match Option::<serde_json::Value>::deserialize(deserializer)? {
None => Ok(None),
Some(val) => {
if let serde_json::Value::Number(num) = val {
// mainnet ttd is serialized as number, which serde is unable to deserialize as
// integer
if num.as_f64() == Some(5.875e22) {
Ok(Some(U256::from(58750000000000000000000u128)))
} else {
num.as_u64()
.map(U256::from)
.ok_or_else(|| serde::de::Error::custom("expected a number"))
.map(Some)
}
} else {
Err(serde::de::Error::custom("expected a number"))
}
}
}
}

#[cfg(test)]
mod tests {
use super::{ChainConfig, Genesis, GenesisAccount, H256};
Expand Down
22 changes: 1 addition & 21 deletions ethers-providers/src/rpc/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,27 +767,7 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
}

async fn node_info(&self) -> Result<NodeInfo, Self::Error> {
let mut raw: String = self.request("admin_nodeInfo", ()).await?;
// The ethereum mainnet TTD is 58750000000000000000000, and geth serializes this
// without quotes, because that is how golang `big.Int`s marshal in JSON. Numbers
// are arbitrary precision in JSON, so this is valid JSON. This number is also
// greater than a `u64`.
//
// Unfortunately, serde_json only supports parsing up to `u64`, resorting to `f64`
// once `u64` overflows:
// <https://github.com/serde-rs/json/blob/4bc1eaa03a6160593575bc9bc60c94dba4cab1e3/src/de.rs#L1411-L1415>
// <https://github.com/serde-rs/json/blob/4bc1eaa03a6160593575bc9bc60c94dba4cab1e3/src/de.rs#L479-L484>
// <https://github.com/serde-rs/json/blob/4bc1eaa03a6160593575bc9bc60c94dba4cab1e3/src/de.rs#L102-L108>
//
// serde_json does have an arbitrary precision feature, but this breaks untagged
// enums in serde:
// <https://github.com/serde-rs/serde/issues/2230>
// <https://github.com/serde-rs/serde/issues/1183>
//
// To solve this, we surround the mainnet TTD with quotes, which our custom Visitor
// accepts.
raw = raw.replacen(":58750000000000000000000", ":\\\"58750000000000000000000\\\"", 1);
serde_json::from_str(&raw).map_err(Into::into)
self.request("admin_nodeInfo", ()).await
}

async fn peers(&self) -> Result<Vec<PeerInfo>, Self::Error> {
Expand Down

0 comments on commit f80c610

Please sign in to comment.