Skip to content

Commit

Permalink
Merge #1745
Browse files Browse the repository at this point in the history
1745: Implement architecture for ethereum like jsonrpc r=Deniallugo a=perekopskiy



Co-authored-by: perekopskiy <[email protected]>
Co-authored-by: Mykhailo Perekopskyi <[email protected]>
Co-authored-by: Mykhailo Perekopskyi <[email protected]>
Co-authored-by: perekopskiy <[email protected]>
Co-authored-by: Danil <[email protected]>
Co-authored-by: bors-zksync-dev[bot] <76108001+bors-zksync-dev[bot]@users.noreply.github.com>
  • Loading branch information
5 people authored Aug 19, 2021
2 parents 65580af + c6716d6 commit fbbc3e5
Show file tree
Hide file tree
Showing 61 changed files with 6,976 additions and 275 deletions.
190 changes: 132 additions & 58 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"core/bin/prover",
"core/bin/parse_pub_data",
"core/bin/block_revert",
"core/bin/mint_nft_nonce_migration",

# Server micro-services
"core/bin/zksync_api",
Expand Down
4 changes: 2 additions & 2 deletions core/bin/data_restore/src/inmemory_storage_interactor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ impl InMemoryStorageInteractor {
account.nonce = max(account.nonce, *new_nonce);
account.pub_key_hash = *new_pub_key_hash;
}
AccountUpdate::MintNFT { ref token } => {
AccountUpdate::MintNFT { ref token, .. } => {
self.tokens.insert(
token.id,
Token {
Expand All @@ -280,7 +280,7 @@ impl InMemoryStorageInteractor {
},
);
}
AccountUpdate::RemoveNFT { ref token } => {
AccountUpdate::RemoveNFT { ref token, .. } => {
self.tokens.remove(&token.id);
}
}
Expand Down
19 changes: 19 additions & 0 deletions core/bin/mint_nft_nonce_migration/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "mint_nft_nonce_migration"
version = "1.0.0"
edition = "2018"
authors = ["The Matter Labs Team <[email protected]>"]
homepage = "https://zksync.io/"
repository = "https://github.com/matter-labs/zksync"
license = "Apache-2.0"
keywords = ["blockchain", "zksync"]
categories = ["cryptography"]
publish = false # We don't want to publish our binaries.

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
zksync_storage = { path = "../../lib/storage", version = "1.0" }
zksync_config = { path = "../../lib/config", version = "1.0" }
tokio = { version = "0.2", features = ["full"] }
anyhow = "1.0"
13 changes: 13 additions & 0 deletions core/bin/mint_nft_nonce_migration/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use zksync_storage::StorageProcessor;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut storage = StorageProcessor::establish_connection().await?;
storage
.chain()
.state_schema()
.mint_nft_updates_set_nonces()
.await?;

Ok(())
}
7 changes: 5 additions & 2 deletions core/bin/zksync_api/src/api_server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ mod rest;
pub mod rpc_server;
mod rpc_subscriptions;
mod tx_sender;
mod web3;

/// Amount of threads used by each server to serve requests.
const THREADS_PER_SERVER: usize = 128;
Expand Down Expand Up @@ -68,10 +69,12 @@ pub fn start_api_server(
);

rpc_server::start_rpc_server(
connection_pool,
connection_pool.clone(),
sign_check_sender,
ticker_request_sender,
panic_notify,
panic_notify.clone(),
config,
);

web3::start_rpc_server(connection_pool, panic_notify, config);
}
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 @@ -99,6 +101,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 @@ -115,6 +119,7 @@ impl ApiError for InvalidDataError {
Self::InvalidCurrency => ErrorCode::InvalidCurrency,
Self::TransactionNotFound => ErrorCode::TransactionNotFound,
Self::PaginationLimitTooBig => ErrorCode::PaginationLimitTooBig,
Self::InvalidNFTTokenId => ErrorCode::InvalidNFTTokenId,
}
}
}
Expand Down
50 changes: 42 additions & 8 deletions core/bin/zksync_api/src/api_server/rest/v02/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use tokio::sync::Mutex;
use zksync_api_client::rest::client::Client;
use zksync_api_types::v02::Response;
use zksync_config::ZkSyncConfig;
use zksync_crypto::rand::{SeedableRng, XorShiftRng};
use zksync_crypto::rand::{Rng, SeedableRng, XorShiftRng};
use zksync_storage::{
chain::operations::records::NewExecutedPriorityOperation,
chain::operations::OperationsSchema,
Expand All @@ -37,9 +37,10 @@ use zksync_types::{
operations::{ChangePubKeyOp, TransferToNewOp},
prover::ProverJobType,
tx::ChangePubKeyType,
AccountId, AccountMap, Address, BatchFee, BlockNumber, Deposit, DepositOp, ExecutedOperations,
ExecutedPriorityOp, ExecutedTx, Fee, FullExit, FullExitOp, MintNFTOp, Nonce, OutputFeeType,
PriorityOp, Token, TokenId, TokenLike, Transfer, TransferOp, ZkSyncOp, ZkSyncTx, H256,
AccountId, AccountMap, AccountUpdate, Address, BatchFee, BlockNumber, Deposit, DepositOp,
ExecutedOperations, ExecutedPriorityOp, ExecutedTx, Fee, FullExit, FullExitOp, MintNFTOp,
Nonce, OutputFeeType, PriorityOp, Token, TokenId, TokenLike, Transfer, TransferOp, ZkSyncOp,
ZkSyncTx, H256, NFT,
};

// Local uses
Expand Down Expand Up @@ -395,6 +396,7 @@ impl TestServerConfig {
*account_id,
account,
block_number.0 * accounts.len() as u32 + id as u32,
&mut rng,
));
});
apply_updates(&mut accounts, updates.clone());
Expand All @@ -412,6 +414,34 @@ impl TestServerConfig {
vec![]
};

let mut mint_nft_updates = Vec::new();
for (i, tx) in txs.iter().enumerate() {
if let Some(tx) = tx.get_executed_tx() {
if let ZkSyncTx::MintNFT(tx) = &tx.signed_tx.tx {
let nft_address: Address = rng.gen::<[u8; 20]>().into();
let content_hash: H256 = rng.gen::<[u8; 32]>().into();
let token = NFT::new(
TokenId(80000 + block_number.0 * 100 + i as u32),
0,
tx.creator_id,
tx.creator_address,
nft_address,
None,
content_hash,
);
let update = (
tx.creator_id,
AccountUpdate::MintNFT {
token,
nonce: Nonce(0),
},
);
mint_nft_updates.push(update);
}
}
}
updates.extend(mint_nft_updates);

storage
.chain()
.block_schema()
Expand Down Expand Up @@ -608,7 +638,7 @@ impl TestServerConfig {
block_number: 2,
block_index: 2,
operation: serde_json::to_value(
dummy_deposit_op(Address::default(), AccountId(1), VERIFIED_OP_SERIAL_ID, 2).op,
dummy_deposit_op(Address::default(), AccountId(3), VERIFIED_OP_SERIAL_ID, 2).op,
)
.unwrap(),
from_account: Default::default(),
Expand All @@ -621,14 +651,16 @@ impl TestServerConfig {
eth_block: 10,
created_at: chrono::Utc::now(),
eth_block_index: Some(1),
tx_hash: Default::default(),
tx_hash: dummy_ethereum_tx_hash(VERIFIED_OP_SERIAL_ID as i64)
.as_bytes()
.to_vec(),
},
// Committed priority operation.
NewExecutedPriorityOperation {
block_number: EXECUTED_BLOCKS_COUNT as i64 + 1,
block_index: 1,
operation: serde_json::to_value(
dummy_full_exit_op(AccountId(1), Address::default(), COMMITTED_OP_SERIAL_ID, 3)
dummy_full_exit_op(AccountId(3), Address::default(), COMMITTED_OP_SERIAL_ID, 3)
.op,
)
.unwrap(),
Expand All @@ -642,7 +674,9 @@ impl TestServerConfig {
eth_block: 14,
created_at: chrono::Utc::now(),
eth_block_index: Some(1),
tx_hash: Default::default(),
tx_hash: dummy_ethereum_tx_hash(COMMITTED_OP_SERIAL_ID as i64)
.as_bytes()
.to_vec(),
},
];

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)
}
}
13 changes: 10 additions & 3 deletions 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,15 +93,18 @@ 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 {
fn account_info(&self, addr: Address) -> BoxFutureResult<AccountInfoResp> {
spawn! {self._impl_account_info(addr)}
spawn!(self._impl_account_info(addr))
}

fn ethop_info(&self, serial_id: u32) -> BoxFutureResult<ETHOpInfoResp> {
spawn! {self._impl_ethop_info(serial_id)}
spawn!(self._impl_ethop_info(serial_id))
}

fn tx_info(&self, hash: TxHash) -> BoxFutureResult<TransactionInfoResp> {
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 fbbc3e5

Please sign in to comment.