Skip to content

Commit

Permalink
feat: fetch block numbers in store api + refactor: remove unwraps fro…
Browse files Browse the repository at this point in the history
…m libmdx impl of store (lambdaclass#150)

Based on lambdaclass#146, please merge it first

**Motivation**

Add a way to fetch blocks from their hashes (as blocks are stored by
number this translates to adding a block_hash -> block_number mapping)

<!-- Why does this pull request exist? What are its goals? -->

**Description**

* Add `get_block_number` & `add_block_number` methods to `Store` (both
using block_hash as key)
* Remove unwraps from libmdx impl of `Store` 

<!-- A clear and concise general description of the changes this PR
introduces -->

<!-- Link to issues: Resolves lambdaclass#111, Resolves lambdaclass#222 -->

Closes None, but is needed in order to implement lambdaclass#31
  • Loading branch information
fmoletta authored Jul 17, 2024
1 parent 11b5694 commit 426fe39
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 66 deletions.
1 change: 1 addition & 0 deletions crates/core/src/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use std::cmp::{max, Ordering};
use super::Transaction;

pub type BlockNumber = u64;
pub type BlockHash = H256;

use lazy_static::lazy_static;

Expand Down
16 changes: 15 additions & 1 deletion crates/storage/src/in_memory.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use super::{Key, StoreEngine, Value};
use crate::error::StoreError;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHeader, BlockNumber};
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber};
use ethereum_types::Address;
use std::{collections::HashMap, fmt::Debug};

#[derive(Default)]
pub struct Store {
account_infos: HashMap<Address, AccountInfo>,
block_numbers: HashMap<BlockHash, BlockNumber>,
bodies: HashMap<BlockNumber, BlockBody>,
headers: HashMap<BlockNumber, BlockHeader>,
values: HashMap<Key, Value>,
Expand Down Expand Up @@ -66,6 +67,19 @@ impl StoreEngine for Store {
self.bodies.insert(block_number, block_body);
Ok(())
}

fn add_block_number(
&mut self,
block_hash: BlockHash,
block_number: BlockNumber,
) -> Result<(), StoreError> {
self.block_numbers.insert(block_hash, block_number);
Ok(())
}

fn get_block_number(&self, block_hash: BlockHash) -> Result<Option<BlockNumber>, StoreError> {
Ok(self.block_numbers.get(&block_hash).copied())
}
}

impl Debug for Store {
Expand Down
67 changes: 55 additions & 12 deletions crates/storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use self::libmdbx::Store as LibmdbxStore;
use self::rocksdb::Store as RocksDbStore;
#[cfg(feature = "sled")]
use self::sled::Store as SledStore;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHeader, BlockNumber};
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber};
use ethereum_types::Address;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -67,6 +67,16 @@ pub trait StoreEngine: Debug + Send {
/// Obtain block body
fn get_block_body(&self, block_number: BlockNumber) -> Result<Option<BlockBody>, StoreError>;

/// Add block body
fn add_block_number(
&mut self,
block_hash: BlockHash,
block_number: BlockNumber,
) -> Result<(), StoreError>;

/// Obtain block number
fn get_block_number(&self, block_hash: BlockHash) -> Result<Option<BlockNumber>, StoreError>;

/// Set an arbitrary value (used for eventual persistent values: eg. current_block_height)
fn set_value(&mut self, key: Key, value: Value) -> Result<(), StoreError>;

Expand Down Expand Up @@ -179,6 +189,29 @@ impl Store {
.unwrap()
.get_block_body(block_number)
}

pub fn add_block_number(
&self,
block_hash: BlockHash,
block_number: BlockNumber,
) -> Result<(), StoreError> {
self.engine
.clone()
.lock()
.unwrap()
.add_block_number(block_hash, block_number)
}

pub fn get_block_number(
&self,
block_hash: BlockHash,
) -> Result<Option<BlockNumber>, StoreError> {
self.engine
.clone()
.lock()
.unwrap()
.get_block_number(block_hash)
}
}

#[cfg(test)]
Expand All @@ -199,8 +232,7 @@ mod tests {
#[test]
fn test_in_memory_store() {
let store = Store::new("test", EngineType::InMemory).unwrap();
test_store_account(store.clone());
test_store_block(store.clone());
test_store_suite(store);
}

#[cfg(feature = "libmdbx")]
Expand All @@ -209,9 +241,7 @@ mod tests {
// Removing preexistent DBs in case of a failed previous test
remove_test_dbs("test.mdbx");
let store = Store::new("test.mdbx", EngineType::Libmdbx).unwrap();
test_store_account(store.clone());
test_store_block(store.clone());

test_store_suite(store);
remove_test_dbs("test.mdbx");
}

Expand All @@ -221,9 +251,7 @@ mod tests {
// Removing preexistent DBs in case of a failed previous test
remove_test_dbs("test.sled");
let store = Store::new("test.sled", EngineType::Sled).unwrap();
test_store_account(store.clone());
// test_store_block(store.clone()); Unimplemented

test_store_suite(store);
remove_test_dbs("test.sled");
}

Expand All @@ -233,12 +261,16 @@ mod tests {
// Removing preexistent DBs in case of a failed previous test
remove_test_dbs("test.rocksdb");
let store = Store::new("test.rocksdb", EngineType::Sled).unwrap();
test_store_account(store.clone());
// test_store_block(store.clone()); Unimplemented

test_store_suite(store);
remove_test_dbs("test.rocksdb");
}

fn test_store_suite(store: Store) {
test_store_account(store.clone());
test_store_block(store.clone());
test_store_block_number(store.clone());
}

fn test_store_account(mut store: Store) {
let address = Address::random();
let code = Bytes::new();
Expand Down Expand Up @@ -347,4 +379,15 @@ mod tests {
};
(block_header, block_body)
}

fn test_store_block_number(store: Store) {
let block_hash = H256::random();
let block_number = 6;

store.add_block_number(block_hash, block_number).unwrap();

let stored_number = store.get_block_number(block_hash).unwrap().unwrap();

assert_eq!(stored_number, block_number);
}
}
120 changes: 70 additions & 50 deletions crates/storage/src/libmdbx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use super::{Key, StoreEngine, Value};
use crate::error::StoreError;
use crate::rlp::{
AccountCodeHashRLP, AccountCodeRLP, AccountInfoRLP, AccountStorageKeyRLP,
AccountStorageValueRLP, AddressRLP, BlockBodyRLP, BlockHeaderRLP, ReceiptRLP,
AccountStorageValueRLP, AddressRLP, BlockBodyRLP, BlockHashRLP, BlockHeaderRLP, ReceiptRLP,
};
use anyhow::Result;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHeader};
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader};
use ethereum_rust_core::types::{BlockNumber, Index};
use ethereum_types::Address;
use libmdbx::{
Expand Down Expand Up @@ -35,26 +35,22 @@ impl StoreEngine for Store {
account_info: AccountInfo,
) -> Result<(), StoreError> {
// Write account to mdbx
{
let txn = self.db.begin_readwrite().unwrap();
match txn.upsert::<AccountInfos>(address.into(), account_info.into()) {
Ok(_) => txn.commit().unwrap(),
Err(err) => return Err(StoreError::LibmdbxError(err)),
}
}
Ok(())
let txn = self
.db
.begin_readwrite()
.map_err(StoreError::LibmdbxError)?;
txn.upsert::<AccountInfos>(address.into(), account_info.into())
.map_err(StoreError::LibmdbxError)?;
txn.commit().map_err(StoreError::LibmdbxError)
}

fn get_account_info(&self, address: Address) -> Result<Option<AccountInfo>, StoreError> {
// Read account from mdbx
let read_value = {
let txn = self.db.begin_read().unwrap();
txn.get::<AccountInfos>(address.into())
};
match read_value {
Ok(value) => Ok(value.map(|a| a.to())),
Err(err) => Err(StoreError::LibmdbxError(err)),
}
let txn = self.db.begin_read().map_err(StoreError::LibmdbxError)?;
Ok(txn
.get::<AccountInfos>(address.into())
.map_err(StoreError::LibmdbxError)?
.map(|a| a.to()))
}

fn add_block_header(
Expand All @@ -63,29 +59,25 @@ impl StoreEngine for Store {
block_header: BlockHeader,
) -> std::result::Result<(), StoreError> {
// Write block header to mdbx
{
let txn = self.db.begin_readwrite().unwrap();
match txn.upsert::<Headers>(block_number, block_header.into()) {
Ok(_) => txn.commit().unwrap(),
Err(err) => return Err(StoreError::LibmdbxError(err)),
}
}
Ok(())
let txn = self
.db
.begin_readwrite()
.map_err(StoreError::LibmdbxError)?;
txn.upsert::<Headers>(block_number, block_header.into())
.map_err(StoreError::LibmdbxError)?;
txn.commit().map_err(StoreError::LibmdbxError)
}

fn get_block_header(
&self,
block_number: BlockNumber,
) -> std::result::Result<Option<BlockHeader>, StoreError> {
// Read block header from mdbx
let read_value = {
let txn = self.db.begin_read().unwrap();
txn.get::<Headers>(block_number)
};
match read_value {
Ok(value) => Ok(value.map(|a| a.to())),
Err(err) => Err(StoreError::LibmdbxError(err)),
}
let txn = self.db.begin_read().map_err(StoreError::LibmdbxError)?;
Ok(txn
.get::<Headers>(block_number)
.map_err(StoreError::LibmdbxError)?
.map(|h| h.to()))
}

fn add_block_body(
Expand All @@ -94,29 +86,50 @@ impl StoreEngine for Store {
block_body: BlockBody,
) -> std::result::Result<(), StoreError> {
// Write block body to mdbx
{
let txn = self.db.begin_readwrite().unwrap();
match txn.upsert::<Bodies>(block_number, block_body.into()) {
Ok(_) => txn.commit().unwrap(),
Err(err) => return Err(StoreError::LibmdbxError(err)),
}
}
Ok(())
let txn = self
.db
.begin_readwrite()
.map_err(StoreError::LibmdbxError)?;
txn.upsert::<Bodies>(block_number, block_body.into())
.map_err(StoreError::LibmdbxError)?;
txn.commit().map_err(StoreError::LibmdbxError)
}

fn get_block_body(
&self,
block_number: BlockNumber,
) -> std::result::Result<Option<BlockBody>, StoreError> {
// Read block body from mdbx
let read_value = {
let txn = self.db.begin_read().unwrap();
txn.get::<Bodies>(block_number)
};
match read_value {
Ok(value) => Ok(value.map(|a| a.to())),
Err(err) => Err(StoreError::LibmdbxError(err)),
}
let txn = self.db.begin_read().map_err(StoreError::LibmdbxError)?;
Ok(txn
.get::<Bodies>(block_number)
.map_err(StoreError::LibmdbxError)?
.map(|b| b.to()))
}

fn add_block_number(
&mut self,
block_hash: BlockHash,
block_number: BlockNumber,
) -> std::result::Result<(), StoreError> {
// Write block number to mdbx
let txn = self
.db
.begin_readwrite()
.map_err(StoreError::LibmdbxError)?;
txn.upsert::<BlockNumbers>(block_hash.into(), block_number)
.map_err(StoreError::LibmdbxError)?;
txn.commit().map_err(StoreError::LibmdbxError)
}

fn get_block_number(
&self,
block_hash: BlockHash,
) -> std::result::Result<Option<BlockNumber>, StoreError> {
// Read block number from mdbx
let txn = self.db.begin_read().map_err(StoreError::LibmdbxError)?;
txn.get::<BlockNumbers>(block_hash.into())
.map_err(StoreError::LibmdbxError)
}

fn set_value(&mut self, _key: Key, _value: Value) -> Result<(), StoreError> {
Expand All @@ -135,6 +148,12 @@ impl Debug for Store {
}

// Define tables

table!(
/// Block hash to number table.
( BlockNumbers ) BlockHashRLP => BlockNumber
);

table!(
/// Block headers table.
( Headers ) BlockNumber => BlockHeaderRLP
Expand Down Expand Up @@ -164,6 +183,7 @@ dupsort!(
/// will be temporary.
pub fn init_db(path: Option<impl AsRef<Path>>) -> Database {
let tables = [
table_info!(BlockNumbers),
table_info!(Headers),
table_info!(Bodies),
table_info!(AccountInfos),
Expand Down
3 changes: 2 additions & 1 deletion crates/storage/src/rlp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::marker::PhantomData;

use ethereum_rust_core::{
rlp::{decode::RLPDecode, encode::RLPEncode},
types::{AccountInfo, BlockBody, BlockHeader, Receipt},
types::{AccountInfo, BlockBody, BlockHash, BlockHeader, Receipt},
Address,
};
use libmdbx::orm::{Decodable, Encodable};
Expand All @@ -19,6 +19,7 @@ pub struct AccountStorageKeyRLP(pub [u8; 32]);
pub struct AccountStorageValueRLP(pub [u8; 32]);

// Block types
pub type BlockHashRLP = Rlp<BlockHash>;
pub type BlockHeaderRLP = Rlp<BlockHeader>;
pub type BlockBodyRLP = Rlp<BlockBody>;

Expand Down
14 changes: 13 additions & 1 deletion crates/storage/src/rocksdb.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{Key, StoreEngine, Value};
use crate::error::StoreError;
use crate::rlp::{AccountInfoRLP, AddressRLP};
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHeader, BlockNumber};
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber};
use ethereum_types::Address;
use libmdbx::orm::{Decodable, Encodable};
use std::fmt::Debug;
Expand Down Expand Up @@ -133,6 +133,18 @@ impl StoreEngine for Store {
todo!()
}

fn add_block_number(
&mut self,
_block_hash: BlockHash,
_block_number: BlockNumber,
) -> Result<(), StoreError> {
todo!()
}

fn get_block_number(&self, _block_hash: BlockHash) -> Result<Option<BlockNumber>, StoreError> {
todo!()
}

fn set_value(&mut self, key: Key, value: Value) -> Result<(), StoreError> {
let (reply_sender, reply_receiver) = sync_channel(0);
self.command_sender.send(StoreCommand::Put(
Expand Down
Loading

0 comments on commit 426fe39

Please sign in to comment.