Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add rpc endpoint eth_getCode #162

Merged
merged 44 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
95c651a
Impl RLPDecode for BlockHeader
fmoletta Jul 12, 2024
1e2a66c
Extend Store api to fetch blocks + start implementing Decode for Tran…
fmoletta Jul 12, 2024
ac5f04e
Encode and Decode transactions with type
fmoletta Jul 12, 2024
d397b34
Impl RLPDecode for Withdrawal
fmoletta Jul 12, 2024
6d6a0f8
Complete api for libmdx
fmoletta Jul 12, 2024
63f5d18
Implement getters and setters for block in store api
fmoletta Jul 12, 2024
da19600
Fixes + add test
fmoletta Jul 12, 2024
5e5f792
Clippy
fmoletta Jul 12, 2024
847782d
Add api skeleton for other db impls
fmoletta Jul 12, 2024
9e485c5
Move test to main module + fix api
fmoletta Jul 12, 2024
db86801
Merge branch 'main' into add-block-api-to-db
fmoletta Jul 15, 2024
7e98b8a
Add mapping between block hash & block number to store api
fmoletta Jul 15, 2024
23133aa
reafctor: Remove unwraps from libmdx impl of Store
fmoletta Jul 15, 2024
ffeccbf
Add methods to store
fmoletta Jul 15, 2024
2ab77f5
Add test
fmoletta Jul 15, 2024
fe7ba64
clippy
fmoletta Jul 15, 2024
682fa90
Add table to init
fmoletta Jul 15, 2024
5b3beee
Merge branch 'main' of https://github.com/lambdaclass/ethrex into add…
fmoletta Jul 16, 2024
2cca6ba
Merge branch 'main' of https://github.com/lambdaclass/ethrex into add…
fmoletta Jul 16, 2024
78fee7c
Parse GetBlockByNumber request
fmoletta Jul 11, 2024
d154f5c
Add state to rpc handler
fmoletta Jul 12, 2024
f56738c
Add state to rpc handler + fmt
fmoletta Jul 12, 2024
62a3f87
Impl getBlockByNumber
fmoletta Jul 15, 2024
f8fba01
Add getBlockByHash wip
fmoletta Jul 15, 2024
87d2ce0
Complete getBlockByHash
fmoletta Jul 15, 2024
d729b60
fmt
fmoletta Jul 15, 2024
631dfa7
Fixes
fmoletta Jul 16, 2024
2828593
Add tracing
fmoletta Jul 16, 2024
4de8f45
Remove from attribute from StoreError::Libmdx
fmoletta Jul 16, 2024
6e023e1
Collect store tests in test_store_suite
fmoletta Jul 16, 2024
5725f9d
Merge branch 'main' of https://github.com/lambdaclass/ethrex into get…
fmoletta Jul 16, 2024
4b16d64
Merge branch 'main' into add-block-number-table
fmoletta Jul 16, 2024
c75d2b4
Merge branch 'add-block-number-table' into get_block_by_number
fmoletta Jul 16, 2024
17161d0
Merge branch 'main' of https://github.com/lambdaclass/ethrex into get…
fmoletta Jul 17, 2024
30aee3c
Add eth_getBalance endpoint
fmoletta Jul 17, 2024
13262e9
Push file
fmoletta Jul 17, 2024
d97b5d8
Fix comment
fmoletta Jul 17, 2024
bfa249a
clippy
fmoletta Jul 17, 2024
cd8edfb
Add endpoint + store api methods
fmoletta Jul 17, 2024
5ed85a5
add get_code_by_account_address method to store
fmoletta Jul 17, 2024
7b7e4fe
Fix
fmoletta Jul 17, 2024
ec4f7c3
Add rpc call + update tracing
fmoletta Jul 17, 2024
cac3a99
fix
fmoletta Jul 17, 2024
599b801
Merge branch 'main' of https://github.com/lambdaclass/ethrex into eth…
fmoletta Jul 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions crates/rpc/src/eth/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ pub struct GetBalanceRequest {
pub block: BlockIdentifier,
}

pub struct GetCodeRequest {
pub address: Address,
pub block: BlockIdentifier,
}

impl GetBalanceRequest {
pub fn parse(params: &Option<Vec<Value>>) -> Option<GetBalanceRequest> {
let params = params.as_ref()?;
Expand All @@ -25,6 +30,19 @@ impl GetBalanceRequest {
}
}

impl GetCodeRequest {
pub fn parse(params: &Option<Vec<Value>>) -> Option<GetCodeRequest> {
let params = params.as_ref()?;
if params.len() != 2 {
return None;
};
Some(GetCodeRequest {
address: serde_json::from_value(params[0].clone()).ok()?,
block: serde_json::from_value(params[1].clone()).ok()?,
})
}
}

pub fn get_balance(request: &GetBalanceRequest, storage: Store) -> Result<Value, RpcErr> {
info!(
"Requested balance of account {} at block {}",
Expand All @@ -40,3 +58,19 @@ pub fn get_balance(request: &GetBalanceRequest, storage: Store) -> Result<Value,

serde_json::to_value(format!("{:#x}", account.balance)).map_err(|_| RpcErr::Internal)
}

pub fn get_code(request: &GetCodeRequest, storage: Store) -> Result<Value, RpcErr> {
info!(
"Requested code of account {} at block {}",
request.address, request.block
);
let code = match storage.get_code_by_account_address(request.address) {
Ok(Some(code)) => code,
// Account not found
Ok(_) => return Ok(Value::Null),
// DB error
_ => return Err(RpcErr::Internal),
};

serde_json::to_value(format!("0x{:x}", code)).map_err(|_| RpcErr::Internal)
}
6 changes: 5 additions & 1 deletion crates/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{future::IntoFuture, net::SocketAddr};
use axum::{routing::post, Json, Router};
use engine::{ExchangeCapabilitiesRequest, NewPayloadV3Request};
use eth::{
account::{self, GetBalanceRequest},
account::{self, GetBalanceRequest, GetCodeRequest},
block::{
self, GetBlockByHashRequest, GetBlockByNumberRequest,
GetBlockTransactionCountByNumberRequest, GetTransactionByBlockHashAndIndexRequest,
Expand Down Expand Up @@ -97,6 +97,10 @@ pub fn map_requests(req: &RpcRequest, storage: Store) -> Result<Value, RpcErr> {
let request = GetBalanceRequest::parse(&req.params).ok_or(RpcErr::BadParams)?;
account::get_balance(&request, storage)
}
"eth_getCode" => {
let request = GetCodeRequest::parse(&req.params).ok_or(RpcErr::BadParams)?;
account::get_code(&request, storage)
}
"eth_getBlockTransactionCountByNumber" => {
let request = GetBlockTransactionCountByNumberRequest::parse(&req.params)
.ok_or(RpcErr::BadParams)?;
Expand Down
14 changes: 13 additions & 1 deletion crates/storage/src/in_memory.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use super::{Key, StoreEngine, Value};
use crate::error::StoreError;
use bytes::Bytes;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber};
use ethereum_types::Address;
use ethereum_types::{Address, H256};
use std::{collections::HashMap, fmt::Debug};

#[derive(Default)]
Expand All @@ -11,6 +12,8 @@ pub struct Store {
bodies: HashMap<BlockNumber, BlockBody>,
headers: HashMap<BlockNumber, BlockHeader>,
values: HashMap<Key, Value>,
// Maps code hashes to code
account_codes: HashMap<H256, Bytes>,
}

impl Store {
Expand Down Expand Up @@ -80,6 +83,15 @@ impl StoreEngine for Store {
fn get_block_number(&self, block_hash: BlockHash) -> Result<Option<BlockNumber>, StoreError> {
Ok(self.block_numbers.get(&block_hash).copied())
}

fn add_account_code(&mut self, code_hash: H256, code: Bytes) -> Result<(), StoreError> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: why don't we have to specify pub here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is part of a trait implementation, so it has the same visibility as the trait (which is public in this case)

self.account_codes.insert(code_hash, code);
Ok(())
}

fn get_account_code(&self, code_hash: H256) -> Result<Option<Bytes>, StoreError> {
Ok(self.account_codes.get(&code_hash).cloned())
}
}

impl Debug for Store {
Expand Down
58 changes: 57 additions & 1 deletion crates/storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use self::libmdbx::Store as LibmdbxStore;
use self::rocksdb::Store as RocksDbStore;
#[cfg(feature = "sled")]
use self::sled::Store as SledStore;
use bytes::Bytes;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber};
use ethereum_types::Address;
use ethereum_types::{Address, H256};
use std::fmt::Debug;
use std::sync::{Arc, Mutex};

Expand Down Expand Up @@ -82,6 +83,22 @@ pub trait StoreEngine: Debug + Send {

/// Retrieve a stored value under Key
fn get_value(&self, key: Key) -> Result<Option<Value>, StoreError>;

/// Add account code
fn add_account_code(&mut self, code_hash: H256, code: Bytes) -> Result<(), StoreError>;

/// Obtain account code via code hash
fn get_account_code(&self, code_hash: H256) -> Result<Option<Bytes>, StoreError>;

/// Obtain account code via account address
fn get_code_by_account_address(&self, address: Address) -> Result<Option<Bytes>, StoreError> {
let code_hash = match self.get_account_info(address) {
Ok(Some(acc_info)) => acc_info.code_hash,
Ok(None) => return Ok(None),
Err(error) => return Err(error),
};
self.get_account_code(code_hash)
}
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -212,6 +229,33 @@ impl Store {
.unwrap()
.get_block_number(block_hash)
}

pub fn add_account_code(&self, code_hash: H256, code: Bytes) -> Result<(), StoreError> {
self.engine
.clone()
.lock()
.unwrap()
.add_account_code(code_hash, code)
}

pub fn get_account_code(&self, code_hash: H256) -> Result<Option<Bytes>, StoreError> {
self.engine
.clone()
.lock()
.unwrap()
.get_account_code(code_hash)
}

pub fn get_code_by_account_address(
&self,
address: Address,
) -> Result<Option<Bytes>, StoreError> {
self.engine
.clone()
.lock()
.unwrap()
.get_code_by_account_address(address)
}
}

#[cfg(test)]
Expand Down Expand Up @@ -269,6 +313,7 @@ mod tests {
test_store_account(store.clone());
test_store_block(store.clone());
test_store_block_number(store.clone());
test_store_account_code(store.clone());
}

fn test_store_account(mut store: Store) {
Expand Down Expand Up @@ -390,4 +435,15 @@ mod tests {

assert_eq!(stored_number, block_number);
}

fn test_store_account_code(store: Store) {
let code_hash = H256::random();
let code = Bytes::from("kiwi");

store.add_account_code(code_hash, code.clone()).unwrap();

let stored_code = store.get_account_code(code_hash).unwrap().unwrap();

assert_eq!(stored_code, code);
}
}
23 changes: 22 additions & 1 deletion crates/storage/src/libmdbx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ use crate::rlp::{
AccountStorageValueRLP, AddressRLP, BlockBodyRLP, BlockHashRLP, BlockHeaderRLP, ReceiptRLP,
};
use anyhow::Result;
use bytes::Bytes;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader};
use ethereum_rust_core::types::{BlockNumber, Index};
use ethereum_types::Address;
use ethereum_types::{Address, H256};
use libmdbx::{
dupsort,
orm::{table, Database},
Expand Down Expand Up @@ -139,6 +140,26 @@ impl StoreEngine for Store {
fn get_value(&self, _key: Key) -> Result<Option<Value>, StoreError> {
todo!()
}

fn add_account_code(&mut self, code_hash: H256, code: Bytes) -> Result<(), StoreError> {
// Write account code to mdbx
let txn = self
.db
.begin_readwrite()
.map_err(StoreError::LibmdbxError)?;
txn.upsert::<AccountCodes>(code_hash.into(), code.into())
.map_err(StoreError::LibmdbxError)?;
txn.commit().map_err(StoreError::LibmdbxError)
}

fn get_account_code(&self, code_hash: H256) -> Result<Option<Bytes>, StoreError> {
// Read account code from mdbx
let txn = self.db.begin_read().map_err(StoreError::LibmdbxError)?;
Ok(txn
.get::<AccountCodes>(code_hash.into())
.map_err(StoreError::LibmdbxError)?
.map(|b| b.to()))
}
}

impl Debug for Store {
Expand Down
7 changes: 4 additions & 3 deletions crates/storage/src/rlp.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use std::marker::PhantomData;

use bytes::Bytes;
use ethereum_rust_core::{
rlp::{decode::RLPDecode, encode::RLPEncode},
types::{AccountInfo, BlockBody, BlockHash, BlockHeader, Receipt},
Address,
Address, H256,
};
use libmdbx::orm::{Decodable, Encodable};

// Account types
pub type AddressRLP = Rlp<Address>;
pub type AccountInfoRLP = Rlp<AccountInfo>;
pub type AccountCodeHashRLP = Rlp<Vec<u8>>;
pub type AccountCodeRLP = Rlp<Vec<u8>>;
pub type AccountCodeHashRLP = Rlp<H256>;
pub type AccountCodeRLP = Rlp<Bytes>;

// TODO: these structs were changed after a merge.
// See if we can reuse Rlp struct
Expand Down
11 changes: 10 additions & 1 deletion crates/storage/src/rocksdb.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use super::{Key, StoreEngine, Value};
use crate::error::StoreError;
use crate::rlp::{AccountInfoRLP, AddressRLP};
use bytes::Bytes;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber};
use ethereum_types::Address;
use ethereum_types::{Address, H256};
use libmdbx::orm::{Decodable, Encodable};
use std::fmt::Debug;
use std::sync::mpsc::{channel, sync_channel, Receiver, Sender, SyncSender};
Expand Down Expand Up @@ -165,6 +166,14 @@ impl StoreEngine for Store {

reply_receiver.recv()?
}

fn add_account_code(&mut self, _code_hash: H256, _code: Bytes) -> Result<(), StoreError> {
todo!()
}

fn get_account_code(&self, _code_hash: H256) -> Result<Option<Bytes>, StoreError> {
todo!()
}
}

impl Debug for Store {
Expand Down
11 changes: 10 additions & 1 deletion crates/storage/src/sled.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use super::{Key, StoreEngine, Value};
use crate::error::StoreError;
use crate::rlp::{AccountInfoRLP, AddressRLP};
use bytes::Bytes;
use ethereum_rust_core::types::{AccountInfo, BlockBody, BlockHash, BlockHeader, BlockNumber};
use ethereum_types::Address;
use ethereum_types::{Address, H256};
use libmdbx::orm::{Decodable, Encodable};
use sled::Db;
use std::fmt::Debug;
Expand Down Expand Up @@ -93,6 +94,14 @@ impl StoreEngine for Store {
fn get_value(&self, key: Key) -> Result<Option<Vec<u8>>, StoreError> {
Ok(self.values.get(key)?.map(|value| value.to_vec()))
}

fn add_account_code(&mut self, _code_hash: H256, _code: Bytes) -> Result<(), StoreError> {
todo!()
}

fn get_account_code(&self, _code_hash: H256) -> Result<Option<Bytes>, StoreError> {
todo!()
}
}

impl Debug for Store {
Expand Down
Loading