Skip to content

Commit

Permalink
impl more methods
Browse files Browse the repository at this point in the history
  • Loading branch information
eshaan7 committed Feb 7, 2025
1 parent 821965b commit aa7f092
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 29 deletions.
9 changes: 5 additions & 4 deletions core/src/execution/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::{HashMap, HashSet};

use alloy::consensus::BlockHeader;
use alloy::eips::BlockId;
use alloy::network::primitives::HeaderResponse;
use alloy::network::{BlockResponse, ReceiptResponse};
use alloy::primitives::{keccak256, Address, B256, U256};
Expand Down Expand Up @@ -206,6 +207,7 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
let receipt = receipt.unwrap();

let block_number = receipt.block_number().unwrap();
let block_id = BlockId::from(block_number);
let tag = BlockTag::Number(block_number);

let block = self.state.get_block(tag).await;
Expand All @@ -218,7 +220,7 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
// Fetch all receipts in block, check root and inclusion
let receipts = self
.rpc
.get_block_receipts(tag)
.get_block_receipts(block_id)
.await?
.ok_or(eyre::eyre!(ExecutionError::NoReceiptsForBlock(tag)))?;

Expand Down Expand Up @@ -251,12 +253,11 @@ impl<N: NetworkSpec, R: ExecutionRpc<N>> ExecutionClient<N, R> {
} else {
return Ok(None);
};

let tag = BlockTag::Number(block.header().number());
let block_id = BlockId::from(block.header().number());

let receipts = self
.rpc
.get_block_receipts(tag)
.get_block_receipts(block_id)
.await?
.ok_or(eyre::eyre!(ExecutionError::NoReceiptsForBlock(tag)))?;

Expand Down
11 changes: 2 additions & 9 deletions core/src/execution/rpc/http_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,10 @@ impl<N: NetworkSpec> ExecutionRpc<N> for HttpRpc<N> {
Ok(receipt)
}

async fn get_block_receipts(&self, block: BlockTag) -> Result<Option<Vec<N::ReceiptResponse>>> {
let block = match block {
BlockTag::Latest => BlockNumberOrTag::Latest,
BlockTag::Finalized => BlockNumberOrTag::Finalized,
BlockTag::Number(num) => BlockNumberOrTag::Number(num),
};

let block_id = BlockId::from(block);
async fn get_block_receipts(&self, block: BlockId) -> Result<Option<Vec<N::ReceiptResponse>>> {
let receipts = self
.provider
.get_block_receipts(block_id)
.get_block_receipts(block)
.await
.map_err(|e| RpcError::new("get_block_receipts", e))?;

Expand Down
5 changes: 1 addition & 4 deletions core/src/execution/rpc/mock_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ impl<N: NetworkSpec> ExecutionRpc<N> for MockRpc {
Ok(serde_json::from_str(&receipt)?)
}

async fn get_block_receipts(
&self,
_block: BlockTag,
) -> Result<Option<Vec<N::ReceiptResponse>>> {
async fn get_block_receipts(&self, _block: BlockId) -> Result<Option<Vec<N::ReceiptResponse>>> {
let receipts = read_to_string(self.path.join("receipts.json"))?;
Ok(serde_json::from_str(&receipts)?)
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/execution/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub trait ExecutionRpc<N: NetworkSpec>: Send + Clone + Sync + 'static {
async fn get_code(&self, address: Address, block: u64) -> Result<Vec<u8>>;
async fn send_raw_transaction(&self, bytes: &[u8]) -> Result<B256>;
async fn get_transaction_receipt(&self, tx_hash: B256) -> Result<Option<N::ReceiptResponse>>;
async fn get_block_receipts(&self, block: BlockTag) -> Result<Option<Vec<N::ReceiptResponse>>>;
async fn get_block_receipts(&self, block: BlockId) -> Result<Option<Vec<N::ReceiptResponse>>>;
async fn get_transaction(&self, tx_hash: B256) -> Result<Option<N::TransactionResponse>>;
async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>>;
async fn get_filter_changes(&self, filter_id: U256) -> Result<FilterChanges>;
Expand Down
5 changes: 4 additions & 1 deletion verifiable-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@

| Ethereum JSON-RPC Method | Helios Verifiable API Endpoint |
|--------------------------------|-------------------------------------------------------------------------|
| `eth_getProof` | `/eth/v1/proof/account/{address}?block={tag_or_hash_number}` |
| `eth_getBalance` | `/eth/v1/proof/balance/{address}?block={tag_or_hash_number}` |
| `eth_getTransactionCount` | `/eth/v1/proof/transaction_count/{address}?block={tag_or_hash_number}` |
| `eth_getCode` | `/eth/v1/proof/code/{address}?block={tag_or_hash_number}` |
| `eth_getStorageAt` | `/eth/v1/proof/storage/{address}/{slot}?block={tag_or_hash_number}` |
| `eth_getBlockReceipts` | `/eth/v1/proof/block_receipts/{block}` |
| `eth_getTransactionReceipt` | `/eth/v1/proof/tx_receipt/{tx_hash}` |
| `eth_getFilterLogs` | `/eth/v1/proof/filter_logs/{filter_id}` |
| `eth_getFilterLogs` | `/eth/v1/proof/filter_logs/{filter_id}` |
| `eth_getFilterChanges` | `/eth/v1/proof/filter_changes/{filter_id}` |
94 changes: 88 additions & 6 deletions verifiable-api/bin/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use alloy::{
eips::BlockNumberOrTag,
network::{BlockResponse, ReceiptResponse},
primitives::{Address, B256, U256},
rpc::types::{BlockId, BlockTransactionsKind, Log},
rpc::types::{BlockId, BlockTransactionsKind, FilterChanges, Log},
};
use axum::{
extract::{Path, Query, State},
Expand All @@ -20,7 +20,7 @@ use futures::future::try_join_all;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::json;

use helios_core::{execution::rpc::ExecutionRpc, network_spec::NetworkSpec, types::BlockTag};
use helios_core::{execution::rpc::ExecutionRpc, network_spec::NetworkSpec};
use helios_verifiable_api::{proof::create_receipt_proof, rpc_client::ExecutionClient, types::*};

use crate::ApiState;
Expand All @@ -42,6 +42,34 @@ pub struct BlockQuery {
block: Option<BlockId>,
}

#[derive(Deserialize)]
pub struct AccountProofQuery {
pub block: Option<BlockId>,
pub storage_keys: Vec<B256>,
}

/// This method returns the account proof for a given address.
///
/// Replaces the `eth_getProof` RPC method.
pub async fn get_account_proof<N: NetworkSpec, R: ExecutionRpc<N>>(
Path(address): Path<Address>,
Query(AccountProofQuery {
block,
storage_keys,
}): Query<AccountProofQuery>,
State(ApiState { execution_client }): State<ApiState<N, R>>,
) -> Response<GetAccountProofResponse> {
let block = block.unwrap_or(BlockId::latest());

let proof = execution_client
.rpc
.get_proof(address, &storage_keys, block)
.await
.map_err(map_server_err)?;

Ok(Json(proof))
}

/// This method returns the balance of an account for a given address,
/// along with the Merkle proof of the account's inclusion in the state trie.
///
Expand Down Expand Up @@ -178,7 +206,7 @@ pub async fn get_storage_at<N: NetworkSpec, R: ExecutionRpc<N>>(

let proof = execution_client
.rpc
.get_proof(address, &[storage_slot.into()], block)
.get_proof(address, &[storage_slot], block)
.await
.map_err(map_server_err)?;

Expand All @@ -204,6 +232,25 @@ pub async fn get_storage_at<N: NetworkSpec, R: ExecutionRpc<N>>(
}))
}

/// This method returns all transaction receipts for a given block.
///
/// Replaces the `eth_getBlockReceipts` RPC method.
pub async fn get_block_receipts<N: NetworkSpec, R: ExecutionRpc<N>>(
Path(block): Path<Option<BlockId>>,
State(ApiState { execution_client }): State<ApiState<N, R>>,
) -> Response<GetBlockReceiptsResponse<N>> {
let block = block.unwrap_or(BlockId::latest());

let receipts = execution_client
.rpc
.get_block_receipts(block)
.await
.map_err(map_server_err)?
.unwrap_or(vec![]);

Ok(Json(receipts))
}

/// This method returns the receipt of a transaction along with a Merkle proof of its inclusion.
///
/// Replaces the `eth_getTransactionReceipt` RPC method.
Expand All @@ -225,7 +272,7 @@ pub async fn get_transaction_receipt<N: NetworkSpec, R: ExecutionRpc<N>>(

let receipts = execution_client
.rpc
.get_block_receipts(BlockTag::Number(receipt.block_number().unwrap()))
.get_block_receipts(BlockId::from(receipt.block_number().unwrap()))
.await
.map_err(map_server_err)?
.ok_or_else(|| {
Expand Down Expand Up @@ -270,6 +317,41 @@ pub async fn get_filter_logs<N: NetworkSpec, R: ExecutionRpc<N>>(
}))
}

/// This method returns the changes since the last poll for a given filter id.
/// If filter is of logs type, then corresponding to each log,
/// it also returns the transaction receipt and a Merkle proof of its inclusion..
///
/// Replaces the `eth_getFilterChanges` RPC method.
pub async fn get_filter_changes<N: NetworkSpec, R: ExecutionRpc<N>>(
Path(filter_id): Path<U256>,
State(ApiState { execution_client }): State<ApiState<N, R>>,
) -> Response<GetFilterChangesResponse<N>> {
let filter_changes = execution_client
.rpc
.get_filter_changes(filter_id)
.await
.map_err(map_server_err)?;

Ok(Json(match filter_changes {
FilterChanges::Logs(logs) => {
// Create receipt proofs for each log
let receipt_proofs = create_receipt_proofs_for_logs(&logs, execution_client)
.await
.map_err(map_server_err)?;

GetFilterChangesResponse::Logs(GetFilterLogsResponse {
logs,
receipt_proofs,
})
}
FilterChanges::Hashes(hashes) => GetFilterChangesResponse::Hashes(hashes),
FilterChanges::Empty => GetFilterChangesResponse::Hashes(vec![]),
FilterChanges::Transactions(txs) => GetFilterChangesResponse::Hashes(
txs.into_iter().map(|t| t.inner.tx_hash().clone()).collect(),
),
}))
}

async fn create_receipt_proofs_for_logs<N: NetworkSpec, R: ExecutionRpc<N>>(
logs: &[Log],
execution_client: Arc<ExecutionClient<N, R>>,
Expand All @@ -284,8 +366,8 @@ async fn create_receipt_proofs_for_logs<N: NetworkSpec, R: ExecutionRpc<N>>(
let blocks_receipts_fut = block_nums.into_iter().map(|block_num| {
let execution_client = Arc::clone(&execution_client);
async move {
let tag = BlockTag::Number(block_num);
let receipts = execution_client.rpc.get_block_receipts(tag).await?;
let block_id = BlockId::from(block_num);
let receipts = execution_client.rpc.get_block_receipts(block_id).await?;
receipts
.ok_or_eyre("No receipts found for the block")
.map(|receipts| (block_num, receipts))
Expand Down
8 changes: 7 additions & 1 deletion verifiable-api/bin/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ pub fn build_router<N: NetworkSpec, R: ExecutionRpc<N>>() -> Router<ApiState<N,
Router::new().nest(
"/eth/v1/proof",
Router::new()
.route("/account/{address}", get(handlers::get_account_proof))
.route("/balance/{address}", get(handlers::get_balance))
.route(
"/transaction_count/{address}",
get(handlers::get_transaction_count),
)
.route("/code/{address}", get(handlers::get_code))
.route("/storage/{address}/{slot}", get(handlers::get_storage_at))
.route("/block_receipts/{block}", get(handlers::get_block_receipts))
.route(
"/tx_receipt/{tx_hash}",
get(handlers::get_transaction_receipt),
)
.route("/filter_logs/{filter_id}", get(handlers::get_filter_logs)),
.route("/filter_logs/{filter_id}", get(handlers::get_filter_logs))
.route(
"/filter_changes/{filter_id}",
get(handlers::get_filter_changes),
),
)
}
52 changes: 52 additions & 0 deletions verifiable-api/src/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ use crate::types::*;

#[async_trait]
pub trait VerifiableApi<N: NetworkSpec> {
async fn get_account(
&self,
address: Address,
block: Option<BlockId>,
) -> Result<GetAccountProofResponse, Error>;
async fn get_balance(
&self,
address: Address,
Expand All @@ -33,11 +38,19 @@ pub trait VerifiableApi<N: NetworkSpec> {
key: U256,
block: Option<BlockId>,
) -> Result<GetStorageAtResponse, Error>;
async fn get_block_receipts(
&self,
block: BlockId,
) -> Result<GetBlockReceiptsResponse<N>, Error>;
async fn get_transaction_receipt(
&self,
tx_hash: B256,
) -> Result<GetTransactionReceiptResponse<N>, Error>;
async fn get_filter_logs(&self, filter_id: U256) -> Result<GetFilterLogsResponse<N>, Error>;
async fn get_filter_changes(
&self,
filter_id: U256,
) -> Result<GetFilterChangesResponse<N>, Error>;
}

pub struct VerifiableApiClient {
Expand All @@ -56,6 +69,22 @@ impl VerifiableApiClient {

#[async_trait]
impl<N: NetworkSpec> VerifiableApi<N> for VerifiableApiClient {
async fn get_account(
&self,
address: Address,
block: Option<BlockId>,
) -> Result<GetAccountProofResponse, Error> {
let url = format!("{}/eth/v1/proof/account/{}", self.base_url, address);
let response = self
.client
.get(&url)
.query(&[("block", block)])
.send()
.await?;
let response = response.json::<GetAccountProofResponse>().await?;
Ok(response)
}

async fn get_balance(
&self,
address: Address,
Expand Down Expand Up @@ -124,6 +153,16 @@ impl<N: NetworkSpec> VerifiableApi<N> for VerifiableApiClient {
Ok(response)
}

async fn get_block_receipts(
&self,
block: BlockId,
) -> Result<GetBlockReceiptsResponse<N>, Error> {
let url = format!("{}/eth/v1/proof/block_receipts/{}", self.base_url, block);
let response = self.client.get(&url).send().await?;
let response = response.json::<GetBlockReceiptsResponse<N>>().await?;
Ok(response)
}

async fn get_transaction_receipt(
&self,
tx_hash: B256,
Expand All @@ -140,4 +179,17 @@ impl<N: NetworkSpec> VerifiableApi<N> for VerifiableApiClient {
let response = response.json::<GetFilterLogsResponse<N>>().await?;
Ok(response)
}

async fn get_filter_changes(
&self,
filter_id: U256,
) -> Result<GetFilterChangesResponse<N>, Error> {
let url = format!(
"{}/eth/v1/proof/filter_changes/{}",
self.base_url, filter_id
);
let response = self.client.get(&url).send().await?;
let response = response.json::<GetFilterChangesResponse<N>>().await?;
Ok(response)
}
}
Loading

0 comments on commit aa7f092

Please sign in to comment.