Implement Compact codec for alloy_primitives::Log (#7474)

This commit is contained in:
jn
2024-04-08 11:34:14 -07:00
committed by GitHub
parent 33d335837a
commit 91a1503079
8 changed files with 2521 additions and 1 deletions

1
Cargo.lock generated
View File

@ -6237,6 +6237,7 @@ dependencies = [
"proptest-derive", "proptest-derive",
"reth-codecs-derive", "reth-codecs-derive",
"serde", "serde",
"serde_json",
"test-fuzz", "test-fuzz",
] ]

View File

@ -30,7 +30,7 @@ alloy-eips.workspace = true
enr = { workspace = true, features = ["rust-secp256k1"] } enr = { workspace = true, features = ["rust-secp256k1"] }
# crypto # crypto
secp256k1 = { workspace = true, features = ["global-context", "recovery"] } secp256k1 = { workspace = true, features = ["global-context", "recovery", "rand"] }
# for eip-4844 # for eip-4844
c-kzg = { workspace = true, features = ["serde"], optional = true } c-kzg = { workspace = true, features = ["serde"], optional = true }

View File

@ -51,3 +51,27 @@ where
} }
bloom bloom
} }
#[cfg(test)]
mod tests {
use super::*;
use proptest::proptest;
proptest! {
#[test]
fn test_roundtrip_conversion_between_log_and_alloy_log(log: Log) {
// Convert log to buffer and then create alloy_log from buffer and compare
let mut compacted_log = Vec::<u8>::new();
let len = log.clone().to_compact(&mut compacted_log);
let alloy_log = AlloyLog::from_compact(&compacted_log, len).0;
assert_eq!(log, alloy_log.into());
// Create alloy_log from log and then convert it to buffer and compare compacted_alloy_log and compacted_log
let alloy_log = AlloyLog::new_unchecked(log.address, log.topics, log.data);
let mut compacted_alloy_log = Vec::<u8>::new();
let _len = alloy_log.to_compact(&mut compacted_alloy_log);
assert_eq!(compacted_log, compacted_alloy_log);
}
}
}

View File

@ -21,6 +21,7 @@ alloy-primitives = { workspace = true, features = ["arbitrary", "serde"] }
serde.workspace = true serde.workspace = true
modular-bitfield = "0.11.2" modular-bitfield = "0.11.2"
test-fuzz.workspace = true test-fuzz.workspace = true
serde_json.workspace = true
arbitrary = { workspace = true, features = ["derive"] } arbitrary = { workspace = true, features = ["derive"] }
proptest.workspace = true proptest.workspace = true

View File

@ -0,0 +1,94 @@
use crate::Compact;
use alloy_primitives::{Address, Bytes, Log, LogData};
use bytes::BufMut;
/// Implement `Compact` for `LogData` and `Log`.
impl Compact for LogData {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: BufMut + AsMut<[u8]>,
{
let mut buffer = bytes::BytesMut::new();
let (topics, data) = self.split();
topics.specialized_to_compact(&mut buffer);
data.to_compact(&mut buffer);
let total_length = buffer.len();
buf.put(buffer);
total_length
}
fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
let (topics, new_buf) = Vec::specialized_from_compact(buf, buf.len());
buf = new_buf;
let (data, buf) = Bytes::from_compact(buf, buf.len());
let log_data = LogData::new_unchecked(topics, data);
(log_data, buf)
}
}
impl Compact for Log {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: BufMut + AsMut<[u8]>,
{
let mut buffer = bytes::BytesMut::new();
self.address.to_compact(&mut buffer);
self.data.to_compact(&mut buffer);
let total_length = buffer.len();
buf.put(buffer);
total_length
}
fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
let (address, new_buf) = Address::from_compact(buf, buf.len());
buf = new_buf;
let (log_data, new_buf) = LogData::from_compact(buf, buf.len());
buf = new_buf;
let log = Log { address, data: log_data };
(log, buf)
}
}
#[cfg(test)]
mod tests {
use super::{Compact, Log};
use alloy_primitives::{Address, Bytes, LogData, B256};
use proptest::proptest;
use serde::Deserialize;
proptest! {
#[test]
fn roundtrip(log: Log) {
let mut buf = Vec::<u8>::new();
let len = log.clone().to_compact(&mut buf);
let (decoded, _) = Log::from_compact(&buf, len);
assert_eq!(log, decoded);
}
}
#[derive(Deserialize)]
struct CompactLogTestVector {
topics: Vec<B256>,
address: Address,
data: Bytes,
encoded_bytes: Bytes,
}
#[test]
fn test_compact_log_codec() {
let test_vectors: Vec<CompactLogTestVector> =
serde_json::from_str(include_str!("../../testdata/log_compact.json")).unwrap();
for test_vector in test_vectors {
let log_data = LogData::new_unchecked(test_vector.topics, test_vector.data);
let log = Log { address: test_vector.address, data: log_data };
let mut buf = Vec::<u8>::new();
let len = log.clone().to_compact(&mut buf);
assert_eq!(test_vector.encoded_bytes, buf);
let (decoded, _) = Log::from_compact(&test_vector.encoded_bytes, len);
assert_eq!(log, decoded);
}
}
}

View File

@ -0,0 +1 @@
mod log;

View File

@ -16,6 +16,8 @@ pub use reth_codecs_derive::*;
use alloy_primitives::{Address, Bloom, Bytes, B256, B512, U256}; use alloy_primitives::{Address, Bloom, Bytes, B256, B512, U256};
use bytes::Buf; use bytes::Buf;
mod alloy;
/// Trait that implements the `Compact` codec. /// Trait that implements the `Compact` codec.
/// ///
/// When deriving the trait for custom structs, be aware of certain limitations/recommendations: /// When deriving the trait for custom structs, be aware of certain limitations/recommendations:

File diff suppressed because it is too large Load Diff