Skip to content

Commit f9d8d60

Browse files
committed
feat: add missing RPC methods (#15)
1 parent ada007f commit f9d8d60

17 files changed

Lines changed: 637 additions & 97 deletions

File tree

.github/CODEOWNERS

Lines changed: 45 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,45 @@
1-
* @gakonst
2-
crates/chain-state/ @fgimenez @mattsse
3-
crates/chainspec/ @Rjected @joshieDo @mattsse
4-
crates/cli/ @mattsse @Rjected
5-
crates/config/ @shekhirin @mattsse @Rjected
6-
crates/consensus/ @mattsse @Rjected
7-
crates/e2e-test-utils/ @mattsse @Rjected @klkvr @fgimenez
8-
crates/engine/ @mattsse @Rjected @mediocregopher @yongkangc
9-
crates/era/ @mattsse
10-
crates/era-downloader/ @mattsse
11-
crates/era-utils/ @mattsse
12-
crates/errors/ @mattsse
13-
crates/ethereum/ @mattsse @Rjected
14-
crates/etl/ @joshieDo @shekhirin
15-
crates/evm/ @mattsse @Rjected @klkvr
16-
crates/exex/ @shekhirin
17-
crates/fs-util/ @mattsse
18-
crates/metrics/ @mattsse @Rjected
19-
crates/net/ @mattsse @Rjected
20-
crates/net/downloaders/ @Rjected
21-
crates/node/ @mattsse @Rjected @klkvr
22-
crates/payload/ @mattsse @Rjected
23-
crates/primitives-traits/ @Rjected @mattsse @klkvr
24-
crates/primitives/ @Rjected @mattsse @klkvr
25-
crates/prune/ @shekhirin @joshieDo
26-
crates/ress/ @shekhirin @Rjected
27-
crates/revm/ @mattsse
28-
crates/rpc/ @mattsse @Rjected
29-
crates/stages/ @shekhirin @mediocregopher
30-
crates/static-file/ @joshieDo @shekhirin
31-
crates/stateless/ @mattsse
32-
crates/storage/codecs/ @joshieDo
33-
crates/storage/db-api/ @joshieDo
34-
crates/storage/db-common/ @Rjected
35-
crates/storage/db/ @joshieDo
36-
crates/storage/errors/ @joshieDo
37-
crates/storage/libmdbx-rs/ @shekhirin
38-
crates/storage/nippy-jar/ @joshieDo @shekhirin
39-
crates/storage/provider/ @joshieDo @shekhirin @yongkangc
40-
crates/storage/storage-api/ @joshieDo
41-
crates/tasks/ @mattsse @DaniPopes
42-
crates/tokio-util/ @mattsse
43-
crates/tracing/ @mattsse @shekhirin
44-
crates/tracing-otlp/ @mattsse @Rjected
45-
crates/transaction-pool/ @mattsse @yongkangc
46-
crates/trie/ @Rjected @shekhirin @mediocregopher @yongkangc
47-
bin/reth/ @mattsse @shekhirin @Rjected
48-
bin/reth-bench/ @mattsse @Rjected @shekhirin @yongkangc
49-
bin/reth-bench-compare/ @mediocregopher @shekhirin @yongkangc
50-
etc/ @Rjected @shekhirin
51-
.github/ @gakonst @DaniPopes
1+
* @joey0612
2+
crates/blockchain-tree-api/ @graceharuki @joey0612
3+
crates/blockchain-tree/ @graceharuki @joey0612
4+
crates/chain-state/ @graceharuki @joey0612
5+
crates/chainspec/ @graceharuki @joey0612
6+
crates/cli/ @graceharuki @joey0612
7+
crates/consensus/ @graceharuki @joey0612
8+
crates/e2e-test-utils/ @graceharuki @joey0612
9+
crates/engine @graceharuki @joey0612
10+
crates/engine/ @graceharuki @joey0612
11+
crates/era/ @graceharuki @joey0612
12+
crates/errors/ @graceharuki @joey0612
13+
crates/ethereum-forks/ @graceharuki @joey0612
14+
crates/ethereum/ @graceharuki @joey0612
15+
crates/etl/ @graceharuki @joey0612
16+
crates/evm/ @graceharuki @joey0612
17+
crates/exex/ @graceharuki @joey0612
18+
crates/net/ @graceharuki @joey0612
19+
crates/net/downloaders/ @graceharuki @joey0612
20+
crates/node/ @graceharuki @joey0612
21+
crates/optimism/ @graceharuki @joey0612
22+
crates/payload/ @graceharuki @joey0612
23+
crates/primitives-traits/ @graceharuki @joey0612
24+
crates/primitives/ @graceharuki @joey0612
25+
crates/prune/ @graceharuki @joey0612
26+
crates/ress @graceharuki @joey0612
27+
crates/revm/ @graceharuki @joey0612
28+
crates/rpc/ @graceharuki @joey0612
29+
crates/stages/ @graceharuki @joey0612
30+
crates/static-file/ @graceharuki @joey0612
31+
crates/storage/codecs/ @graceharuki @joey0612
32+
crates/storage/db-api/ @graceharuki @joey0612
33+
crates/storage/db-common/ @graceharuki @joey0612
34+
crates/storage/db/ @graceharuki @joey0612
35+
crates/storage/errors/ @graceharuki @joey0612
36+
crates/storage/libmdbx-rs/ @graceharuki @joey0612
37+
crates/storage/nippy-jar/ @graceharuki @joey0612
38+
crates/storage/provider/ @graceharuki @joey0612
39+
crates/storage/storage-api/ @graceharuki @joey0612
40+
crates/tasks/ @graceharuki @joey0612
41+
crates/tokio-util/ @graceharuki @joey0612
42+
crates/transaction-pool/ @graceharuki @joey0612
43+
crates/trie/ @graceharuki @joey0612
44+
etc/ @graceharuki @joey0612
45+
.github/ @joey0612

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ This project based on the excellent community versions as foundation, We extend
157157
- [@loocapro](https://github.com/loocapro)
158158
- All contributors on reth for reth-bsc
159159

160+
## Acknowledgements from BNBChain team
161+
162+
This project based on the excellent community versions as foundation, We extend our sincere appreciation to the teams below:
163+
- [Reth](https://github.com/paradigmxyz/reth) - The reth project
164+
- [Reth-bsc](https://github.com/loocapro/reth-bsc) - The BSC Reth implementation from community
165+
- Especially thanks to:
166+
- [@mattsse](https://github.com/mattsse)
167+
- [@klkvr](https://github.com/klkvr)
168+
- [@loocapro](https://github.com/loocapro)
169+
- All contributors on reth for reth-bsc
160170

161171
## Warning
162172

crates/ethereum/node/tests/e2e/dev.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ async fn can_run_dev_node_custom_attributes() -> eyre::Result<()> {
6868
.unwrap()
6969
.unwrap()
7070
.header
71+
.inner
7172
.beneficiary ==
7273
fee_recipient
7374
);

crates/rpc/rpc-convert/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ thiserror.workspace = true
3434
auto_impl.workspace = true
3535
dyn-clone.workspace = true
3636

37+
# serialization
38+
serde = { workspace = true, features = ["derive"] }
39+
3740
[dev-dependencies]
3841
serde_json.workspace = true
3942

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
//! Custom RPC header types with additional fields
2+
3+
use alloy_network::primitives::HeaderResponse;
4+
use alloy_primitives::{BlockHash, U256};
5+
6+
/// Custom RPC header that extends the standard header with additional fields
7+
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
8+
#[serde(rename_all = "camelCase")]
9+
pub struct CustomRpcHeader<H = alloy_consensus::Header> {
10+
/// Hash of the block
11+
pub hash: BlockHash,
12+
/// Inner consensus header.
13+
#[serde(flatten)]
14+
pub inner: H,
15+
/// Total difficulty
16+
///
17+
/// Note: This field is now effectively deprecated: <https://github.com/ethereum/execution-apis/pull/570>
18+
#[serde(default, skip_serializing_if = "Option::is_none")]
19+
pub total_difficulty: Option<U256>,
20+
/// Integer the size of this block in bytes.
21+
#[serde(default, skip_serializing_if = "Option::is_none")]
22+
pub size: Option<U256>,
23+
/// Millisecond timestamp - custom field for BNB Chain
24+
#[serde(default, skip_serializing_if = "Option::is_none")]
25+
pub milli_timestamp: Option<U256>,
26+
}
27+
28+
impl<H> CustomRpcHeader<H> {
29+
/// Create a new custom header from consensus header components
30+
pub const fn new(
31+
hash: BlockHash,
32+
inner: H,
33+
total_difficulty: Option<U256>,
34+
size: Option<U256>,
35+
milli_timestamp: Option<U256>,
36+
) -> Self {
37+
Self { hash, inner, total_difficulty, size, milli_timestamp }
38+
}
39+
40+
/// Create a custom header from a consensus header
41+
pub fn from_consensus(
42+
header: alloy_consensus::Header,
43+
total_difficulty: Option<U256>,
44+
size: Option<U256>,
45+
) -> CustomRpcHeader<alloy_consensus::Header> {
46+
let hash = header.hash_slow();
47+
let milli_timestamp = Some(U256::from(calculate_millisecond_timestamp(&header)));
48+
49+
CustomRpcHeader { hash, inner: header, total_difficulty, size, milli_timestamp }
50+
}
51+
52+
/// Create a custom header from any block header
53+
pub fn from_header<T: reth_primitives_traits::BlockHeader>(
54+
header: T,
55+
hash: BlockHash,
56+
total_difficulty: Option<U256>,
57+
size: Option<U256>,
58+
) -> CustomRpcHeader<T> {
59+
let milli_timestamp = Some(U256::from(calculate_millisecond_timestamp(&header)));
60+
61+
CustomRpcHeader { hash, inner: header, total_difficulty, size, milli_timestamp }
62+
}
63+
}
64+
65+
impl<H> HeaderResponse for CustomRpcHeader<H>
66+
where
67+
H: alloy_consensus::BlockHeader,
68+
{
69+
fn hash(&self) -> BlockHash {
70+
self.hash
71+
}
72+
}
73+
74+
impl<H> alloy_consensus::BlockHeader for CustomRpcHeader<H>
75+
where
76+
H: alloy_consensus::BlockHeader,
77+
{
78+
fn parent_hash(&self) -> alloy_primitives::B256 {
79+
self.inner.parent_hash()
80+
}
81+
82+
fn ommers_hash(&self) -> alloy_primitives::B256 {
83+
self.inner.ommers_hash()
84+
}
85+
86+
fn beneficiary(&self) -> alloy_primitives::Address {
87+
self.inner.beneficiary()
88+
}
89+
90+
fn state_root(&self) -> alloy_primitives::B256 {
91+
self.inner.state_root()
92+
}
93+
94+
fn transactions_root(&self) -> alloy_primitives::B256 {
95+
self.inner.transactions_root()
96+
}
97+
98+
fn receipts_root(&self) -> alloy_primitives::B256 {
99+
self.inner.receipts_root()
100+
}
101+
102+
fn withdrawals_root(&self) -> Option<alloy_primitives::B256> {
103+
self.inner.withdrawals_root()
104+
}
105+
106+
fn logs_bloom(&self) -> alloy_primitives::Bloom {
107+
self.inner.logs_bloom()
108+
}
109+
110+
fn difficulty(&self) -> alloy_primitives::U256 {
111+
self.inner.difficulty()
112+
}
113+
114+
fn number(&self) -> u64 {
115+
self.inner.number()
116+
}
117+
118+
fn gas_limit(&self) -> u64 {
119+
self.inner.gas_limit()
120+
}
121+
122+
fn gas_used(&self) -> u64 {
123+
self.inner.gas_used()
124+
}
125+
126+
fn timestamp(&self) -> u64 {
127+
self.inner.timestamp()
128+
}
129+
130+
fn mix_hash(&self) -> Option<alloy_primitives::B256> {
131+
self.inner.mix_hash()
132+
}
133+
134+
fn nonce(&self) -> Option<alloy_primitives::FixedBytes<8>> {
135+
self.inner.nonce()
136+
}
137+
138+
fn base_fee_per_gas(&self) -> Option<u64> {
139+
self.inner.base_fee_per_gas()
140+
}
141+
142+
fn blob_gas_used(&self) -> Option<u64> {
143+
self.inner.blob_gas_used()
144+
}
145+
146+
fn excess_blob_gas(&self) -> Option<u64> {
147+
self.inner.excess_blob_gas()
148+
}
149+
150+
fn parent_beacon_block_root(&self) -> Option<alloy_primitives::B256> {
151+
self.inner.parent_beacon_block_root()
152+
}
153+
154+
fn requests_hash(&self) -> Option<alloy_primitives::B256> {
155+
self.inner.requests_hash()
156+
}
157+
158+
fn extra_data(&self) -> &alloy_primitives::Bytes {
159+
self.inner.extra_data()
160+
}
161+
}
162+
163+
// RpcObject is automatically implemented via blanket impl for types that implement Serialize +
164+
// Deserialize
165+
166+
impl<H> reth_rpc_traits::FromConsensusHeader<H> for CustomRpcHeader<H>
167+
where
168+
H: reth_primitives_traits::BlockHeader + Clone,
169+
{
170+
fn from_consensus_header(
171+
header: reth_primitives_traits::SealedHeader<H>,
172+
block_size: usize,
173+
) -> Self {
174+
let header_hash = header.hash();
175+
let consensus_header = header.into_header();
176+
let milli_timestamp = Some(U256::from(calculate_millisecond_timestamp(&consensus_header)));
177+
178+
Self {
179+
hash: header_hash,
180+
inner: consensus_header,
181+
total_difficulty: None,
182+
size: Some(U256::from(block_size)),
183+
milli_timestamp,
184+
}
185+
}
186+
}
187+
188+
/// Type alias for the standard Ethereum custom header
189+
pub type EthereumCustomHeader = CustomRpcHeader<alloy_consensus::Header>;
190+
191+
/// Custom header converter that creates `CustomRpcHeader` instances
192+
#[derive(Debug, Clone)]
193+
pub struct CustomHeaderConverter;
194+
195+
impl<H> crate::transaction::HeaderConverter<H, CustomRpcHeader<H>> for CustomHeaderConverter
196+
where
197+
H: reth_primitives_traits::BlockHeader + Clone,
198+
{
199+
fn convert_header(
200+
&self,
201+
header: reth_primitives_traits::SealedHeader<H>,
202+
block_size: usize,
203+
td: Option<alloy_primitives::U256>,
204+
) -> CustomRpcHeader<H> {
205+
let header_hash = header.hash();
206+
let consensus_header = header.into_header();
207+
let milli_timestamp = Some(U256::from(calculate_millisecond_timestamp(&consensus_header)));
208+
209+
CustomRpcHeader {
210+
hash: header_hash,
211+
inner: consensus_header,
212+
total_difficulty: td,
213+
size: Some(alloy_primitives::U256::from(block_size)),
214+
milli_timestamp,
215+
}
216+
}
217+
}
218+
219+
/// Calculate millisecond timestamp from header `mix_hash` for any `BlockHeader` type.
220+
pub fn calculate_millisecond_timestamp<T: reth_primitives_traits::BlockHeader>(header: &T) -> u64 {
221+
let seconds = header.timestamp();
222+
let mix_hash = header.mix_hash();
223+
224+
let ms_part = if let Some(mix_hash) = mix_hash {
225+
if mix_hash.is_zero() {
226+
0
227+
} else {
228+
let bytes = mix_hash.as_slice();
229+
// Convert last 8 bytes to u64 (big-endian), equivalent to Go's
230+
// uint256.SetBytes32().Uint64()
231+
let mut result = 0u64;
232+
for &byte in bytes.iter().skip(24).take(8) {
233+
result = (result << 8) | u64::from(byte);
234+
}
235+
result
236+
}
237+
} else {
238+
0
239+
};
240+
241+
seconds * 1000 + ms_part
242+
}

crates/rpc/rpc-convert/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,13 @@
1010
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
1111
#![cfg_attr(docsrs, feature(doc_cfg))]
1212

13+
pub mod custom_header;
1314
mod rpc;
1415
pub mod transaction;
1516

17+
pub use custom_header::{
18+
calculate_millisecond_timestamp, CustomHeaderConverter, CustomRpcHeader, EthereumCustomHeader,
19+
};
1620
pub use rpc::*;
1721
pub use transaction::{RpcConvert, RpcConverter, TransactionConversionError};
1822

0 commit comments

Comments
 (0)