diff --git a/crates/storage/codecs/Cargo.toml b/crates/storage/codecs/Cargo.toml index 31f954f86..ab8f1a323 100644 --- a/crates/storage/codecs/Cargo.toml +++ b/crates/storage/codecs/Cargo.toml @@ -11,18 +11,21 @@ repository.workspace = true workspace = true [dependencies] +# reth reth-codecs-derive = { path = "./derive", default-features = false } +# eth alloy-eips = { workspace = true, optional = true } alloy-primitives.workspace = true +# misc bytes.workspace = true +modular-bitfield = { workspace = true, optional = true } +serde.workspace = true [dev-dependencies] alloy-eips = { workspace = true, default-features = false, features = ["arbitrary", "serde"] } alloy-primitives = { workspace = true, features = ["arbitrary", "serde"] } -serde.workspace = true -modular-bitfield.workspace = true test-fuzz.workspace = true serde_json.workspace = true @@ -33,5 +36,5 @@ proptest-derive.workspace = true [features] default = ["std", "alloy"] std = ["alloy-primitives/std", "bytes/std"] -alloy = ["alloy-eips"] +alloy = ["dep:alloy-eips", "dep:modular-bitfield"] optimism = ["reth-codecs-derive/optimism"] diff --git a/crates/storage/codecs/src/alloy/mod.rs b/crates/storage/codecs/src/alloy/mod.rs index 7d7a794fe..aff164642 100644 --- a/crates/storage/codecs/src/alloy/mod.rs +++ b/crates/storage/codecs/src/alloy/mod.rs @@ -1,3 +1,4 @@ mod access_list; mod log; mod txkind; +mod withdrawal; diff --git a/crates/storage/codecs/src/alloy/withdrawal.rs b/crates/storage/codecs/src/alloy/withdrawal.rs new file mode 100644 index 000000000..0849b7e4a --- /dev/null +++ b/crates/storage/codecs/src/alloy/withdrawal.rs @@ -0,0 +1,62 @@ +use crate::Compact; +use alloy_eips::eip4895::Withdrawal as AlloyWithdrawal; +use alloy_primitives::Address; +use reth_codecs_derive::main_codec; + +/// Withdrawal acts as bridge which simplifies Compact implementation for AlloyWithdrawal. +/// +/// Notice: Make sure this struct is 1:1 with `alloy_eips::eip4895::Withdrawal` +#[main_codec] +#[derive(Debug, Clone, PartialEq, Eq, Default)] +struct Withdrawal { + /// Monotonically increasing identifier issued by consensus layer. + index: u64, + /// Index of validator associated with withdrawal. + validator_index: u64, + /// Target address for withdrawn ether. + address: Address, + /// Value of the withdrawal in gwei. + amount: u64, +} + +impl Compact for AlloyWithdrawal { + fn to_compact(self, buf: &mut B) -> usize + where + B: bytes::BufMut + AsMut<[u8]>, + { + let withdrawal = Withdrawal { + index: self.index, + validator_index: self.validator_index, + address: self.address, + amount: self.amount, + }; + withdrawal.to_compact(buf) + } + + fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) { + let (withdrawal, _) = Withdrawal::from_compact(buf, len); + let alloy_withdrawal = AlloyWithdrawal { + index: withdrawal.index, + validator_index: withdrawal.validator_index, + address: withdrawal.address, + amount: withdrawal.amount, + }; + (alloy_withdrawal, buf) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use proptest::proptest; + + proptest! { + #[test] + fn roundtrip(withdrawal: AlloyWithdrawal) { + let mut compacted_withdrawal = Vec::::new(); + let len = withdrawal.to_compact(&mut compacted_withdrawal); + let (decoded, _) = AlloyWithdrawal::from_compact(&compacted_withdrawal, len); + assert_eq!(withdrawal, decoded) + } + } +}