Skip to content

Commit

Permalink
Merge pull request #1803 from matter-labs/perekopskiy-zks-755-impleme…
Browse files Browse the repository at this point in the history
…nt-eth_call-for-ethereum-like

Implement `eth_call` for ethereum like json rpc
  • Loading branch information
perekopskiy authored Aug 19, 2021
2 parents af92b45 + 603da76 commit a538d72
Show file tree
Hide file tree
Showing 22 changed files with 1,476 additions and 110 deletions.
5 changes: 5 additions & 0 deletions core/bin/zksync_api/src/api_server/rest/v02/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use thiserror::Error;

// Workspace uses
use zksync_api_types::v02::pagination::{UnknownFromParameter, MAX_LIMIT};
use zksync_crypto::params::MIN_NFT_TOKEN_ID;

// Local uses
use crate::{api_server::tx_sender::SubmitError, fee_ticker::PriceError};
Expand All @@ -25,6 +26,7 @@ pub enum ErrorCode {
TransactionNotFound = 205,
PaginationLimitTooBig = 206,
QueryDeserializationError = 207,
InvalidNFTTokenId = 208,
StorageError = 300,
TokenNotFound = 500,
ExternalApiError = 501,
Expand Down Expand Up @@ -98,6 +100,8 @@ pub enum InvalidDataError {
TransactionNotFound,
#[error("Limit for pagination should be less than or equal to {}", MAX_LIMIT)]
PaginationLimitTooBig,
#[error("NFT token ID should be greater than or equal to {}", MIN_NFT_TOKEN_ID)]
InvalidNFTTokenId,
}

impl ApiError for InvalidDataError {
Expand All @@ -114,6 +118,7 @@ impl ApiError for InvalidDataError {
Self::InvalidCurrency => ErrorCode::InvalidCurrency,
Self::TransactionNotFound => ErrorCode::TransactionNotFound,
Self::PaginationLimitTooBig => ErrorCode::PaginationLimitTooBig,
Self::InvalidNFTTokenId => ErrorCode::InvalidNFTTokenId,
}
}
}
Expand Down
43 changes: 39 additions & 4 deletions core/bin/zksync_api/src/api_server/rest/v02/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ use zksync_api_types::v02::{
token::{ApiNFT, ApiToken, TokenPrice},
};
use zksync_config::ZkSyncConfig;
use zksync_crypto::params::MIN_NFT_TOKEN_ID;
use zksync_storage::{ConnectionPool, StorageProcessor};
use zksync_types::{Token, TokenId, TokenLike};
use zksync_types::{AccountId, Token, TokenId, TokenLike};

// Local uses
use super::{
Expand Down Expand Up @@ -249,6 +250,9 @@ async fn get_nft(
data: web::Data<ApiTokenData>,
id: web::Path<TokenId>,
) -> ApiResult<Option<ApiNFT>> {
if id.0 < MIN_NFT_TOKEN_ID {
return Error::from(InvalidDataError::InvalidNFTTokenId).into();
}
let mut storage = api_try!(data.pool.access_storage().await.map_err(Error::storage));
let nft = api_try!(storage
.tokens_schema()
Expand All @@ -258,6 +262,23 @@ async fn get_nft(
ApiResult::Ok(nft)
}

async fn get_nft_owner(
data: web::Data<ApiTokenData>,
id: web::Path<TokenId>,
) -> ApiResult<Option<AccountId>> {
if id.0 < MIN_NFT_TOKEN_ID {
return Error::from(InvalidDataError::InvalidNFTTokenId).into();
}
let mut storage = api_try!(data.pool.access_storage().await.map_err(Error::storage));
let owner_id = api_try!(storage
.chain()
.account_schema()
.get_nft_owner(*id)
.await
.map_err(Error::storage));
ApiResult::Ok(owner_id)
}

pub fn api_scope(
config: &ZkSyncConfig,
pool: ConnectionPool,
Expand All @@ -278,6 +299,7 @@ pub fn api_scope(
web::get().to(token_price),
)
.route("nft/{id}", web::get().to(get_nft))
.route("nft/{id}/owner", web::get().to(get_nft_owner))
}

#[cfg(test)]
Expand Down Expand Up @@ -421,10 +443,23 @@ mod tests {
let response = client.token_price(&token_like, "333").await?;
assert!(response.error.is_some());

let id = TokenId(65542);
let response = client.nft_by_id(id).await?;
let nft_id = TokenId(65542);
let response = client.nft_by_id(nft_id).await?;
let nft: ApiNFT = deserialize_response_result(response)?;
assert_eq!(nft.id, id);
assert_eq!(nft.id, nft_id);

let response = client.nft_owner_by_id(nft_id).await?;
let owner_id: AccountId = deserialize_response_result(response)?;
let expected_owner_id = {
let mut storage = cfg.pool.access_storage().await?;
storage
.chain()
.account_schema()
.get_nft_owner(nft_id)
.await?
.unwrap()
};
assert_eq!(owner_id, expected_owner_id);

server.stop().await;
Ok(())
Expand Down
24 changes: 23 additions & 1 deletion core/bin/zksync_api/src/api_server/rpc_server/rpc_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ use zksync_api_types::{
v02::{fee::ApiTxFeeTypes, token::ApiNFT},
TxWithSignature,
};
use zksync_crypto::params::MIN_NFT_TOKEN_ID;
use zksync_types::{
tx::{EthBatchSignatures, TxEthSignatureVariant, TxHash},
Address, Fee, Token, TokenId, TokenLike, TotalFee, TxFeeTypes, ZkSyncTx,
AccountId, Address, Fee, Token, TokenId, TokenLike, TotalFee, TxFeeTypes, ZkSyncTx,
};
// Local uses
use crate::{api_server::tx_sender::SubmitError, fee_ticker::TokenPriceRequestType};
Expand Down Expand Up @@ -291,4 +292,25 @@ impl RpcApp {
metrics::histogram!("api.rpc.get_eth_tx_for_withdrawal", start.elapsed());
result
}

pub async fn _impl_get_nft_owner(self, id: TokenId) -> Result<Option<AccountId>> {
let start = Instant::now();
let owner_id = if id.0 < MIN_NFT_TOKEN_ID {
None
} else {
let mut storage = self.access_storage().await?;
storage
.chain()
.account_schema()
.get_nft_owner(id)
.await
.map_err(|err| {
vlog::warn!("Internal Server Error: '{}'; input: N/A", err);
Error::internal_error()
})?
};

metrics::histogram!("api.rpc.get_nft_owner", start.elapsed());
Ok(owner_id)
}
}
9 changes: 8 additions & 1 deletion core/bin/zksync_api/src/api_server/rpc_server/rpc_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use zksync_api_types::{
use zksync_crypto::params::ZKSYNC_VERSION;
use zksync_types::{
tx::{EthBatchSignatures, TxEthSignatureVariant, TxHash},
Address, Fee, Token, TokenId, TokenLike, TotalFee, ZkSyncTx,
AccountId, Address, Fee, Token, TokenId, TokenLike, TotalFee, ZkSyncTx,
};

// Local uses
Expand Down Expand Up @@ -93,6 +93,9 @@ pub trait Rpc {

#[rpc(name = "get_nft", returns = "Option<ApiNFT>")]
fn get_nft(&self, id: TokenId) -> BoxFutureResult<Option<ApiNFT>>;

#[rpc(name = "get_nft_owner", returns = "Option<AccountId>")]
fn get_nft_owner(&self, id: TokenId) -> BoxFutureResult<Option<AccountId>>;
}

impl Rpc for RpcApp {
Expand Down Expand Up @@ -173,4 +176,8 @@ impl Rpc for RpcApp {
fn get_nft(&self, id: TokenId) -> BoxFutureResult<Option<ApiNFT>> {
spawn!(self._impl_get_nft(id))
}

fn get_nft_owner(&self, id: TokenId) -> BoxFutureResult<Option<AccountId>> {
spawn!(self._impl_get_nft_owner(id))
}
}
Loading

0 comments on commit a538d72

Please sign in to comment.