Skip to content

Commit

Permalink
Merge #2243
Browse files Browse the repository at this point in the history
2243: Add gas cost to testkit about pending withdraw r=Deniallugo a=Deniallugo

Signed-off-by: deniallugo <deniallugo@gmail.com>

Co-authored-by: deniallugo <deniallugo@gmail.com>
  • Loading branch information
bors-matterlabs-dev[bot] and Deniallugo committed May 13, 2022
2 parents 3115e15 + 7116f73 commit b37da6f
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 5 deletions.
45 changes: 45 additions & 0 deletions contracts/contracts/dev-contracts/PendingBalanceWithdrawer.sol
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.7.0;

pragma experimental ABIEncoderV2;

import "../ZkSync.sol";

contract PendingBalanceWithdrawer {
ZkSync immutable zkSync;

struct RequestWithdrawFT {
address payable owner;
address token;
uint256 gas;
}

struct RequestWithdrawNFT {
uint32 tokenId;
uint256 gas;
}

constructor(address _zkSync) {
zkSync = ZkSync(_zkSync);
}

function withdrawPendingBalances(
RequestWithdrawFT[] calldata _FTRequests,
RequestWithdrawNFT[] calldata _NFTRequests
) external {
for (uint256 i = 0; i < _FTRequests.length; ++i) {
try
zkSync.withdrawPendingBalance{gas: _FTRequests[i].gas}(
_FTRequests[i].owner,
_FTRequests[i].token,
type(uint128).max
)
{} catch {}
}

for (uint256 i = 0; i < _NFTRequests.length; ++i) {
try zkSync.withdrawPendingNFTBalance{gas: _NFTRequests[i].gas}(_NFTRequests[i].tokenId) {} catch {}
}
}
}
7 changes: 7 additions & 0 deletions contracts/scripts/deploy-testkit.ts
Expand Up @@ -58,6 +58,13 @@ async function main() {
const testWallet = Wallet.fromMnemonic(ethTestConfig.test_mnemonic, "m/44'/60'/0'/0/" + i).connect(provider);
await (await erc20.mint(testWallet.address, '0x4B3B4CA85A86C47A098A224000000000')).wait();
}
const pendingWithdrawer = await deployContract(
deployWallet,
readContractCode('dev-contracts/PendingBalanceWithdrawer'),
[deployer.addresses.ZkSync],
{ gasLimit: 5000000 }
);
console.log(`CONTRACTS_PENDING_BALANCE_WITHDRAWER=${pendingWithdrawer.address}`);
}

main()
Expand Down
18 changes: 16 additions & 2 deletions core/tests/testkit/src/bin/gas_price_test.rs
Expand Up @@ -47,6 +47,8 @@ struct CostsSample {
verify_cost: BigInt,
/// Operator withdrawal gas cost
withdrawals_cost: BigInt,
/// Pending withdrawer withdrawal gas cost
pending_withdrawals_cost: BigInt,
}

impl CostsSample {
Expand All @@ -64,6 +66,14 @@ impl CostsSample {
.gas_used
.map(u256_to_bigint)
.expect("verify gas used"),
pending_withdrawals_cost: block_result
.pending_withdrawals_result
.map(|rec| {
rec.gas_used
.map(u256_to_bigint)
.expect("pending withdrawals gas used")
})
.unwrap_or_default(),
withdrawals_cost: block_result
.withdrawals_result
.gas_used
Expand All @@ -80,13 +90,15 @@ impl CostsSample {
let commit_cost = (&self.commit_cost - &base_cost.base_commit_cost) / samples;
let verify_cost = (&self.verify_cost - &base_cost.base_verify_cost) / samples;
let withdraw_cost = (&self.withdrawals_cost - &base_cost.base_withdraw_cost) / samples;
let total = &commit_cost + &verify_cost + &withdraw_cost;
let pending_withdraw_cost = &self.pending_withdrawals_cost / samples;
let total = &commit_cost + &verify_cost + &withdraw_cost + &pending_withdraw_cost;

CostPerOperation {
user_gas_cost,
commit_cost,
verify_cost,
withdraw_cost,
pending_withdraw_cost,
total,
}
}
Expand All @@ -110,6 +122,7 @@ struct CostPerOperation {
commit_cost: BigInt,
verify_cost: BigInt,
withdraw_cost: BigInt,
pending_withdraw_cost: BigInt,
total: BigInt,
}

Expand Down Expand Up @@ -139,12 +152,13 @@ impl CostPerOperation {
String::new()
};
println!(
"Gas cost of {}:\nuser_gas_cost: {}\ncommit: {}\nprove: {}\nexecute: {}\ntotal: {}{}",
"Gas cost of {}:\nuser_gas_cost: {}\ncommit: {}\nprove: {}\nexecute: {}\npending_withdraw: {}\ntotal: {}{}",
description,
self.user_gas_cost,
self.commit_cost,
self.verify_cost,
self.withdraw_cost,
self.pending_withdraw_cost,
self.total,
grief_info
);
Expand Down
66 changes: 64 additions & 2 deletions core/tests/testkit/src/eth_account.rs
@@ -1,7 +1,8 @@
use crate::external_commands::js_revert_reason;
use std::collections::HashMap;

use anyhow::{bail, ensure, format_err};
use ethabi::Token;
use ethabi::{Contract, Token, Uint};
use num::{BigUint, ToPrimitive};
use std::convert::TryFrom;
use std::str::FromStr;
Expand All @@ -18,7 +19,7 @@ use zksync_types::aggregated_operations::{
stored_block_info, BlocksCommitOperation, BlocksExecuteOperation, BlocksProofOperation,
};
use zksync_types::block::Block;
use zksync_types::{AccountId, Address, Nonce, PriorityOp, PubKeyHash, TokenId};
use zksync_types::{AccountId, Address, Nonce, PriorityOp, PubKeyHash, TokenId, ZkSyncTx};

pub fn parse_ether(eth_value: &str) -> Result<BigUint, anyhow::Error> {
let split = eth_value.split('.').collect::<Vec<&str>>();
Expand Down Expand Up @@ -429,6 +430,67 @@ impl EthereumAccount {
Ok(ETHExecResult::new(receipt, &self.main_contract_eth_client).await)
}

// Completes pending withdrawals.
pub async fn execute_pending_withdrawals(
&self,
execute_operation: &BlocksExecuteOperation,
tokens: &HashMap<TokenId, Address>,
pending_withdrawer_contract: &(Contract, Address),
) -> Result<Option<ETHExecResult>, anyhow::Error> {
let ex_ops: Vec<_> = execute_operation
.blocks
.iter()
.flat_map(|b| {
b.block_transactions.iter().filter(|a| {
a.is_successful()
&& (a.variance_name() == "Withdraw" || a.variance_name() == "WithdrawNFT")
})
})
.collect();
let mut ft_balances = vec![];
let mut nft_balances = vec![];
for ex_op in ex_ops {
let ex_op = ex_op.get_executed_tx().unwrap().signed_tx.clone().tx;
match ex_op {
ZkSyncTx::Withdraw(tx) => ft_balances.push(Token::Tuple(vec![
Token::Address(tx.to),
Token::Address(*tokens.get(&tx.token).unwrap()),
Token::Uint(Uint::from(200_000)),
])),
ZkSyncTx::WithdrawNFT(tx) => nft_balances.push(Token::Tuple(vec![
Token::Uint(Uint::from_str(&tx.token.0.to_string()).unwrap()),
Token::Uint(Uint::from(300_000)),
])),
_ => unreachable!(),
};
}

if ft_balances.is_empty() && nft_balances.is_empty() {
return Ok(None);
}

let f = pending_withdrawer_contract
.0
.function("withdrawPendingBalances")
.expect("failed to get function parameters");

let tokens = vec![Token::Array(ft_balances), Token::Array(nft_balances)];
let data = f
.encode_input(&tokens)
.expect("failed to encode parameters");
let signed_tx = self
.main_contract_eth_client
.sign_prepared_tx_for_addr(data, pending_withdrawer_contract.1, Options::default())
.await
.map_err(|e| format_err!("Complete withdrawals send err: {}", e))?;

let receipt =
send_raw_tx_wait_confirmation(&self.main_contract_eth_client, signed_tx.raw_tx).await?;
Ok(Some(
ETHExecResult::new(receipt, &self.main_contract_eth_client).await,
))
}

pub async fn revert_blocks(&self, blocks: &[Block]) -> Result<ETHExecResult, anyhow::Error> {
let tx_arg = Token::Array(blocks.iter().map(stored_block_info).collect());

Expand Down
23 changes: 23 additions & 0 deletions core/tests/testkit/src/external_commands.rs
Expand Up @@ -2,11 +2,13 @@
//! `zk` script should be in path.
//!
use std::collections::HashMap;
use std::fs::read;
use std::process::Command;
use std::str::FromStr;
use web3::types::{Address, H256};

use serde::{Deserialize, Serialize};
use serde_json::Value;
use zksync_crypto::convert::FeConvert;
use zksync_crypto::Fr;

Expand All @@ -17,6 +19,7 @@ pub struct Contracts {
pub contract: Address,
pub upgrade_gatekeeper: Address,
pub test_erc20_address: Address,
pub pending_withdrawer: (ethabi::Contract, Address),
}

fn get_contract_address(deploy_script_out: &str) -> Option<(String, Address)> {
Expand All @@ -42,6 +45,13 @@ fn get_contract_address(deploy_script_out: &str) -> Option<(String, Address)> {
String::from("CONTRACTS_UPGRADE_GATEKEEPER_ADDR"),
Address::from_str(output).expect("can't parse contract address"),
))
} else if let Some(output) =
deploy_script_out.strip_prefix("CONTRACTS_PENDING_BALANCE_WITHDRAWER=0x")
{
Some((
String::from("CONTRACTS_PENDING_BALANCE_WITHDRAWER"),
Address::from_str(output).expect("can't parse contract address"),
))
} else {
deploy_script_out
.strip_prefix("CONTRACTS_TEST_ERC20=0x")
Expand All @@ -54,6 +64,13 @@ fn get_contract_address(deploy_script_out: &str) -> Option<(String, Address)> {
}
}

fn pending_withdrawer_contract() -> ethabi::Contract {
let path = "contracts/artifacts/cache/solpp-generated-contracts/dev-contracts/PendingBalanceWithdrawer.sol/PendingBalanceWithdrawer.json";
let pending_withdrawer_abi: Value =
serde_json::from_slice(read(path).unwrap().as_slice()).unwrap();
serde_json::from_value(pending_withdrawer_abi.get("abi").unwrap().clone()).unwrap()
}

/// Runs external command and returns stdout output
fn run_external_command(command: &str, args: &[&str]) -> String {
let result = Command::new(command)
Expand Down Expand Up @@ -120,6 +137,12 @@ pub fn deploy_contracts(use_prod_contracts: bool, genesis_root: Fr) -> Contracts
test_erc20_address: contracts
.remove("CONTRACTS_TEST_ERC20")
.expect("TEST_ERC20 missing"),
pending_withdrawer: (
pending_withdrawer_contract(),
contracts
.remove("CONTRACTS_PENDING_BALANCE_WITHDRAWER")
.expect("CONTRACTS_PENDING_BALANCE_WITHDRAWER missing"),
),
}
}

Expand Down
15 changes: 14 additions & 1 deletion core/tests/testkit/src/test_setup.rs
Expand Up @@ -48,6 +48,7 @@ pub struct TestSetup {

pub accounts: AccountSet,
pub tokens: HashMap<TokenId, Address>,
pub deployed_contracts: Contracts,

pub expected_changes_for_current_block: ExpectedAccountState,

Expand Down Expand Up @@ -94,6 +95,7 @@ impl TestSetup {
processed_tx_events_receiver: sk_channels.queued_txs_events,
accounts,
tokens,
deployed_contracts: deployed_contracts.clone(),
expected_changes_for_current_block: ExpectedAccountState::default(),
commit_account,
current_state_root: Some(initial_root),
Expand Down Expand Up @@ -996,6 +998,7 @@ impl TestSetup {
.await
.expect("block commit send tx")
.expect_success();

self.last_committed_block = new_block.clone();

new_block
Expand Down Expand Up @@ -1081,7 +1084,6 @@ impl TestSetup {
.send(StateKeeperTestkitRequest::SealBlock)
.await
.expect("sk receiver dropped");

let new_block = self.await_for_block_commit().await;
self.current_state_root = Some(new_block.new_root_hash);

Expand Down Expand Up @@ -1119,6 +1121,16 @@ impl TestSetup {
.await
.expect("execute block tx")
.expect_success();
let pending_withdrawals_result = self
.commit_account
.execute_pending_withdrawals(
&block_execute_op,
&self.tokens,
&self.deployed_contracts.pending_withdrawer,
)
.await
.expect("execute block tx")
.map(|a| a.expect_success());

self.last_committed_block = new_block.clone();

Expand Down Expand Up @@ -1167,6 +1179,7 @@ impl TestSetup {
commit_result,
verify_result,
withdrawals_result,
pending_withdrawals_result,
block_chunks,
))
}
Expand Down
3 changes: 3 additions & 0 deletions core/tests/testkit/src/types.rs
Expand Up @@ -43,6 +43,7 @@ pub struct BlockExecutionResult {
pub commit_result: TransactionReceipt,
pub verify_result: TransactionReceipt,
pub withdrawals_result: TransactionReceipt,
pub pending_withdrawals_result: Option<TransactionReceipt>,
pub block_size_chunks: usize,
}

Expand All @@ -52,13 +53,15 @@ impl BlockExecutionResult {
commit_result: TransactionReceipt,
verify_result: TransactionReceipt,
withdrawals_result: TransactionReceipt,
pending_withdrawals_result: Option<TransactionReceipt>,
block_size_chunks: usize,
) -> Self {
Self {
block,
commit_result,
verify_result,
withdrawals_result,
pending_withdrawals_result,
block_size_chunks,
}
}
Expand Down

0 comments on commit b37da6f

Please sign in to comment.