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(core): adds a get proof endpoint in zks namespace #455

7 changes: 7 additions & 0 deletions core/lib/config/src/configs/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ pub struct Web3JsonRpcConfig {
/// The value is per active connection.
/// Note: For HTTP, rate limiting is expected to be configured on the infra level.
pub websocket_requests_per_minute_limit: Option<u32>,
/// Tree API url, currently used to proxy `getProof` calls to the tree
pub tree_api_url: Option<String>,
}

impl Web3JsonRpcConfig {
Expand Down Expand Up @@ -123,6 +125,7 @@ impl Web3JsonRpcConfig {
max_batch_request_size: Default::default(),
max_response_body_size_mb: Default::default(),
websocket_requests_per_minute_limit: Default::default(),
tree_api_url: None,
}
}

Expand Down Expand Up @@ -205,6 +208,10 @@ impl Web3JsonRpcConfig {
// The default limit is chosen to be reasonably permissive.
self.websocket_requests_per_minute_limit.unwrap_or(6000)
}

pub fn tree_api_url(&self) -> Option<String> {
self.tree_api_url.clone()
}
}

#[derive(Debug, Deserialize, Clone, PartialEq)]
Expand Down
1 change: 1 addition & 0 deletions core/lib/env_config/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ mod tests {
max_batch_request_size: Some(200),
max_response_body_size_mb: Some(10),
websocket_requests_per_minute_limit: Some(10),
tree_api_url: None,
},
contract_verification: ContractVerificationApiConfig {
port: 3070,
Expand Down
16 changes: 16 additions & 0 deletions core/lib/types/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,3 +684,19 @@ pub struct L1BatchDetails {
#[serde(flatten)]
pub base: BlockDetailsBase,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct StorageProof {
pub key: H256,
pub proof: Vec<H256>,
pub value: H256,
pub index: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Proof {
pub address: Address,
pub storage_proof: Vec<StorageProof>,
}
2 changes: 2 additions & 0 deletions core/lib/web3_decl/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ pub enum Web3Error {
InvalidFilterBlockHash,
#[error("Query returned more than {0} results. Try smaller range of blocks")]
TooManyLogs(usize),
#[error("Tree API is not available")]
TreeApiUnavailable,
}
3 changes: 1 addition & 2 deletions core/lib/zksync_core/src/api_server/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,13 @@ impl TreeApiClient for AsyncTreeReader {

/// [`TreeApiClient`] implementation requesting data from a Merkle tree API server.
#[derive(Debug, Clone)]
pub(crate) struct TreeApiHttpClient {
pub struct TreeApiHttpClient {
inner: reqwest::Client,
info_url: String,
proofs_url: String,
}

impl TreeApiHttpClient {
#[cfg(test)] // temporary measure until `TreeApiClient` is required by other components
pub fn new(url_base: &str) -> Self {
Self {
inner: reqwest::Client::new(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub fn into_jsrpc_error(err: Web3Error) -> Error {
Web3Error::SubmitTransactionError(_, _) | Web3Error::SerializationError(_) => 3.into(),
Web3Error::PubSubTimeout => 4.into(),
Web3Error::RequestTimeout => 5.into(),
Web3Error::TreeApiUnavailable => 6.into(),
},
message: match err {
Web3Error::SubmitTransactionError(_, _) => err.to_string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use jsonrpc_derive::rpc;
// Workspace uses
use zksync_types::{
api::{
BlockDetails, BridgeAddresses, L1BatchDetails, L2ToL1LogProof, ProtocolVersion,
BlockDetails, BridgeAddresses, L1BatchDetails, L2ToL1LogProof, Proof, ProtocolVersion,
TransactionDetails,
},
fee::Fee,
Expand Down Expand Up @@ -111,6 +111,14 @@ pub trait ZksNamespaceT {

#[rpc(name = "zks_getLogsWithVirtualBlocks")]
fn get_logs_with_virtual_blocks(&self, filter: Filter) -> BoxFuture<Result<Vec<Log>>>;

#[rpc(name = "zks_getProof")]
fn get_proof(
&self,
address: Address,
keys: Vec<H256>,
l1_batch_number: L1BatchNumber,
) -> BoxFuture<Result<Proof>>;
}

impl<G: L1GasPriceProvider + Send + Sync + 'static> ZksNamespaceT for ZksNamespace<G> {
Expand Down Expand Up @@ -308,4 +316,19 @@ impl<G: L1GasPriceProvider + Send + Sync + 'static> ZksNamespaceT for ZksNamespa
.map_err(into_jsrpc_error)
})
}

fn get_proof(
&self,
address: Address,
keys: Vec<H256>,
l1_batch_number: L1BatchNumber,
) -> BoxFuture<Result<Proof>> {
let self_ = self.clone();
Box::pin(async move {
self_
.get_proofs_impl(address, keys.clone(), l1_batch_number)
.await
.map_err(into_jsrpc_error)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub fn into_jsrpc_error(err: Web3Error) -> ErrorObjectOwned {
Web3Error::SubmitTransactionError(_, _) | Web3Error::SerializationError(_) => 3,
Web3Error::PubSubTimeout => 4,
Web3Error::RequestTimeout => 5,
Web3Error::TreeApiUnavailable => 6,
},
match err {
Web3Error::SubmitTransactionError(ref message, _) => message.clone(),
Expand Down
12 changes: 11 additions & 1 deletion core/lib/zksync_core/src/api_server/web3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use zksync_web3_decl::{

use crate::{
api_server::{
execution_sandbox::VmConcurrencyBarrier, tx_sender::TxSender,
execution_sandbox::VmConcurrencyBarrier, tree::TreeApiHttpClient, tx_sender::TxSender,
web3::backend_jsonrpc::batch_limiter_middleware::RateLimitMetadata,
},
l1_gas_price::L1GasPriceProvider,
Expand Down Expand Up @@ -136,6 +136,7 @@ pub struct ApiBuilder<G> {
polling_interval: Option<Duration>,
namespaces: Option<Vec<Namespace>>,
logs_translator_enabled: bool,
tree_api_url: Option<String>,
}

impl<G> ApiBuilder<G> {
Expand All @@ -159,6 +160,7 @@ impl<G> ApiBuilder<G> {
namespaces: None,
config,
logs_translator_enabled: false,
tree_api_url: None,
}
}

Expand Down Expand Up @@ -255,6 +257,11 @@ impl<G> ApiBuilder<G> {
self.logs_translator_enabled = true;
self
}

pub fn with_tree_api(mut self, tree_api_url: Option<String>) -> Self {
self.tree_api_url = tree_api_url;
self
}
}

impl<G: 'static + Send + Sync + L1GasPriceProvider> ApiBuilder<G> {
Expand All @@ -280,6 +287,9 @@ impl<G: 'static + Send + Sync + L1GasPriceProvider> ApiBuilder<G> {
api_config: self.config,
last_sealed_miniblock,
logs_translator_enabled: self.logs_translator_enabled,
tree_api: self
.tree_api_url
.map(|url| TreeApiHttpClient::new(url.as_str())),
}
}

Expand Down
52 changes: 46 additions & 6 deletions core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,28 @@ use zksync_dal::StorageProcessor;
use zksync_mini_merkle_tree::MiniMerkleTree;
use zksync_types::{
api::{
BlockDetails, BridgeAddresses, GetLogsFilter, L1BatchDetails, L2ToL1LogProof,
ProtocolVersion, TransactionDetails,
BlockDetails, BridgeAddresses, GetLogsFilter, L1BatchDetails, L2ToL1LogProof, Proof,
ProtocolVersion, StorageProof, TransactionDetails,
},
fee::Fee,
l1::L1Tx,
l2::L2Tx,
l2_to_l1_log::L2ToL1Log,
tokens::ETHEREUM_ADDRESS,
transaction_request::CallRequest,
L1BatchNumber, MiniblockNumber, Transaction, L1_MESSENGER_ADDRESS, L2_ETH_TOKEN_ADDRESS,
MAX_GAS_PER_PUBDATA_BYTE, REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, U256, U64,
AccountTreeId, L1BatchNumber, MiniblockNumber, StorageKey, Transaction, L1_MESSENGER_ADDRESS,
L2_ETH_TOKEN_ADDRESS, MAX_GAS_PER_PUBDATA_BYTE, REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, U256,
U64,
};
use zksync_utils::{address_to_h256, ratio_to_big_decimal_normalized};
use zksync_web3_decl::{
error::Web3Error,
types::{Address, Filter, Log, Token, H256},
};

use crate::api_server::web3::{
backend_jsonrpc::error::internal_error, metrics::API_METRICS, RpcState,
use crate::api_server::{
tree::TreeApiClient,
web3::{backend_jsonrpc::error::internal_error, metrics::API_METRICS, RpcState},
};
use crate::l1_gas_price::L1GasPriceProvider;

Expand Down Expand Up @@ -620,4 +622,42 @@ impl<G: L1GasPriceProvider> ZksNamespace<G> {
) -> Result<Vec<Log>, Web3Error> {
self.state.translate_get_logs(filter).await
}

#[tracing::instrument(skip_all)]
pub async fn get_proofs_impl(
&self,
address: Address,
keys: Vec<H256>,
l1_batch_number: L1BatchNumber,
slowli marked this conversation as resolved.
Show resolved Hide resolved
) -> Result<Proof, Web3Error> {
const METHOD_NAME: &str = "get_proofs";

let hashed_keys = keys
.iter()
.map(|key| StorageKey::new(AccountTreeId::new(address), *key).hashed_key_u256())
.collect();

let storage_proof = self
.state
.tree_api
.as_ref()
.ok_or(Web3Error::TreeApiUnavailable)?
.get_proofs(l1_batch_number, hashed_keys)
.await
.map_err(|err| internal_error(METHOD_NAME, err))?
.into_iter()
.zip(keys)
.map(|(proof, key)| StorageProof {
key,
proof: proof.merkle_path,
value: proof.value,
index: proof.index,
})
.collect();

Ok(Proof {
address,
storage_proof,
})
}
}
3 changes: 3 additions & 0 deletions core/lib/zksync_core/src/api_server/web3/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use super::metrics::API_METRICS;
use crate::{
api_server::{
execution_sandbox::BlockArgs,
tree::TreeApiHttpClient,
tx_sender::TxSender,
web3::{
backend_jsonrpc::error::internal_error, namespaces::eth::EVENT_TOPIC_NUMBER_LIMIT,
Expand Down Expand Up @@ -167,6 +168,7 @@ impl SealedMiniblockNumber {
pub struct RpcState<E> {
pub installed_filters: Arc<RwLock<Filters>>,
pub connection_pool: ConnectionPool,
pub tree_api: Option<TreeApiHttpClient>,
pub tx_sender: TxSender<E>,
pub sync_state: Option<SyncState>,
pub(super) api_config: InternalApiConfig,
Expand All @@ -185,6 +187,7 @@ impl<E> Clone for RpcState<E> {
installed_filters: self.installed_filters.clone(),
connection_pool: self.connection_pool.clone(),
tx_sender: self.tx_sender.clone(),
tree_api: self.tree_api.clone(),
sync_state: self.sync_state.clone(),
api_config: self.api_config.clone(),
last_sealed_miniblock: self.last_sealed_miniblock.clone(),
Expand Down
1 change: 1 addition & 0 deletions core/lib/zksync_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1364,6 +1364,7 @@ async fn run_ws_api<G: L1GasPriceProvider + Send + Sync + 'static>(
)
.with_polling_interval(api_config.web3_json_rpc.pubsub_interval())
.with_threads(api_config.web3_json_rpc.ws_server_threads())
.with_tree_api(api_config.web3_json_rpc.tree_api_url())
.with_tx_sender(tx_sender, vm_barrier)
.enable_api_namespaces(Namespace::NON_DEBUG.to_vec());

Expand Down