Skip to content

Commit

Permalink
feat: store account info in db (lambdaclass#63)
Browse files Browse the repository at this point in the history
**Motivation**

 Enable storing account information in DB
 
**Description**
 

* Rename `Account` into `GenesisAccount` and add a separate `Account`
struct containing the storage, code, and info fields, with the info
being an `AccountInfo` struct containing the code hash. Also implement
conversion from `GenesisAccount` to `Account`
* Create `AccountInfos` table mapping addresses to account info
* Implement TODO comment related to encoding

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

Closes lambdaclass#40
  • Loading branch information
fmoletta authored Jun 26, 2024
1 parent c904c05 commit b91588b
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 19 deletions.
1 change: 1 addition & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ tinyvec = "1.6.0"
ethereum-types = "0.14.1"
serde.workspace = true
serde_json.workspace = true
keccak-hash = "0.10.0"

[dev-dependencies]
hex-literal = "0.4.1"
61 changes: 55 additions & 6 deletions crates/core/src/types/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,66 @@ use std::collections::HashMap;

use bytes::Bytes;
use ethereum_types::{H256, U256};
use serde::Deserialize;

use crate::rlp::encode::RLPEncode;

use super::GenesisAccount;

#[allow(unused)]
#[derive(Debug, Deserialize, PartialEq)]
#[derive(Debug, PartialEq)]
pub struct Account {
#[serde(default)]
pub info: AccountInfo,
pub code: Bytes,
#[serde(default)]
pub storage: HashMap<H256, H256>,
#[serde(deserialize_with = "crate::serde_utils::u256::deser_dec_str")]
}

#[derive(Debug, PartialEq)]
pub struct AccountInfo {
pub code_hash: H256,
pub balance: U256,
#[serde(default, deserialize_with = "crate::serde_utils::u64::deser_dec_str")]
pub nonce: u64,
}

impl From<GenesisAccount> for Account {
fn from(genesis: GenesisAccount) -> Self {
Self {
info: AccountInfo {
code_hash: code_hash(&genesis.code),
balance: genesis.balance,
nonce: genesis.nonce,
},
code: genesis.code,
storage: genesis.storage,
}
}
}

fn code_hash(code: &Bytes) -> H256 {
keccak_hash::keccak(code.as_ref())
}

impl RLPEncode for AccountInfo {
fn encode(&self, buf: &mut dyn bytes::BufMut) {
self.code_hash.encode(buf);
self.balance.encode(buf);
self.nonce.encode(buf);
}
}

#[cfg(test)]
mod test {
use std::str::FromStr;

use super::*;

#[test]
fn test_code_hash() {
let empty_code = Bytes::new();
let hash = code_hash(&empty_code);
assert_eq!(
hash,
H256::from_str("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
.unwrap()
)
}
}
7 changes: 1 addition & 6 deletions crates/core/src/types/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,7 @@ impl RLPEncode for BlockHeader {
self.transactions_root.encode(buf);
self.receipt_root.encode(buf);
self.logs_bloom.encode(buf);

// TODO: move to rlp::encode
let mut tmp_buf = vec![];
self.difficulty.to_big_endian(&mut tmp_buf);
tmp_buf.encode(buf);

self.difficulty.encode(buf);
self.number.encode(buf);
self.gas_limit.encode(buf);
self.gas_used.encode(buf);
Expand Down
20 changes: 16 additions & 4 deletions crates/core/src/types/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::types::Account;
use bytes::Bytes;
use ethereum_types::{Address, H256, U256};
use serde::Deserialize;
Expand All @@ -11,7 +10,7 @@ pub struct Genesis {
/// Chain configuration
pub config: ChainConfig,
/// The initial state of the accounts in the genesis block.
pub alloc: HashMap<Address, Account>,
pub alloc: HashMap<Address, GenesisAccount>,
/// Genesis header values
pub coinbase: Address,
pub difficulty: U256,
Expand Down Expand Up @@ -76,6 +75,19 @@ pub struct ChainConfig {
pub terminal_total_difficulty_passed: bool,
}

#[allow(unused)]
#[derive(Debug, Deserialize, PartialEq)]
pub struct GenesisAccount {
#[serde(default)]
pub code: Bytes,
#[serde(default)]
pub storage: HashMap<H256, H256>,
#[serde(deserialize_with = "crate::serde_utils::u256::deser_dec_str")]
pub balance: U256,
#[serde(default, deserialize_with = "crate::serde_utils::u64::deser_dec_str")]
pub nonce: u64,
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down Expand Up @@ -125,11 +137,11 @@ mod tests {
// We will only check a couple of the hashmap's values as it is quite large
let addr_a = Address::from_str("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02").unwrap();
assert!(genesis.alloc.contains_key(&addr_a));
let expected_account_a = Account {
let expected_account_a = GenesisAccount {
code: Bytes::from(String::from("0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500")),
storage: Default::default(),
balance: 0.into(),
nonce: 1,
storage: Default::default(),
};
assert_eq!(genesis.alloc[&addr_a], expected_account_a);
// Check some storage values from another account
Expand Down
33 changes: 33 additions & 0 deletions crates/storage/src/account.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use libmdbx::orm::{Decodable, Encodable};

pub struct AddressRLP(Vec<u8>);

pub struct AccountInfoRLP(Vec<u8>);

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

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

impl Decodable for AddressRLP {
fn decode(b: &[u8]) -> anyhow::Result<Self> {
Ok(AddressRLP(b.to_vec()))
}
}

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

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

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

use account::{AccountInfoRLP, AddressRLP};
use block::{BlockBodyRLP, BlockHeaderRLP};
use core::types::BlockNumber;
use libmdbx::{
Expand All @@ -17,12 +19,21 @@ table!(
/// Block bodies table.
( Bodies ) BlockNumber => BlockBodyRLP
);
table!(
/// Account infos table.
( AccountInfos ) AddressRLP => AccountInfoRLP
);

/// 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), table_info!(Bodies)]
.into_iter()
.collect();
let tables = [
table_info!(Headers),
table_info!(Bodies),
table_info!(AccountInfos),
]
.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 b91588b

Please sign in to comment.