Skip to content

Commit

Permalink
feat: add .era2 state snapshots types (#1374)
Browse files Browse the repository at this point in the history
  • Loading branch information
KolbyML authored Aug 21, 2024
1 parent da113e8 commit 7802037
Show file tree
Hide file tree
Showing 6 changed files with 438 additions and 43 deletions.
6 changes: 6 additions & 0 deletions e2store/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ era is a format for storing beacon chain data more information can be found here

era1 is a format for storing all of Ethereum's pre merge blocks. It contains block headers, block bodies, and receipts for pre-merge block history which ranges block 0-15537394

## What is era2?

era2 is a format made to store full flat state snapshots, one of our first uses of this will be using to bootstrap Portal State Network bridges. Unlike `.era`/`.era1` era2 files will only store 1 block's worth of state per file. The reason for this choice is a snapshot of the state is quite large.

TODO: Add chart of snapshot size at every million block interval.

## What is the difference between `e2store/memory.rs` and `e2store/stream.rs`

`e2store/memory.rs` provides an api to load a full e2store file such as `.era`/`.era1` and manipulate it in memory. For smaller e2store files this approach works well. The issue comes when dealing with e2store files of much greater size loading the whole file into memory at once often isn't possible. This is where `e2store/stream.rs` comes in where you can stream the data you need from a e2store file as you need it. This will be required in `.era2` a format for storing full flat state snapshots.
49 changes: 7 additions & 42 deletions e2store/src/era1.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use crate::e2store::{
memory::E2StoreMemory,
types::{Entry, VersionEntry},
use crate::{
e2store::{
memory::E2StoreMemory,
types::{Entry, VersionEntry},
},
types::HeaderEntry,
};
use alloy_primitives::{B256, U256};
use alloy_rlp::Decodable;
use anyhow::ensure;
use ethportal_api::types::execution::{block_body::BlockBody, header::Header, receipts::Receipts};
use ethportal_api::types::execution::{block_body::BlockBody, receipts::Receipts};
use std::{
fs,
io::{Read, Write},
Expand Down Expand Up @@ -169,44 +172,6 @@ impl TryInto<[Entry; 4]> for BlockTuple {
}
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct HeaderEntry {
pub header: Header,
}

impl TryFrom<&Entry> for HeaderEntry {
type Error = anyhow::Error;

fn try_from(entry: &Entry) -> Result<Self, Self::Error> {
ensure!(
entry.header.type_ == 0x03,
"invalid header entry: incorrect header type"
);
ensure!(
entry.header.reserved == 0,
"invalid header entry: incorrect header reserved bytes"
);
let mut decoder = snap::read::FrameDecoder::new(&entry.value[..]);
let mut buf: Vec<u8> = vec![];
decoder.read_to_end(&mut buf)?;
let header = Decodable::decode(&mut buf.as_slice())?;
Ok(Self { header })
}
}

impl TryInto<Entry> for HeaderEntry {
type Error = anyhow::Error;

fn try_into(self) -> Result<Entry, Self::Error> {
let rlp_encoded = alloy_rlp::encode(self.header);
let buf: Vec<u8> = vec![];
let mut encoder = snap::write::FrameEncoder::new(buf);
let _ = encoder.write(&rlp_encoded)?;
let encoded = encoder.into_inner()?;
Ok(Entry::new(0x03, encoded))
}
}

#[derive(Clone, Eq, PartialEq, Debug)]
pub struct BodyEntry {
pub body: BlockBody,
Expand Down
Loading

0 comments on commit 7802037

Please sign in to comment.