Skip to content

Commit

Permalink
Merge branch 'dev' into sb-fix-v1-lint
Browse files Browse the repository at this point in the history
  • Loading branch information
StanislavBreadless authored Dec 7, 2021
2 parents c279d57 + b7d473f commit 889560e
Show file tree
Hide file tree
Showing 22 changed files with 1,234 additions and 325 deletions.
116 changes: 116 additions & 0 deletions core/bin/zksync_core/src/genesis.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use std::time::Instant;

// External uses
// Workspace uses
use zksync_crypto::{
ff,
params::{MIN_NFT_TOKEN_ID, NFT_STORAGE_ACCOUNT_ADDRESS, NFT_STORAGE_ACCOUNT_ID, NFT_TOKEN_ID},
};
use zksync_state::state::ZkSyncState;
use zksync_storage::ConnectionPool;
use zksync_types::{Account, AccountId, AccountUpdate, Address, BlockNumber, Token, TokenKind};
// Local uses

pub async fn create_genesis_block(pool: ConnectionPool, fee_account_address: &Address) {
let start = Instant::now();
let mut storage = pool
.access_storage()
.await
.expect("db connection failed for statekeeper");
let mut transaction = storage
.start_transaction()
.await
.expect("unable to create db transaction in statekeeper");

let (last_committed, mut accounts) = transaction
.chain()
.state_schema()
.load_committed_state(None)
.await
.expect("db failed");

assert!(
*last_committed == 0 && accounts.is_empty(),
"db should be empty"
);

vlog::info!("Adding special token");
transaction
.tokens_schema()
.store_token(Token::new(
NFT_TOKEN_ID,
*NFT_STORAGE_ACCOUNT_ADDRESS,
"SPECIAL",
18,
TokenKind::NFT,
))
.await
.expect("failed to store special token");
vlog::info!("Special token added");

let fee_account = Account::default_with_address(fee_account_address);
let db_create_fee_account = AccountUpdate::Create {
address: *fee_account_address,
nonce: fee_account.nonce,
};
accounts.insert(AccountId(0), fee_account);

let (mut special_account, db_create_special_account) =
Account::create_account(NFT_STORAGE_ACCOUNT_ID, *NFT_STORAGE_ACCOUNT_ADDRESS);
special_account.set_balance(NFT_TOKEN_ID, num::BigUint::from(MIN_NFT_TOKEN_ID));
let db_set_special_account_balance = AccountUpdate::UpdateBalance {
old_nonce: special_account.nonce,
new_nonce: special_account.nonce,
balance_update: (
NFT_TOKEN_ID,
num::BigUint::from(0u64),
num::BigUint::from(MIN_NFT_TOKEN_ID),
),
};
accounts.insert(NFT_STORAGE_ACCOUNT_ID, special_account);

transaction
.chain()
.state_schema()
.commit_state_update(
BlockNumber(0),
&[
(AccountId(0), db_create_fee_account),
db_create_special_account[0].clone(),
(NFT_STORAGE_ACCOUNT_ID, db_set_special_account_balance),
],
0,
)
.await
.expect("db fail");
transaction
.chain()
.state_schema()
.apply_state_update(BlockNumber(0))
.await
.expect("db fail");

let state = ZkSyncState::from_acc_map(accounts, last_committed + 1);
let root_hash = state.root_hash();
transaction
.chain()
.block_schema()
.save_genesis_block(root_hash)
.await
.expect("db fail");

transaction
.commit()
.await
.expect("Unable to commit transaction in statekeeper");
vlog::info!("Genesis block created, state: {}", state.root_hash());

// Below we are intentionally using `println`, because during genesis we parse the genesis root from
// the server output in order to save it into the config file.
// See `server.genesis()` in the `zk` tool for details.
// TODO: Find a better and a more intuitive approach (ZKS-816).
let genesis_root = format!("CONTRACTS_GENESIS_ROOT=0x{}", ff::to_hex(&root_hash));
println!("{}", &genesis_root);

metrics::histogram!("state_keeper.create_genesis_block", start.elapsed());
}
5 changes: 3 additions & 2 deletions core/bin/zksync_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub mod state_keeper;
pub mod token_handler;
pub mod tx_event_emitter;

mod genesis;

/// Waits for any of the tokio tasks to be finished.
/// Since the main tokio tasks are used as actors which should live as long
/// as application runs, any possible outcome (either `Ok` or `Err`) is considered
Expand All @@ -53,8 +55,7 @@ pub async fn genesis_init(config: &ChainConfig) {
let pool = ConnectionPool::new(Some(1));

vlog::info!("Generating genesis block.");
ZkSyncStateKeeper::create_genesis_block(pool.clone(), &config.state_keeper.fee_account_addr)
.await;
genesis::create_genesis_block(pool.clone(), &config.state_keeper.fee_account_addr).await;
vlog::info!("Adding initial tokens to db");
let genesis_tokens = get_genesis_token_list(&config.eth.network.to_string())
.expect("Initial token list not found");
Expand Down
150 changes: 10 additions & 140 deletions core/bin/zksync_core/src/state_keeper/init_params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use zksync_types::{
BlockNumber, TokenId, NFT,
};

use super::state_restore::{db::StateRestoreStorage, RestoredTree};

#[derive(Debug, Clone)]
pub struct ZkSyncStateInitParams {
pub tree: AccountTree,
Expand Down Expand Up @@ -71,119 +73,21 @@ impl ZkSyncStateInitParams {
async fn load_account_tree(
&mut self,
storage: &mut zksync_storage::StorageProcessor<'_>,
) -> Result<BlockNumber, anyhow::Error> {
let (last_cached_block_number, accounts) = if let Some((block, _)) = storage
.chain()
.block_schema()
.get_account_tree_cache()
.await?
{
storage
.chain()
.state_schema()
.load_committed_state(Some(block))
.await?
} else {
storage.chain().state_schema().load_verified_state().await?
};

for (id, account) in accounts {
self.insert_account(id, account);
}

if let Some(account_tree_cache) = storage
.chain()
.block_schema()
.get_account_tree_cache_block(last_cached_block_number)
.await?
{
self.tree
.set_internals(serde_json::from_value(account_tree_cache)?);
} else {
self.tree.root_hash();
let account_tree_cache = self.tree.get_internals();
storage
.chain()
.block_schema()
.store_account_tree_cache(
last_cached_block_number,
serde_json::to_value(account_tree_cache)?,
)
.await?;
}

let (block_number, accounts) = storage
.chain()
.state_schema()
.load_committed_state(None)
.await
.map_err(|e| anyhow::format_err!("couldn't load committed state: {}", e))?;

if block_number != last_cached_block_number {
if let Some((_, account_updates)) = storage
.chain()
.state_schema()
.load_state_diff(last_cached_block_number, Some(block_number))
.await?
{
let mut updated_accounts = account_updates
.into_iter()
.map(|(id, _)| id)
.collect::<Vec<_>>();
updated_accounts.sort_unstable();
updated_accounts.dedup();
for idx in updated_accounts {
if let Some(acc) = accounts.get(&idx).cloned() {
self.insert_account(idx, acc);
} else {
self.remove_account(idx);
}
}
}
}

// We have to load actual number of the last committed block, since above we load the block number from state,
// and in case of empty block being sealed (that may happen because of bug).
// Note that if this block is greater than the `block_number`, it means that some empty blocks were committed,
// so the root hash has not changed and we don't need to update the tree in order to get the right root hash.
let last_actually_committed_block_number = storage
.chain()
.block_schema()
.get_last_saved_block()
.await?;

let block_number = std::cmp::max(last_actually_committed_block_number, block_number);

if *block_number != 0 {
let storage_root_hash = storage
.chain()
.block_schema()
.get_block(block_number)
.await?
.expect("restored block must exist");

let root_hash_db = storage_root_hash.new_root_hash;
let root_hash_calculated = self.tree.root_hash();
if root_hash_calculated != root_hash_db {
panic!(
"Restored root_hash is different. \n \
Root hash from the database: {:?} \n \
Root hash from that was calculated: {:?} \n
Current block number: {}",
root_hash_db, root_hash_calculated, block_number
);
}
}

Ok(block_number)
) -> BlockNumber {
let mut restored_tree = RestoredTree::new(StateRestoreStorage::new(storage));
let last_block_number = restored_tree.restore().await;
self.tree = restored_tree.tree;
self.acc_id_by_addr = restored_tree.acc_id_by_addr;
last_block_number
}

async fn load_from_db(
&mut self,
storage: &mut zksync_storage::StorageProcessor<'_>,
) -> Result<(), anyhow::Error> {
let block_number = self.load_account_tree(storage).await?;
let block_number = self.load_account_tree(storage).await;
self.last_block_number = block_number;

self.unprocessed_priority_op =
Self::unprocessed_priority_op_id(storage, block_number).await?;
self.nfts = Self::load_nft_tokens(storage, block_number).await?;
Expand All @@ -196,45 +100,11 @@ impl ZkSyncStateInitParams {
Ok(())
}

pub async fn load_state_diff(
&mut self,
storage: &mut zksync_storage::StorageProcessor<'_>,
) -> Result<(), anyhow::Error> {
let state_diff = storage
.chain()
.state_schema()
.load_state_diff(self.last_block_number, None)
.await
.map_err(|e| anyhow::format_err!("failed to load committed state: {}", e))?;

if let Some((block_number, updates)) = state_diff {
for (id, update) in updates.into_iter() {
let updated_account = Account::apply_update(self.remove_account(id), update);
if let Some(account) = updated_account {
self.insert_account(id, account);
}
}
self.unprocessed_priority_op =
Self::unprocessed_priority_op_id(storage, block_number).await?;
self.last_block_number = block_number;
}
Ok(())
}

pub fn insert_account(&mut self, id: AccountId, acc: Account) {
self.acc_id_by_addr.insert(acc.address, id);
self.tree.insert(*id, acc);
}

pub fn remove_account(&mut self, id: AccountId) -> Option<Account> {
if let Some(acc) = self.tree.remove(*id) {
self.acc_id_by_addr.remove(&acc.address);
Some(acc)
} else {
None
}
}

async fn load_nft_tokens(
storage: &mut zksync_storage::StorageProcessor<'_>,
block_number: BlockNumber,
Expand Down
Loading

0 comments on commit 889560e

Please sign in to comment.