Skip to content

Commit 1350138

Browse files
authored
Merge pull request #444 from matter-labs/dev
chore: merge dev in main
2 parents 1ae2305 + c10e873 commit 1350138

File tree

39 files changed

+21179
-12174
lines changed

39 files changed

+21179
-12174
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ prover_examples = { git = "https://github.com/matter-labs/zksync-airbender", tag
6666
execution_utils = { git = "https://github.com/matter-labs/zksync-airbender", tag = "v0.4.3"}
6767
prover = { git = "https://github.com/matter-labs/zksync-airbender", tag = "v0.4.3" }
6868

69+
# zerocopy 0.8.29 introduced a compilation issue, remove this
70+
# when the compilation issue is resolved
71+
zerocopy = { version = "=0.8.28" }
72+
73+
6974
# [profile.dev]
7075
# opt-level = 0
7176
# lto = false
@@ -91,3 +96,4 @@ debug = true
9196
# prover_examples = { path = "../zksync-airbender/circuit_defs/prover_examples" }
9297
# risc_v_simulator = { path = "../zksync-airbender/risc_v_simulator" }
9398
# execution_utils = { path = "../zksync-airbender/execution_utils" }
99+

basic_bootloader/src/bootloader/process_transaction.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,9 @@ where
185185
)?;
186186

187187
// TODO: l1 transaction preparation (marking factory deps)
188-
let chain_id = system.get_chain_id();
189188

190189
let (tx_hash, preparation_out_of_resources): (Bytes32, bool) = match transaction
191-
.calculate_hash(chain_id, &mut resources)
190+
.calculate_hash(&mut resources)
192191
{
193192
Ok(h) => (h.into(), false),
194193
Err(e) => {
@@ -208,7 +207,7 @@ where
208207
let mut inf_resources = S::Resources::FORMAL_INFINITE;
209208
(
210209
transaction
211-
.calculate_hash(chain_id, &mut inf_resources)
210+
.calculate_hash(&mut inf_resources)
212211
.expect("must succeed")
213212
.into(),
214213
true,
@@ -620,18 +619,16 @@ where
620619
tx_gas_price: gas_price,
621620
});
622621

623-
let chain_id = system.get_chain_id();
624-
625622
// Process access list
626623
parse_and_warm_up_access_list(system, &mut resources, &transaction)?;
627624

628-
let tx_hash: Bytes32 = transaction.transaction_hash(chain_id, &mut resources)?;
625+
let tx_hash: Bytes32 = transaction.transaction_hash(&mut resources)?;
629626

630627
// We have to charge native for this hash, as it's computed during parsing
631628
// for RLP-encoded transactions.
632629
// We over-estimate using the total tx length
633630
charge_keccak(transaction.len(), &mut resources)?;
634-
let suggested_signed_hash: Bytes32 = transaction.signed_hash::<S::Resources>(chain_id)?;
631+
let suggested_signed_hash: Bytes32 = transaction.signed_hash()?;
635632

636633
let ValidationResult {
637634
validation_pubdata,

basic_bootloader/src/bootloader/transaction/abi_encoded/mod.rs

Lines changed: 10 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
//! unique Layer 2 features that cannot be expressed in standard
1010
//! Ethereum transaction formats. This includes:
1111
//!
12-
//! - **`EIP_712_TX_TYPE` (0x71)**: User-submitted transactions with EIP-712 signing
1312
//! - **`L1_L2_TX_TYPE` (0x7f)**: Transactions initiated from L1 (deposits, forced transactions)
1413
//! - **`UPGRADE_TX_TYPE` (0x7e)**: System upgrade transactions (protocol changes)
1514
@@ -96,8 +95,6 @@ pub struct AbiEncodedTransaction<A: Allocator> {
9695

9796
#[allow(dead_code)]
9897
impl<A: Allocator> AbiEncodedTransaction<A> {
99-
/// The type id of EIP712 transactions.
100-
pub const EIP_712_TX_TYPE: u8 = 0x71;
10198
/// The type id of protocol upgrade transactions.
10299
pub const UPGRADE_TX_TYPE: u8 = 0x7e;
103100
/// The type id of L1 -> L2 transactions.
@@ -218,7 +215,7 @@ impl<A: Allocator> AbiEncodedTransaction<A> {
218215
let tx_type = self.tx_type.read();
219216

220217
match tx_type {
221-
Self::UPGRADE_TX_TYPE | Self::L1_L2_TX_TYPE | Self::EIP_712_TX_TYPE => {}
218+
Self::UPGRADE_TX_TYPE | Self::L1_L2_TX_TYPE => {}
222219
_ => return Err(()),
223220
}
224221

@@ -232,7 +229,7 @@ impl<A: Allocator> AbiEncodedTransaction<A> {
232229
}
233230
}
234231

235-
// paymasters are not supported, even for EIP712 txs
232+
// paymasters are not supported
236233
if self.paymaster.read() != B160::ZERO {
237234
return Err(());
238235
}
@@ -248,17 +245,11 @@ impl<A: Allocator> AbiEncodedTransaction<A> {
248245
}
249246
}
250247
}
251-
// reserved[1] = refund recipient for l1 to l2 and upgrade txs,
252-
// for EIP712 txs should be zero
248+
// reserved[1] = refund recipient for l1 to l2 and upgrade txs
253249
match tx_type {
254250
Self::L1_L2_TX_TYPE | Self::UPGRADE_TX_TYPE => {
255251
// TODO: validate address?
256252
}
257-
Self::EIP_712_TX_TYPE => {
258-
if !self.reserved[1].read().is_zero() {
259-
return Err(());
260-
}
261-
}
262253
_ => unreachable!(),
263254
}
264255

@@ -280,7 +271,7 @@ impl<A: Allocator> AbiEncodedTransaction<A> {
280271
}
281272
}
282273

283-
// paymasters are not supported, even for EIP712 txs
274+
// paymasters are not supported
284275
if !self.paymaster_input.range.is_empty() {
285276
return Err(());
286277
}
@@ -324,190 +315,19 @@ impl<A: Allocator> AbiEncodedTransaction<A> {
324315
(parity, r, s)
325316
}
326317

327-
///
328-
/// Calculate the signed transaction hash.
329-
/// i.e. the one should be signed for the EOA accounts.
330-
///
331-
pub fn calculate_signed_hash<R: Resources>(
332-
&self,
333-
chain_id: u64,
334-
resources: &mut R,
335-
) -> Result<[u8; 32], TxError> {
336-
let tx_type = self.tx_type.read();
337-
match tx_type {
338-
Self::EIP_712_TX_TYPE => self.eip712_tx_calculate_signed_hash(chain_id, resources),
339-
_ => Err(
340-
internal_error!("Invalid type for signed hash, most likely l1 or upgrade").into(),
341-
),
342-
}
343-
}
344-
345318
///
346319
/// Calculate the transaction hash.
347320
/// i.e. the transaction hash to be used in the explorer.
348321
///
349-
pub fn calculate_hash<R: Resources>(
350-
&self,
351-
chain_id: u64,
352-
resources: &mut R,
353-
) -> Result<[u8; 32], TxError> {
322+
pub fn calculate_hash<R: Resources>(&self, resources: &mut R) -> Result<[u8; 32], TxError> {
354323
let tx_type = self.tx_type.read();
355324
match tx_type {
356-
Self::EIP_712_TX_TYPE => self.eip712_tx_calculate_hash(chain_id, resources),
357325
Self::L1_L2_TX_TYPE => self.l1_tx_calculate_hash(resources),
358326
Self::UPGRADE_TX_TYPE => self.l1_tx_calculate_hash(resources),
359327
_ => Err(internal_error!("Type should be validated").into()),
360328
}
361329
}
362330

363-
// Keccak256 of:
364-
// EIP712Domain(string name,string version,uint256 chainId)
365-
// = c2f8787176b8ac6bf7215b4adcc1e069bf4ab82d9ab1df05a57a91d425935b6e
366-
const DOMAIN_TYPE_HASH: [u8; 32] = [
367-
0xc2, 0xf8, 0x78, 0x71, 0x76, 0xb8, 0xac, 0x6b, 0xf7, 0x21, 0x5b, 0x4a, 0xdc, 0xc1, 0xe0,
368-
0x69, 0xbf, 0x4a, 0xb8, 0x2d, 0x9a, 0xb1, 0xdf, 0x05, 0xa5, 0x7a, 0x91, 0xd4, 0x25, 0x93,
369-
0x5b, 0x6e,
370-
];
371-
372-
// Keccak256 of:
373-
// zkSync
374-
// = 19b453ce45aaaaf3a300f5a9ec95869b4f28ab10430b572ee218c3a6a5e07d6f
375-
const DOMAIN_NAME_HASH: [u8; 32] = [
376-
0x19, 0xb4, 0x53, 0xce, 0x45, 0xaa, 0xaa, 0xf3, 0xa3, 0x00, 0xf5, 0xa9, 0xec, 0x95, 0x86,
377-
0x9b, 0x4f, 0x28, 0xab, 0x10, 0x43, 0x0b, 0x57, 0x2e, 0xe2, 0x18, 0xc3, 0xa6, 0xa5, 0xe0,
378-
0x7d, 0x6f,
379-
];
380-
// Keccak256 of:
381-
// 2
382-
// = ad7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5
383-
const DOMAIN_VERSION_HASH: [u8; 32] = [
384-
0xad, 0x7c, 0x5b, 0xef, 0x02, 0x78, 0x16, 0xa8, 0x00, 0xda, 0x17, 0x36, 0x44, 0x4f, 0xb5,
385-
0x8a, 0x80, 0x7e, 0xf4, 0xc9, 0x60, 0x3b, 0x78, 0x48, 0x67, 0x3f, 0x7e, 0x3a, 0x68, 0xeb,
386-
0x14, 0xa5,
387-
];
388-
389-
fn domain_hash_struct<R: Resources>(
390-
chain_id: u64,
391-
resources: &mut R,
392-
) -> Result<[u8; 32], TxError> {
393-
let len = Self::DOMAIN_TYPE_HASH.len()
394-
+ Self::DOMAIN_NAME_HASH.len()
395-
+ Self::DOMAIN_VERSION_HASH.len()
396-
+ U256::BYTES;
397-
charge_keccak(len, resources)?;
398-
399-
let mut hasher = Keccak256::new();
400-
hasher.update(Self::DOMAIN_TYPE_HASH);
401-
hasher.update(Self::DOMAIN_NAME_HASH);
402-
hasher.update(Self::DOMAIN_VERSION_HASH);
403-
hasher.update(U256::from(chain_id).to_be_bytes::<32>());
404-
Ok(*hasher.finalize().split_first_chunk::<32>().unwrap().0)
405-
}
406-
407-
// Keccak256 of:
408-
// Transaction(uint256 txType,uint256 from,uint256 to,uint256 gasLimit,uint256 gasPerPubdataByteLimit,uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,uint256 paymaster,uint256 nonce,uint256 value,bytes data,bytes32[] factoryDeps,bytes paymasterInput)
409-
// = 848e1bfa1ac4e3576b728bda6721b215c70a7799a5b4866282a71bab954baac8
410-
const TYPE_HASH: [u8; 32] = [
411-
0x84, 0x8e, 0x1b, 0xfa, 0x1a, 0xc4, 0xe3, 0x57, 0x6b, 0x72, 0x8b, 0xda, 0x67, 0x21, 0xb2,
412-
0x15, 0xc7, 0x0a, 0x77, 0x99, 0xa5, 0xb4, 0x86, 0x62, 0x82, 0xa7, 0x1b, 0xab, 0x95, 0x4b,
413-
0xaa, 0xc8,
414-
];
415-
416-
fn hash_struct<R: Resources>(&self, resources: &mut R) -> Result<[u8; 32], TxError> {
417-
let len = U256::BYTES * 14;
418-
charge_keccak(len, resources)?;
419-
420-
let mut hasher = Keccak256::new();
421-
hasher.update(Self::TYPE_HASH);
422-
hasher.update(self.tx_type.encoding(&self.underlying_buffer.as_slice()));
423-
hasher.update(self.from.encoding(&self.underlying_buffer.as_slice()));
424-
hasher.update(self.to.encoding(&self.underlying_buffer.as_slice()));
425-
hasher.update(self.gas_limit.encoding(&self.underlying_buffer.as_slice()));
426-
hasher.update(
427-
self.gas_per_pubdata_limit
428-
.encoding(&self.underlying_buffer.as_slice()),
429-
);
430-
hasher.update(
431-
self.max_fee_per_gas
432-
.encoding(&self.underlying_buffer.as_slice()),
433-
);
434-
hasher.update(
435-
self.max_priority_fee_per_gas
436-
.encoding(&self.underlying_buffer.as_slice()),
437-
);
438-
hasher.update(self.paymaster.encoding(&self.underlying_buffer.as_slice()));
439-
hasher.update(self.nonce.encoding(&self.underlying_buffer.as_slice()));
440-
hasher.update(self.value.encoding(&self.underlying_buffer.as_slice()));
441-
442-
charge_keccak(self.data.range.len(), resources)?;
443-
let data_hash = <Keccak256 as MiniDigest>::digest(
444-
self.data.encoding(&self.underlying_buffer.as_slice()),
445-
);
446-
hasher.update(&data_hash);
447-
448-
charge_keccak(self.factory_deps.range.len(), resources)?;
449-
let factory_deps_hash = <Keccak256 as MiniDigest>::digest(
450-
self.factory_deps
451-
.encoding(&self.underlying_buffer.as_slice()),
452-
);
453-
hasher.update(&factory_deps_hash);
454-
455-
charge_keccak(self.paymaster_input.range.len(), resources)?;
456-
let paymaster_input_hash = <Keccak256 as MiniDigest>::digest(
457-
self.paymaster_input
458-
.encoding(&self.underlying_buffer.as_slice()),
459-
);
460-
hasher.update(&paymaster_input_hash);
461-
462-
Ok(hasher.finalize())
463-
}
464-
465-
///
466-
/// Calculate signed tx hash(the one that should be signed by the sender):
467-
/// Keccak256(0x19 0x01 ‖ domainSeparator ‖ hashStruct(tx))
468-
///
469-
fn eip712_tx_calculate_signed_hash<R: Resources>(
470-
&self,
471-
chain_id: u64,
472-
resources: &mut R,
473-
) -> Result<[u8; 32], TxError> {
474-
let domain_separator = Self::domain_hash_struct(chain_id, resources)?;
475-
let hs = self.hash_struct(resources)?;
476-
charge_keccak(2 + 2 * U256::BYTES, resources)?;
477-
let mut hasher = Keccak256::new();
478-
hasher.update([0x19, 0x01]);
479-
hasher.update(domain_separator);
480-
hasher.update(hs);
481-
482-
Ok(hasher.finalize())
483-
}
484-
485-
///
486-
/// Calculate tx hash with signature(to be used in the explorer):
487-
/// Keccak256(signed_hash || Keccak256(signature))
488-
///
489-
fn eip712_tx_calculate_hash<R: Resources>(
490-
&self,
491-
chain_id: u64,
492-
resources: &mut R,
493-
) -> Result<[u8; 32], TxError> {
494-
let signed_hash = self.eip712_tx_calculate_signed_hash(chain_id, resources)?;
495-
// First charge for hashing the signature
496-
charge_keccak(self.signature.range.len(), resources)?;
497-
// Next charge for combining the two hashes
498-
charge_keccak(U256::BYTES * 2, resources)?;
499-
500-
let signature_hash = <Keccak256 as MiniDigest>::digest(
501-
self.signature.encoding(&self.underlying_buffer.as_slice()),
502-
);
503-
504-
let mut hasher = Keccak256::new();
505-
hasher.update(signed_hash);
506-
hasher.update(signature_hash);
507-
508-
Ok(hasher.finalize())
509-
}
510-
511331
///
512332
/// Calculate l1 tx hash:
513333
/// Keccak256(abi.encode(transaction))
@@ -521,23 +341,14 @@ impl<A: Allocator> AbiEncodedTransaction<A> {
521341
Ok(hasher.finalize())
522342
}
523343

524-
/// Checks if the transaction is of type EIP-712
525-
pub fn is_eip_712(&self) -> bool {
526-
self.tx_type.read() == Self::EIP_712_TX_TYPE
527-
}
528-
529344
/// Returns the balance required to process the transaction.
530345
/// If the calculation overflows, returns `None`.
531346
pub fn required_balance(&self) -> Option<U256> {
532-
if self.is_eip_712() && self.paymaster.read() != B160::ZERO {
533-
Some(self.value.read())
534-
} else {
535-
let fee_amount = self
536-
.max_fee_per_gas
537-
.read()
538-
.checked_mul(U256::from(self.gas_limit.read()))?;
539-
self.value.read().checked_add(U256::from(fee_amount))
540-
}
347+
let fee_amount = self
348+
.max_fee_per_gas
349+
.read()
350+
.checked_mul(U256::from(self.gas_limit.read()))?;
351+
self.value.read().checked_add(U256::from(fee_amount))
541352
}
542353

543354
#[allow(clippy::len_without_is_empty)]
@@ -560,10 +371,6 @@ impl<T: 'static + Clone + Copy + core::fmt::Debug> ParsedValue<T> {
560371
pub fn read_ref(&self) -> &T {
561372
&self.value
562373
}
563-
564-
fn encoding<'a>(&self, source: &'a [u8]) -> &'a [u8] {
565-
unsafe { source.get_unchecked(self.range.clone()) }
566-
}
567374
}
568375

569376
struct Parser<'a> {

basic_bootloader/src/bootloader/transaction/authorization_list.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,11 @@ fn recover_authority<S: EthereumLikeTypes>(
222222
use zk_ee::system::SystemFunctions;
223223
let mut ecrecover_input = [0u8; 128];
224224
let (parity, r, s) = auth_sig_data;
225+
if parity > 1 {
226+
return Ok(None);
227+
}
225228
ecrecover_input[0..32].copy_from_slice(msg);
226-
ecrecover_input[63] = if parity <= 1 { parity + 27 } else { parity };
229+
ecrecover_input[63] = parity + 27;
227230
ecrecover_input[64..96][(32 - r.len())..].copy_from_slice(r);
228231
ecrecover_input[96..128][(32 - s.len())..].copy_from_slice(s);
229232
let mut ecrecover_output = ArrayBuilder::default();

basic_bootloader/src/bootloader/transaction/mod.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -168,26 +168,22 @@ impl<A: Allocator> Transaction<A> {
168168
/// Computes the transaction hash used for indexing or inclusion.
169169
pub fn transaction_hash<R: Resources>(
170170
&mut self,
171-
chain_id: u64,
172171
resources: &mut R,
173172
) -> Result<Bytes32, TxError> {
174173
match self {
175174
Self::Rlp(tx) => tx.transaction_hash(resources),
176-
Self::Abi(tx) => tx
177-
.calculate_hash(chain_id, resources)
178-
.map(Bytes32::from_array),
175+
Self::Abi(tx) => tx.calculate_hash(resources).map(Bytes32::from_array),
179176
}
180177
}
181178

182179
/// Returns the signing hash for signature verification.
183-
pub fn signed_hash<R: Resources>(&mut self, chain_id: u64) -> Result<Bytes32, TxError> {
180+
pub fn signed_hash(&mut self) -> Result<Bytes32, TxError> {
184181
// Caller should charge native for this hash
185-
let mut inf_resources = R::FORMAL_INFINITE;
186182
match self {
187183
Self::Rlp(tx) => Ok(*tx.hash_for_signature_verification()),
188-
Self::Abi(tx) => tx
189-
.calculate_signed_hash(chain_id, &mut inf_resources)
190-
.map(Bytes32::from_array),
184+
Self::Abi(_tx) => {
185+
Err(internal_error!("ABI encoded transactions do not support signed hash").into())
186+
}
191187
}
192188
}
193189

0 commit comments

Comments
 (0)