Skip to content

Commit 74cc278

Browse files
committed
merged main
2 parents f1f000d + c1f64c9 commit 74cc278

9 files changed

+224
-52
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

e2e-tests/test/eth-apis.test.ts

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { expect } from "chai";
2-
import { getTestProvider } from "../helpers/utils";
2+
import { expectThrowsAsync, getTestProvider } from "../helpers/utils";
33
import { RichAccounts } from "../helpers/constants";
44
import { ethers } from "ethers";
55

@@ -18,3 +18,47 @@ describe("eth_accounts", function () {
1818
expect(accounts).to.deep.equal(richAccounts);
1919
});
2020
});
21+
22+
describe("eth_sendTransaction", function () {
23+
it("Should execute with impersonation", async function () {
24+
// Arrange
25+
const fromAddr = "0xE999bb14881e48934A489cC9B35A4f9449EE87fb";
26+
const toAddr = "0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4";
27+
const transaction = {
28+
to: toAddr,
29+
value: "0x0",
30+
data: "0xa9059cbb000000000000000000000000981f198286e40f9979274e0876636e9144b8fb8e0000000000000000000000000000000000000000000000000000000000989680",
31+
from: fromAddr,
32+
};
33+
34+
// Act
35+
await provider.send("hardhat_impersonateAccount", [fromAddr]);
36+
37+
const hash = await provider.send("eth_sendTransaction", [transaction]);
38+
39+
// Wait for the transaction to be mined and get the receipt
40+
const receipt = await provider.waitForTransaction(hash);
41+
42+
await provider.send("hardhat_stopImpersonatingAccount", [fromAddr]);
43+
44+
// Assert
45+
expect(receipt["from"]).to.equal(fromAddr);
46+
});
47+
48+
it("Should fail without impersonation", async function () {
49+
const action = async () => {
50+
const fromAddr = "0xE999bb14881e48934A489cC9B35A4f9449EE87fb";
51+
const toAddr = "0x3355df6d4c9c3035724fd0e3914de96a5a83aaf4";
52+
const transaction = {
53+
to: toAddr,
54+
value: "0x0",
55+
data: "0xa9059cbb000000000000000000000000981f198286e40f9979274e0876636e9144b8fb8e0000000000000000000000000000000000000000000000000000000000989680",
56+
from: fromAddr,
57+
};
58+
59+
await provider.send("eth_sendTransaction", [transaction]);
60+
};
61+
62+
await expectThrowsAsync(action, "not allowed to perform transactions");
63+
});
64+
});

src/fork.rs

+9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use zksync_types::{
1919
Block, BlockDetails, BlockIdVariant, BlockNumber, BridgeAddresses, Transaction,
2020
TransactionDetails, TransactionVariant,
2121
},
22+
fee_model::FeeParams,
2223
l2::L2Tx,
2324
url::SensitiveUrl,
2425
ProtocolVersionId, StorageKey,
@@ -308,6 +309,9 @@ pub trait ForkSource {
308309
/// Returns the block details for a given miniblock number.
309310
fn get_block_details(&self, miniblock: L2BlockNumber) -> eyre::Result<Option<BlockDetails>>;
310311

312+
/// Returns fee parameters for the give source.
313+
fn get_fee_params(&self) -> eyre::Result<FeeParams>;
314+
311315
/// Returns the transaction count for a given block hash.
312316
fn get_block_transaction_count_by_hash(&self, block_hash: H256) -> eyre::Result<Option<U256>>;
313317

@@ -362,6 +366,7 @@ pub struct ForkDetails<S> {
362366
pub estimate_gas_price_scale_factor: f64,
363367
/// The factor by which to scale the gasLimit.
364368
pub estimate_gas_scale_factor: f32,
369+
pub fee_params: Option<FeeParams>,
365370
}
366371

367372
const SUPPORTED_VERSIONS: &[ProtocolVersionId] = &[
@@ -446,6 +451,8 @@ impl ForkDetails<HttpForkSource> {
446451

447452
let (estimate_gas_price_scale_factor, estimate_gas_scale_factor) =
448453
network.local_gas_scale_factors();
454+
let fee_params = client.get_fee_params().await.ok();
455+
449456
ForkDetails {
450457
fork_source: HttpForkSource::new(url.to_owned(), cache_config),
451458
l1_block: l1_batch_number,
@@ -458,6 +465,7 @@ impl ForkDetails<HttpForkSource> {
458465
l2_fair_gas_price: block_details.base.l2_fair_gas_price,
459466
estimate_gas_price_scale_factor,
460467
estimate_gas_scale_factor,
468+
fee_params,
461469
}
462470
}
463471
/// Create a fork from a given network at a given height.
@@ -601,6 +609,7 @@ mod tests {
601609
l2_fair_gas_price: DEFAULT_L2_GAS_PRICE,
602610
estimate_gas_price_scale_factor: DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR,
603611
estimate_gas_scale_factor: DEFAULT_ESTIMATE_GAS_SCALE_FACTOR,
612+
fee_params: None,
604613
};
605614

606615
let mut fork_storage = ForkStorage::new(Some(fork_details), &options);

src/http_fork_source.rs

+6
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,12 @@ impl ForkSource for HttpForkSource {
286286
.wrap_err("fork http client failed")
287287
}
288288

289+
/// Returns fee parameters for the give source.
290+
fn get_fee_params(&self) -> eyre::Result<zksync_types::fee_model::FeeParams> {
291+
let client = self.create_client();
292+
block_on(async move { client.get_fee_params().await }).wrap_err("fork http client failed")
293+
}
294+
289295
/// Returns addresses of the default bridge contracts.
290296
fn get_bridge_contracts(&self) -> eyre::Result<BridgeAddresses> {
291297
if let Some(bridge_addresses) = self

src/node/eth.rs

+30-27
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use zksync_types::{
1616
l2::L2Tx,
1717
transaction_request::TransactionRequest,
1818
utils::storage_key_for_standard_token_balance,
19-
PackedEthSignature, StorageKey, L2_BASE_TOKEN_ADDRESS,
19+
PackedEthSignature, StorageKey, L2_BASE_TOKEN_ADDRESS, MAX_L1_TRANSACTION_GAS_LIMIT,
2020
};
2121
use zksync_utils::{h256_to_u256, u256_to_h256};
2222
use zksync_web3_decl::{
@@ -30,8 +30,8 @@ use crate::{
3030
namespaces::{EthNamespaceT, EthTestNodeNamespaceT, RpcResult},
3131
node::{InMemoryNode, TransactionResult, MAX_TX_SIZE, PROTOCOL_VERSION},
3232
utils::{
33-
self, h256_to_u64, into_jsrpc_error, not_implemented, report_into_jsrpc_error,
34-
IntoBoxedFuture,
33+
self, h256_to_u64, into_jsrpc_error, into_jsrpc_error_message, not_implemented,
34+
report_into_jsrpc_error, IntoBoxedFuture,
3535
},
3636
};
3737

@@ -1390,28 +1390,35 @@ impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> EthTestNod
13901390
&self,
13911391
tx: zksync_types::transaction_request::CallRequest,
13921392
) -> jsonrpc_core::BoxFuture<jsonrpc_core::Result<zksync_basic_types::H256>> {
1393-
let chain_id = match self.get_inner().read() {
1394-
Ok(reader) => reader.fork_storage.chain_id,
1393+
let (chain_id, l1_gas_price) = match self.get_inner().read() {
1394+
Ok(reader) => (
1395+
reader.fork_storage.chain_id,
1396+
reader.fee_input_provider.l1_gas_price,
1397+
),
13951398
Err(_) => {
1396-
return futures::future::err(into_jsrpc_error(Web3Error::InternalError(
1397-
anyhow::Error::msg("Failed to acquire read lock for chain ID retrieval."),
1398-
)))
1399+
return futures::future::err(into_jsrpc_error_message(
1400+
"Failed to acquire read lock for chain ID retrieval.".to_string(),
1401+
))
13991402
.boxed()
14001403
}
14011404
};
14021405

14031406
let mut tx_req = TransactionRequest::from(tx.clone());
1407+
// Users might expect a "sensible default"
1408+
if tx.gas.is_none() {
1409+
tx_req.gas = U256::from(MAX_L1_TRANSACTION_GAS_LIMIT);
1410+
}
1411+
14041412
// EIP-1559 gas fields should be processed separately
14051413
if tx.gas_price.is_some() {
14061414
if tx.max_fee_per_gas.is_some() || tx.max_priority_fee_per_gas.is_some() {
14071415
let error_message = "Transaction contains unsupported fields: max_fee_per_gas or max_priority_fee_per_gas";
1408-
return futures::future::err(into_jsrpc_error(Web3Error::InternalError(
1409-
anyhow::Error::msg(error_message),
1410-
)))
1411-
.boxed();
1416+
tracing::error!("{}", error_message);
1417+
return futures::future::err(into_jsrpc_error_message(error_message.to_string()))
1418+
.boxed();
14121419
}
14131420
} else {
1414-
tx_req.gas_price = tx.max_fee_per_gas.unwrap_or_default();
1421+
tx_req.gas_price = tx.max_fee_per_gas.unwrap_or(U256::from(l1_gas_price));
14151422
tx_req.max_priority_fee_per_gas = tx.max_priority_fee_per_gas;
14161423
if tx_req.transaction_type.is_none() {
14171424
tx_req.transaction_type = Some(zksync_types::EIP_1559_TX_TYPE.into());
@@ -1425,8 +1432,9 @@ impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> EthTestNod
14251432
let hash = match tx_req.get_tx_hash(chain_id) {
14261433
Ok(result) => result,
14271434
Err(e) => {
1435+
tracing::error!("Transaction request serialization error: {}", e);
14281436
return futures::future::err(into_jsrpc_error(Web3Error::SerializationError(e)))
1429-
.boxed()
1437+
.boxed();
14301438
}
14311439
};
14321440
let bytes = tx_req.get_signed_bytes(
@@ -1436,8 +1444,9 @@ impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> EthTestNod
14361444
let mut l2_tx: L2Tx = match L2Tx::from_request(tx_req, MAX_TX_SIZE) {
14371445
Ok(tx) => tx,
14381446
Err(e) => {
1447+
tracing::error!("Transaction serialization error: {}", e);
14391448
return futures::future::err(into_jsrpc_error(Web3Error::SerializationError(e)))
1440-
.boxed()
1449+
.boxed();
14411450
}
14421451
};
14431452

@@ -1458,16 +1467,14 @@ impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> EthTestNod
14581467
"Initiator address {:?} is not allowed to perform transactions",
14591468
l2_tx.common_data.initiator_address
14601469
);
1461-
return futures::future::err(into_jsrpc_error(Web3Error::InternalError(
1462-
anyhow::Error::msg(error_message),
1463-
)))
1464-
.boxed();
1470+
tracing::error!("{}", error_message);
1471+
return futures::future::err(into_jsrpc_error_message(error_message)).boxed();
14651472
}
14661473
}
14671474
Err(_) => {
1468-
return futures::future::err(into_jsrpc_error(Web3Error::InternalError(
1469-
anyhow::Error::msg("Failed to acquire read lock for accounts."),
1470-
)))
1475+
return futures::future::err(into_jsrpc_error_message(
1476+
"Failed to acquire read lock for accounts.".to_string(),
1477+
))
14711478
.boxed()
14721479
}
14731480
}
@@ -1476,11 +1483,7 @@ impl<S: ForkSource + std::fmt::Debug + Clone + Send + Sync + 'static> EthTestNod
14761483
Ok(_) => Ok(l2_tx.hash()).into_boxed_future(),
14771484
Err(e) => {
14781485
let error_message = format!("Execution error: {}", e);
1479-
futures::future::err(into_jsrpc_error(Web3Error::SubmitTransactionError(
1480-
error_message,
1481-
l2_tx.hash().as_bytes().to_vec(),
1482-
)))
1483-
.boxed()
1486+
futures::future::err(into_jsrpc_error_message(error_message)).boxed()
14841487
}
14851488
}
14861489
}

src/node/fee_model.rs

+58-11
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,69 @@ use zksync_node_fee_model::BatchFeeModelInputProvider;
33
use zksync_types::fee_model::{FeeModelConfigV2, FeeParams, FeeParamsV2};
44
use zksync_types::L1_GAS_PER_PUBDATA_BYTE;
55

6+
use super::{
7+
DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR, DEFAULT_ESTIMATE_GAS_SCALE_FACTOR,
8+
DEFAULT_L1_GAS_PRICE, DEFAULT_L2_GAS_PRICE,
9+
};
10+
611
#[derive(Debug, Clone, PartialEq)]
712
pub struct TestNodeFeeInputProvider {
813
pub l1_gas_price: u64,
14+
pub l1_pubdata_price: u64,
915
pub l2_gas_price: u64,
16+
pub compute_overhead_part: f64,
17+
pub pubdata_overhead_part: f64,
18+
pub batch_overhead_l1_gas: u64,
19+
pub max_gas_per_batch: u64,
20+
pub max_pubdata_per_batch: u64,
1021
/// L1 Gas Price Scale Factor for gas estimation.
1122
pub estimate_gas_price_scale_factor: f64,
1223
/// The factor by which to scale the gasLimit.
1324
pub estimate_gas_scale_factor: f32,
1425
}
1526

1627
impl TestNodeFeeInputProvider {
17-
pub fn new(
18-
l1_gas_price: u64,
19-
l2_gas_price: u64,
28+
pub fn from_fee_params_and_estimate_scale_factors(
29+
fee_params: FeeParams,
30+
estimate_gas_price_scale_factor: f64,
31+
estimate_gas_scale_factor: f32,
32+
) -> Self {
33+
match fee_params {
34+
FeeParams::V1(_) => todo!(),
35+
FeeParams::V2(fee_params) => Self {
36+
l1_gas_price: fee_params.l1_gas_price,
37+
l1_pubdata_price: fee_params.l1_pubdata_price,
38+
l2_gas_price: fee_params.config.minimal_l2_gas_price,
39+
compute_overhead_part: fee_params.config.compute_overhead_part,
40+
pubdata_overhead_part: fee_params.config.pubdata_overhead_part,
41+
batch_overhead_l1_gas: fee_params.config.batch_overhead_l1_gas,
42+
max_gas_per_batch: fee_params.config.max_gas_per_batch,
43+
max_pubdata_per_batch: fee_params.config.max_pubdata_per_batch,
44+
estimate_gas_price_scale_factor,
45+
estimate_gas_scale_factor,
46+
},
47+
}
48+
}
49+
50+
pub fn from_estimate_scale_factors(
2051
estimate_gas_price_scale_factor: f64,
2152
estimate_gas_scale_factor: f32,
2253
) -> Self {
2354
Self {
24-
l1_gas_price,
25-
l2_gas_price,
2655
estimate_gas_price_scale_factor,
2756
estimate_gas_scale_factor,
57+
..Default::default()
2858
}
2959
}
3060

3161
pub fn get_fee_model_config(&self) -> FeeModelConfigV2 {
3262
FeeModelConfigV2 {
3363
minimal_l2_gas_price: self.l2_gas_price,
34-
compute_overhead_part: 0.0,
35-
pubdata_overhead_part: 1.0,
36-
batch_overhead_l1_gas: 800000,
37-
max_gas_per_batch: 200000000,
38-
max_pubdata_per_batch: 100000,
64+
compute_overhead_part: self.compute_overhead_part,
65+
pubdata_overhead_part: self.pubdata_overhead_part,
66+
batch_overhead_l1_gas: self.batch_overhead_l1_gas,
67+
max_gas_per_batch: self.max_gas_per_batch,
68+
max_pubdata_per_batch: self.max_pubdata_per_batch,
3969
}
4070
}
4171
}
@@ -46,7 +76,24 @@ impl BatchFeeModelInputProvider for TestNodeFeeInputProvider {
4676
FeeParams::V2(FeeParamsV2 {
4777
config: self.get_fee_model_config(),
4878
l1_gas_price: self.l1_gas_price,
49-
l1_pubdata_price: self.l1_gas_price * L1_GAS_PER_PUBDATA_BYTE as u64,
79+
l1_pubdata_price: self.l1_pubdata_price,
5080
})
5181
}
5282
}
83+
84+
impl Default for TestNodeFeeInputProvider {
85+
fn default() -> Self {
86+
Self {
87+
l1_gas_price: DEFAULT_L1_GAS_PRICE,
88+
l1_pubdata_price: DEFAULT_L1_GAS_PRICE * L1_GAS_PER_PUBDATA_BYTE as u64,
89+
l2_gas_price: DEFAULT_L2_GAS_PRICE,
90+
compute_overhead_part: 0.0,
91+
pubdata_overhead_part: 1.0,
92+
batch_overhead_l1_gas: 800000,
93+
max_gas_per_batch: 200000000,
94+
max_pubdata_per_batch: 100000,
95+
estimate_gas_price_scale_factor: DEFAULT_ESTIMATE_GAS_PRICE_SCALE_FACTOR,
96+
estimate_gas_scale_factor: DEFAULT_ESTIMATE_GAS_SCALE_FACTOR,
97+
}
98+
}
99+
}

0 commit comments

Comments
 (0)