Skip to content

Commit 2b5b55b

Browse files
committed
fix: always deserialize Block::totalDifficulty to None (#312)
As explained in #311, the field `totalDifficulty` was removed from the official Ethereum JSON RPC Block schema in ethereum/execution-apis#570, leading to inconsistent answers between providers when calling the EVM RPC canister with `eth_getBlockByNumber`. This seems to affect all blocks and not only post-merge blocks. As a workaround, the EVM RPC canister no longer deserializes the field `totalDifficulty` in the provider's JSON response and set the Candid returned value for `evm_rpc_types::Block::totalDifficulty` always to `None` to be backwards-compatible.
1 parent 502c086 commit 2b5b55b

File tree

6 files changed

+35
-16
lines changed

6 files changed

+35
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
### Fixed
1515

1616
* fix: ensure Candid API is the same as the interface exposed by the canister
17+
* fix: always deserialize `Block::totalDifficulty` to `None` to avoid inconsistencies between providers
1718

1819
## [2.1.0] - 2024-10-14
1920

src/candid_rpc/cketh_conversion.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,10 @@ pub(super) fn from_block(value: crate::rpc_client::json::responses::Block) -> ev
157157
size: value.size.into(),
158158
state_root: Hex32::from(value.state_root.into_bytes()),
159159
timestamp: value.timestamp.into(),
160-
total_difficulty: value.total_difficulty.map(Nat256::from),
160+
// The field totalDifficulty was removed from the official Ethereum JSON RPC Block schema in
161+
// https://github.com/ethereum/execution-apis/pull/570 and as a consequence is inconsistent between different providers.
162+
// See https://github.com/internet-computer-protocol/evm-rpc-canister/issues/311.
163+
total_difficulty: None,
161164
transactions: value
162165
.transactions
163166
.into_iter()

src/rpc_client/json/responses.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -236,13 +236,6 @@ pub struct Block {
236236
#[serde(rename = "timestamp")]
237237
pub timestamp: Timestamp,
238238

239-
/// Total difficulty is the sum of all difficulty values up to and including this block.
240-
///
241-
/// Note: this field was removed from the official JSON-RPC specification in
242-
/// https://github.com/ethereum/execution-apis/pull/570 and may no longer be served by providers.
243-
#[serde(rename = "totalDifficulty")]
244-
pub total_difficulty: Option<Difficulty>,
245-
246239
/// List of transactions in the block.
247240
/// Note that since `eth_get_block_by_number` sets `include_full_transactions` to false,
248241
/// this field only contains the transaction hashes and not the full transactions.

src/rpc_client/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ use evm_rpc_types::{
77
};
88
use ic_canister_log::log;
99
use json::requests::{
10-
BlockSpec, FeeHistoryParams, GetBlockByNumberParams, GetLogsParam, GetTransactionCountParams,
10+
BlockSpec, EthCallParams, FeeHistoryParams, GetBlockByNumberParams, GetLogsParam,
11+
GetTransactionCountParams,
12+
};
13+
use json::responses::{
14+
Block, Data, FeeHistory, LogEntry, SendRawTransactionResult, TransactionReceipt,
1115
};
12-
use json::responses::{Block, FeeHistory, LogEntry, SendRawTransactionResult, TransactionReceipt};
1316
use json::Hash;
1417
use serde::{de::DeserializeOwned, Serialize};
1518
use std::collections::{BTreeMap, BTreeSet};
1619
use std::fmt::Debug;
17-
use crate::rpc_client::json::requests::EthCallParams;
18-
use crate::rpc_client::json::responses::Data;
1920

2021
pub mod amount;
2122
pub(crate) mod eth_rpc;
@@ -401,7 +402,7 @@ impl EthRpcClient {
401402
.await
402403
.reduce(self.consensus_strategy())
403404
}
404-
405+
405406
pub async fn eth_call(&self, params: EthCallParams) -> Result<Data, MultiCallError<Data>> {
406407
self.parallel_call(
407408
"eth_call",

src/rpc_client/numeric/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,4 @@ pub enum TimestampTag {}
4949
pub type Timestamp = Amount<TimestampTag>;
5050

5151
pub enum ChainIdTag {}
52-
pub type ChainId = Amount<ChainIdTag>;
52+
pub type ChainId = Amount<ChainIdTag>;

tests/tests.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ fn eth_get_block_by_number_should_succeed() {
691691
size: 0xcd35_u32.into(),
692692
state_root: "0x13552447dd62f11ad885f21a583c4fa34144efe923c7e35fb018d6710f06b2b6".parse().unwrap(),
693693
timestamp: 0x656f96f3_u32.into(),
694-
total_difficulty: Some(0xc70d815d562d3cfa955_u128.into()),
694+
total_difficulty: None,
695695
transactions: vec![],
696696
transactions_root: None,
697697
uncles: vec![],
@@ -734,7 +734,7 @@ fn eth_get_block_by_number_pre_london_fork_should_succeed() {
734734
size: 0x21c_u32.into(),
735735
state_root: "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".parse().unwrap(),
736736
timestamp: Nat256::ZERO,
737-
total_difficulty: Some(0x400000000_u64.into()),
737+
total_difficulty: None,
738738
transactions: vec![],
739739
transactions_root: Some("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421".parse().unwrap()),
740740
uncles: vec![],
@@ -743,6 +743,27 @@ fn eth_get_block_by_number_pre_london_fork_should_succeed() {
743743
}
744744
}
745745

746+
#[test]
747+
fn eth_get_block_by_number_should_be_consistent_when_total_difficulty_inconsistent() {
748+
let setup = EvmRpcSetup::new().mock_api_keys();
749+
let response = setup.eth_get_block_by_number(
750+
RpcServices::EthMainnet(Some(vec![
751+
EthMainnetService::Ankr,
752+
EthMainnetService::PublicNode,
753+
])),
754+
None,
755+
evm_rpc_types::BlockTag::Latest,
756+
)
757+
.mock_http_once(MockOutcallBuilder::new(200, r#"{"jsonrpc":"2.0","result":{"baseFeePerGas":"0xd7232aa34","difficulty":"0x0","extraData":"0x546974616e2028746974616e6275696c6465722e78797a29","gasLimit":"0x1c9c380","gasUsed":"0xa768c4","hash":"0xc3674be7b9d95580d7f23c03d32e946f2b453679ee6505e3a778f003c5a3cfae","logsBloom":"0x3e6b8420e1a13038902c24d6c2a9720a7ad4860cdc870cd5c0490011e43631134f608935bd83171247407da2c15d85014f9984608c03684c74aad48b20bc24022134cdca5f2e9d2dee3b502a8ccd39eff8040b1d96601c460e119c408c620b44fa14053013220847045556ea70484e67ec012c322830cf56ef75e09bd0db28a00f238adfa587c9f80d7e30d3aba2863e63a5cad78954555966b1055a4936643366a0bb0b1bac68d0e6267fc5bf8304d404b0c69041125219aa70562e6a5a6362331a414a96d0716990a10161b87dd9568046a742d4280014975e232b6001a0360970e569d54404b27807d7a44c949ac507879d9d41ec8842122da6772101bc8b","miner":"0x388c818ca8b9251b393131c08a736a67ccb19297","mixHash":"0x516a58424d4883a3614da00a9c6f18cd5cd54335a08388229a993a8ecf05042f","nonce":"0x0000000000000000","number":"0x11db01d","parentHash":"0x43325027f6adf9befb223f8ae80db057daddcd7b48e41f60cd94bfa8877181ae","receiptsRoot":"0x66934c3fd9c547036fe0e56ad01bc43c84b170be7c4030a86805ddcdab149929","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0xcd35","stateRoot":"0x13552447dd62f11ad885f21a583c4fa34144efe923c7e35fb018d6710f06b2b6","timestamp":"0x656f96f3","totalDifficulty":"0xc70d815d562d3cfa955","withdrawalsRoot":"0xecae44b2c53871003c5cc75285995764034c9b5978a904229d36c1280b141d48"},"id":0}"#))
758+
.mock_http_once(MockOutcallBuilder::new(200, r#"{"jsonrpc":"2.0","result":{"baseFeePerGas":"0xd7232aa34","difficulty":"0x0","extraData":"0x546974616e2028746974616e6275696c6465722e78797a29","gasLimit":"0x1c9c380","gasUsed":"0xa768c4","hash":"0xc3674be7b9d95580d7f23c03d32e946f2b453679ee6505e3a778f003c5a3cfae","logsBloom":"0x3e6b8420e1a13038902c24d6c2a9720a7ad4860cdc870cd5c0490011e43631134f608935bd83171247407da2c15d85014f9984608c03684c74aad48b20bc24022134cdca5f2e9d2dee3b502a8ccd39eff8040b1d96601c460e119c408c620b44fa14053013220847045556ea70484e67ec012c322830cf56ef75e09bd0db28a00f238adfa587c9f80d7e30d3aba2863e63a5cad78954555966b1055a4936643366a0bb0b1bac68d0e6267fc5bf8304d404b0c69041125219aa70562e6a5a6362331a414a96d0716990a10161b87dd9568046a742d4280014975e232b6001a0360970e569d54404b27807d7a44c949ac507879d9d41ec8842122da6772101bc8b","miner":"0x388c818ca8b9251b393131c08a736a67ccb19297","mixHash":"0x516a58424d4883a3614da00a9c6f18cd5cd54335a08388229a993a8ecf05042f","nonce":"0x0000000000000000","number":"0x11db01d","parentHash":"0x43325027f6adf9befb223f8ae80db057daddcd7b48e41f60cd94bfa8877181ae","receiptsRoot":"0x66934c3fd9c547036fe0e56ad01bc43c84b170be7c4030a86805ddcdab149929","sha3Uncles":"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347","size":"0xcd35","stateRoot":"0x13552447dd62f11ad885f21a583c4fa34144efe923c7e35fb018d6710f06b2b6","timestamp":"0x656f96f3","withdrawalsRoot":"0xecae44b2c53871003c5cc75285995764034c9b5978a904229d36c1280b141d48"},"id":0}"#))
759+
.wait()
760+
.expect_consistent()
761+
.unwrap();
762+
763+
assert_eq!(response.number, 18_722_845_u32.into());
764+
assert_eq!(response.total_difficulty, None);
765+
}
766+
746767
#[test]
747768
fn eth_get_transaction_receipt_should_succeed() {
748769
let test_cases = [

0 commit comments

Comments
 (0)