Skip to content

Commit

Permalink
feat: add BlockBodies table to storage (lambdaclass#60)
Browse files Browse the repository at this point in the history
Closes lambdaclass#29

---------

Co-authored-by: Tomás Grüner <47506558+MegaRedHand@users.noreply.github.com>
  • Loading branch information
ricomateo and MegaRedHand authored Jun 26, 2024
1 parent d8f633a commit c904c05
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ core = { path = "./crates/core" }

tracing = "0.1"
tracing-subscriber = "0.3.0"
serde = "1.0.203"
serde = {version = "1.0.203", features = ["derive"]}
serde_json = "1.0.117"
libmdbx = { version = "0.5.0", features = ["orm"] }
61 changes: 58 additions & 3 deletions crates/core/src/rlp/encode.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

use crate::U256;
use bytes::BufMut;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use tinyvec::ArrayVec;

pub trait RLPEncode {
Expand Down Expand Up @@ -188,6 +188,15 @@ impl RLPEncode for String {
}
}

impl RLPEncode for U256 {
fn encode(&self, buf: &mut dyn BufMut) {
let leading_zeros_in_bytes: usize = (self.leading_zeros() / 8) as usize;
let mut bytes: [u8; 32] = [0; 32];
self.to_big_endian(&mut bytes);
bytes[leading_zeros_in_bytes..].encode(buf)
}
}

impl<T: RLPEncode> RLPEncode for Vec<T> {
fn encode(&self, buf: &mut dyn BufMut) {
if self.is_empty() {
Expand All @@ -214,6 +223,24 @@ impl<T: RLPEncode> RLPEncode for Vec<T> {
}
}

impl<T: RLPEncode, S: RLPEncode> RLPEncode for (T, S) {
fn encode(&self, buf: &mut dyn BufMut) {
let total_len = self.0.length() + self.1.length();
if total_len < 56 {
buf.put_u8(0xc0 + total_len as u8);
} else {
let mut bytes = ArrayVec::<[u8; 8]>::new();
bytes.extend_from_slice(&total_len.to_be_bytes());
let start = bytes.iter().position(|&x| x != 0).unwrap();
let len = bytes.len() - start;
buf.put_u8(0xf7 + len as u8);
buf.put_slice(&bytes[start..]);
}
self.0.encode(buf);
self.1.encode(buf);
}
}

impl RLPEncode for Ipv4Addr {
fn encode(&self, buf: &mut dyn BufMut) {
self.octets().encode(buf)
Expand Down Expand Up @@ -289,7 +316,7 @@ impl RLPEncode for ethereum_types::Signature {
mod tests {
use std::net::IpAddr;

use ethereum_types::Address;
use ethereum_types::{Address, U256};
use hex_literal::hex;

use super::RLPEncode;
Expand Down Expand Up @@ -535,4 +562,32 @@ mod tests {
let expected = hex!("94ef2d6d194084c2de36e0dabfce45d046b37d1106");
assert_eq!(encoded, expected);
}

#[test]
fn can_encode_u256() {
let mut encoded = Vec::new();
U256::from(1).encode(&mut encoded);
assert_eq!(encoded, vec![1]);

let mut encoded = Vec::new();
U256::from(128).encode(&mut encoded);
assert_eq!(encoded, vec![0x80 + 1, 128]);

let mut encoded = Vec::new();
U256::max_value().encode(&mut encoded);
let bytes = [0xff; 32];
let mut expected: Vec<u8> = bytes.into();
expected.insert(0, 0x80 + 32);
assert_eq!(encoded, expected);
}

#[test]
fn can_encode_tuple() {
// TODO: check if works for tuples with total length greater than 55 bytes
let tuple: (u8, u8) = (0x01, 0x02);
let mut encoded = Vec::new();
tuple.encode(&mut encoded);
let expected = vec![0xc0 + 2, 0x01, 0x02];
assert_eq!(encoded, expected);
}
}
108 changes: 108 additions & 0 deletions crates/core/src/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,111 @@ impl RLPEncode for BlockHeader {
self.parent_beacon_block_root.encode(buf);
}
}

// The body of a block on the chain
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Body {
transactions: Vec<Transaction>,
ommers: Vec<BlockHeader>,
withdrawals: Vec<Withdrawal>,
}

impl RLPEncode for Body {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
self.transactions.encode(buf);
self.ommers.encode(buf);
self.withdrawals.encode(buf);
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Withdrawal {
index: u64,
validator_index: u64,
address: Address,
amount: U256,
}

impl RLPEncode for Withdrawal {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
self.index.encode(buf);
self.validator_index.encode(buf);
self.address.encode(buf);
self.amount.encode(buf);
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Transaction {
LegacyTransaction(LegacyTransaction),
EIP1559Transaction(EIP1559Transaction),
}

impl RLPEncode for Transaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
match self {
Transaction::LegacyTransaction(t) => t.encode(buf),
Transaction::EIP1559Transaction(t) => t.encode(buf),
};
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LegacyTransaction {
nonce: U256,
gas_price: u64,
gas: u64,
to: Address,
value: U256,
data: Bytes,
v: U256,
r: U256,
s: U256,
}

impl RLPEncode for LegacyTransaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
self.nonce.encode(buf);
self.gas_price.encode(buf);
self.gas.encode(buf);
self.to.encode(buf);
self.value.encode(buf);
self.data.encode(buf);
self.v.encode(buf);
self.r.encode(buf);
self.s.encode(buf);
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EIP1559Transaction {
chain_id: u64,
signer_nonce: U256,
max_priority_fee_per_gas: u64,
max_fee_per_gas: u64,
gas_limit: u64,
destination: Address,
amount: u64,
payload: Bytes,
access_list: Vec<(Address, Vec<H256>)>,
signature_y_parity: bool,
signature_r: U256,
signature_s: U256,
}

impl RLPEncode for EIP1559Transaction {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
self.chain_id.encode(buf);
self.signer_nonce.encode(buf);
self.max_priority_fee_per_gas.encode(buf);
self.max_fee_per_gas.encode(buf);
self.gas_limit.encode(buf);
self.destination.encode(buf);
self.amount.encode(buf);
self.payload.encode(buf);
self.access_list.encode(buf);
self.signature_y_parity.encode(buf);
self.signature_r.encode(buf);
self.signature_s.encode(buf);
}
}
16 changes: 16 additions & 0 deletions crates/storage/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,19 @@ impl Decodable for BlockHeaderRLP {
Ok(BlockHeaderRLP(b.to_vec()))
}
}

pub struct BlockBodyRLP(Vec<u8>);

impl Encodable for BlockBodyRLP {
type Encoded = Vec<u8>;

fn encode(self) -> Self::Encoded {
self.0
}
}

impl Decodable for BlockBodyRLP {
fn decode(b: &[u8]) -> anyhow::Result<Self> {
Ok(BlockBodyRLP(b.to_vec()))
}
}
11 changes: 8 additions & 3 deletions crates/storage/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod block;

use block::BlockHeaderRLP;
use block::{BlockBodyRLP, BlockHeaderRLP};
use core::types::BlockNumber;
use libmdbx::{
orm::{table, Database},
Expand All @@ -13,11 +13,16 @@ table!(
/// Block headers table.
( Headers ) BlockNumber => BlockHeaderRLP
);

table!(
/// Block bodies table.
( Bodies ) BlockNumber => BlockBodyRLP
);
/// Initializes a new database with the provided path. If the path is `None`, the database
/// will be temporary.
pub fn init_db(path: Option<impl AsRef<Path>>) -> Database {
let tables = [table_info!(Headers)].into_iter().collect();
let tables = [table_info!(Headers), table_info!(Bodies)]
.into_iter()
.collect();
let path = path.map(|p| p.as_ref().to_path_buf());
Database::create(path, &tables).unwrap()
}
Expand Down

0 comments on commit c904c05

Please sign in to comment.