diff --git a/src/batch.rs b/src/batch.rs new file mode 100644 index 0000000..7fa051a --- /dev/null +++ b/src/batch.rs @@ -0,0 +1,245 @@ +use circuit_definitions::circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircuit; +use circuit_definitions::snark_wrapper::franklin_crypto::bellman::bn256::Bn256; +use circuit_definitions::snark_wrapper::franklin_crypto::bellman::plonk::better_better_cs::proof::Proof; +use crypto::deserialize_proof; +use ethers::abi::{Function, ParamType, Token}; +use once_cell::sync::Lazy; +use primitive_types::U256; + +static COMMIT_BATCH_INFO_PARAMS: Lazy = Lazy::new(|| { + ParamType::Tuple(vec![ + ParamType::Uint(64), + ParamType::Uint(64), + ParamType::Uint(64), + ParamType::FixedBytes(32), + ParamType::Uint(256), + ParamType::FixedBytes(32), + ParamType::FixedBytes(32), + ParamType::FixedBytes(32), + ParamType::Bytes, + ParamType::Bytes, + ]) +}); + +static STORED_BATCH_INFO_PARAMS: Lazy = Lazy::new(|| { + ParamType::Tuple(vec![ + ParamType::Uint(64), + ParamType::FixedBytes(32), + ParamType::Uint(64), + ParamType::Uint(256), + ParamType::FixedBytes(32), + ParamType::FixedBytes(32), + ParamType::Uint(256), + ParamType::FixedBytes(32), + ]) +}); + +pub struct CommitBatchInfo { + pub batch_number: U256, + pub timestamp: U256, + pub index_repeated_storage_changes: U256, + pub new_state_root: Vec, + pub number_l1_txns: U256, + pub priority_operations_hash: Vec, + pub bootloader_contents_hash: Vec, + pub event_queue_state_hash: Vec, + pub sys_logs: Vec, + pub total_pubdata: Vec, +} + +pub fn parse_commit_batch_info( + func: &Function, + calldata: &[u8], + protocol_version: u16, +) -> Option { + use ethers::abi; + + if calldata.len() < 5 { + return None; + } + + let mut parsed_input = func.decode_input(&calldata[4..]).unwrap(); + + if protocol_version < 26 { + let second_param = parsed_input.pop().unwrap(); + + let abi::Token::Array(inner) = second_param else { + return None; + }; + + let mut batch = None; + + for inner in inner.into_iter() { + let abi::Token::Tuple(inner) = inner else { + return None; + }; + + let [abi::Token::Uint(batch_number), abi::Token::Uint(timestamp), abi::Token::Uint(index_repeated_storage_changes), abi::Token::FixedBytes(new_state_root), abi::Token::Uint(number_l1_txns), abi::Token::FixedBytes(priority_operations_hash), abi::Token::FixedBytes(bootloader_contents_hash), abi::Token::FixedBytes(event_queue_state_hash), abi::Token::Bytes(sys_logs), abi::Token::Bytes(total_pubdata)] = + inner.as_slice() + else { + return None; + }; + + batch = Some(CommitBatchInfo { + batch_number: batch_number.clone(), + timestamp: timestamp.clone(), + index_repeated_storage_changes: index_repeated_storage_changes.clone(), + new_state_root: new_state_root.clone(), + number_l1_txns: number_l1_txns.clone(), + priority_operations_hash: priority_operations_hash.clone(), + bootloader_contents_hash: bootloader_contents_hash.clone(), + event_queue_state_hash: event_queue_state_hash.clone(), + sys_logs: sys_logs.clone(), + total_pubdata: total_pubdata.clone(), + }); + } + + return batch; + } else { + assert_eq!(parsed_input.len(), 4); + + let commit_data = parsed_input.pop().unwrap(); + + let abi::Token::Bytes(mut commit_data_bytes) = commit_data else { + return None; + }; + + commit_data_bytes = commit_data_bytes[1..].to_vec(); + + let combined_params = vec![ + (*STORED_BATCH_INFO_PARAMS).clone(), + ParamType::Array(Box::new((*COMMIT_BATCH_INFO_PARAMS).clone())), + ]; + + let res = ethers::core::abi::decode(&combined_params, &commit_data_bytes); + + if res.is_err() { + return None; + } + + let decoded_input = res.unwrap(); + + if decoded_input.len() != 2 { + return None; + } + + let abi::Token::Array(commit_batches) = decoded_input[1].clone() else { + return None; + }; + + if commit_batches.len() != 1 { + return None; + } + + let abi::Token::Tuple(commit_batch) = commit_batches[0].clone() else { + return None; + }; + + if commit_batch.len() != 10 { + return None; + }; + + let [abi::Token::Uint(batch_number), abi::Token::Uint(timestamp), abi::Token::Uint(index_repeated_storage_changes), abi::Token::FixedBytes(new_state_root), abi::Token::Uint(number_l1_txns), abi::Token::FixedBytes(priority_operations_hash), abi::Token::FixedBytes(bootloader_contents_hash), abi::Token::FixedBytes(event_queue_state_hash), abi::Token::Bytes(sys_logs), abi::Token::Bytes(total_pubdata)] = + commit_batch.as_slice() + else { + return None; + }; + + return Some(CommitBatchInfo { + batch_number: batch_number.clone(), + timestamp: timestamp.clone(), + index_repeated_storage_changes: index_repeated_storage_changes.clone(), + new_state_root: new_state_root.clone(), + number_l1_txns: number_l1_txns.clone(), + priority_operations_hash: priority_operations_hash.clone(), + bootloader_contents_hash: bootloader_contents_hash.clone(), + event_queue_state_hash: event_queue_state_hash.clone(), + sys_logs: sys_logs.clone(), + total_pubdata: total_pubdata.clone(), + }); + } +} + +pub fn parse_batch_proof( + function: &Function, + calldata: &[u8], + protocol_version: u16, + network: &str, +) -> Option> { + let parsed_input = function.decode_input(&calldata[4..]).unwrap(); + + if protocol_version < 26 { + let Token::Tuple(proof) = parsed_input.as_slice().last().unwrap() else { + return None; + }; + + assert_eq!(proof.len(), 2); + + let Token::Array(serialized_proof) = proof[1].clone() else { + return None; + }; + + let proof = serialized_proof + .iter() + .filter_map(|e| { + if let Token::Uint(x) = e { + Some(x.clone()) + } else { + None + } + }) + .collect::>(); + + if network != "mainnet" && serialized_proof.len() == 0 { + return None; + } + + Some(deserialize_proof(proof)) + } else { + let Token::Bytes(proof_data) = parsed_input.as_slice().last().unwrap() else { + return None; + }; + + let stored_batch_info_params = ParamType::Tuple(vec![ + ParamType::Uint(64), + ParamType::FixedBytes(32), + ParamType::Uint(64), + ParamType::Uint(256), + ParamType::FixedBytes(32), + ParamType::FixedBytes(32), + ParamType::Uint(256), + ParamType::FixedBytes(32), + ]); + + let combined_params = vec![ + stored_batch_info_params.clone(), + ParamType::Array(Box::new(stored_batch_info_params)), + ParamType::Array(Box::new(ParamType::Uint(256))), + ]; + + let proof = ethers::core::abi::decode(&combined_params, &proof_data[1..]).unwrap(); + + assert_eq!(proof.len(), 3); + + let Token::Array(serialized_proof) = proof[2].clone() else { + return None; + }; + + let proof = serialized_proof + .iter() + .filter_map(|e| { + if let Token::Uint(x) = e { + Some(x.clone()) + } else { + None + } + }) + .collect::>(); + + if network != "mainnet" && serialized_proof.len() == 0 { + return None; + } + + Some(deserialize_proof(proof)) + } +} diff --git a/src/block_header.rs b/src/block_header.rs index 3a306cc..838332f 100644 --- a/src/block_header.rs +++ b/src/block_header.rs @@ -1,7 +1,10 @@ -use ethers::{abi::{Function, ParamType}, utils::keccak256}; +use ethers::{abi::Function, utils::keccak256}; use zksync_types::{commitment::SerializeCommitment, l2_to_l1_log::L2ToL1Log, H256}; -use crate::outputs::StatusCode; +use crate::{ + batch::{parse_commit_batch_info, CommitBatchInfo}, + outputs::StatusCode, +}; #[derive(Debug, Clone)] pub struct BlockAuxilaryOutput { @@ -33,209 +36,60 @@ impl BlockAuxilaryOutput { } } -pub async fn parse_aux_data(func: &Function, calldata: &[u8], protocol_version: u16) -> Result { - use ethers::abi; - - let batch; - - if calldata.len() < 5 { - return Err(StatusCode::BadCalldataLength); - } - - let mut parsed_input = func.decode_input(&calldata[4..]).unwrap(); - - if protocol_version < 26 { - let second_param = parsed_input.pop().unwrap(); - - let abi::Token::Array(inner) = second_param else { - return Err(StatusCode::FailedToDeconstruct); - }; - - let mut found_params = None; - - for inner in inner.into_iter() { - let abi::Token::Tuple(inner) = inner else { - return Err(StatusCode::FailedToDeconstruct); - }; - - let [ - abi::Token::Uint(batch_number), - abi::Token::Uint(timestamp), - abi::Token::Uint(index_repeated_storage_changes), - abi::Token::FixedBytes(new_state_root), - abi::Token::Uint(number_l1_txns), - abi::Token::FixedBytes(priority_operations_hash), - abi::Token::FixedBytes(bootloader_contents_hash), - abi::Token::FixedBytes(event_queue_state_hash), - abi::Token::Bytes(sys_logs), - abi::Token::Bytes(total_pubdata) - ] = - inner.as_slice() - else { - return Err(StatusCode::FailedToDeconstruct); - }; - - found_params = Some(( - batch_number.clone(), - timestamp.clone(), - index_repeated_storage_changes.clone(), - new_state_root.clone(), - number_l1_txns.clone(), - priority_operations_hash.clone(), - bootloader_contents_hash.clone(), - event_queue_state_hash.clone(), - sys_logs.clone(), - total_pubdata.clone(), - )); - - } - - batch = found_params.unwrap(); - } else { - assert_eq!(parsed_input.len(), 4); - - let commit_data = parsed_input.pop().unwrap(); - - let abi::Token::Bytes(mut commit_data_bytes) = commit_data else { - return Err(StatusCode::FailedToDeconstruct); - }; - - commit_data_bytes = commit_data_bytes[1..].to_vec(); - - let stored_batch_info_params = ParamType::Tuple( - vec![ - ParamType::Uint(64), - ParamType::FixedBytes(32), - ParamType::Uint(64), - ParamType::Uint(256), - ParamType::FixedBytes(32), - ParamType::FixedBytes(32), - ParamType::Uint(256), - ParamType::FixedBytes(32), - ] - ); - - let commit_batch_info_params = ParamType::Tuple( - vec![ - ParamType::Uint(64), - ParamType::Uint(64), - ParamType::Uint(64), - ParamType::FixedBytes(32), - ParamType::Uint(256), - ParamType::FixedBytes(32), - ParamType::FixedBytes(32), - ParamType::FixedBytes(32), - ParamType::Bytes, - ParamType::Bytes, - ] - ); - - let combined_params = vec![ - stored_batch_info_params, - ParamType::Array(Box::new(commit_batch_info_params)) - ]; - - let res = ethers::core::abi::decode(&combined_params, &commit_data_bytes); - - - if res.is_err() { - return Err(StatusCode::FailedToDeconstruct); - } - - let decoded_input = res.unwrap(); - - if decoded_input.len() != 2 { - return Err(StatusCode::FailedToDeconstruct); +pub async fn parse_aux_data( + func: &Function, + calldata: &[u8], + protocol_version: u16, +) -> Result { + let batch = parse_commit_batch_info(func, calldata, protocol_version); + + match batch { + None => Err(StatusCode::FailedToDeconstruct), + Some(batch_commit) => { + let CommitBatchInfo { + batch_number: _, + timestamp: _, + index_repeated_storage_changes: _, + new_state_root: _, + number_l1_txns: _, + priority_operations_hash: _, + bootloader_contents_hash, + event_queue_state_hash, + sys_logs, + total_pubdata: _, + } = batch_commit; + + assert_eq!(bootloader_contents_hash.len(), 32); + assert_eq!(event_queue_state_hash.len(), 32); + + let mut bootloader_contents_hash_buffer = [0u8; 32]; + bootloader_contents_hash_buffer.copy_from_slice(&bootloader_contents_hash); + + let mut event_queue_state_hash_buffer = [0u8; 32]; + event_queue_state_hash_buffer.copy_from_slice(&event_queue_state_hash); + + assert!( + sys_logs.len() % L2ToL1Log::SERIALIZED_SIZE == 0, + "sys logs length should be a factor of serialized size" + ); + let state_diff_hash_sys_log = sys_logs + .chunks(L2ToL1Log::SERIALIZED_SIZE) + .into_iter() + .map(L2ToL1Log::from_slice) + // The value 2 comes from the key in this enum https://github.com/matter-labs/era-system-contracts/blob/d42f707cbe6938a76fa29f4bf76203af1e13f51f/contracts/Constants.sol#L90 + .find(|log| log.key == H256::from_low_u64_be(2_u64)) + .unwrap(); + + let system_logs_hash = keccak256(sys_logs); + + Ok(BlockAuxilaryOutput { + system_logs_hash, + state_diff_hash: state_diff_hash_sys_log.value.to_fixed_bytes(), + bootloader_heap_initial_content_hash: bootloader_contents_hash_buffer, + event_queue_state_hash: event_queue_state_hash_buffer, + }) } - - let abi::Token::Array(commit_batches) = decoded_input[1].clone() else { - return Err(StatusCode::FailedToDeconstruct); - }; - - if commit_batches.len() != 1 { - return Err(StatusCode::FailedToDeconstruct); - } - - let abi::Token::Tuple(commit_batch) = commit_batches[0].clone() else { - return Err(StatusCode::FailedToDeconstruct); - }; - - if commit_batch.len() != 10 { - return Err(StatusCode::FailedToDeconstruct); - }; - - let [ - abi::Token::Uint(batch_number), - abi::Token::Uint(timestamp), - abi::Token::Uint(index_repeated_storage_changes), - abi::Token::FixedBytes(new_state_root), - abi::Token::Uint(number_l1_txns), - abi::Token::FixedBytes(priority_operations_hash), - abi::Token::FixedBytes(bootloader_contents_hash), - abi::Token::FixedBytes(event_queue_state_hash), - abi::Token::Bytes(sys_logs), - abi::Token::Bytes(total_pubdata) - ] = commit_batch.as_slice() - else { - return Err(StatusCode::FailedToDeconstruct); - }; - - batch = ( - batch_number.clone(), - timestamp.clone(), - index_repeated_storage_changes.clone(), - new_state_root.clone(), - number_l1_txns.clone(), - priority_operations_hash.clone(), - bootloader_contents_hash.clone(), - event_queue_state_hash.clone(), - sys_logs.clone(), - total_pubdata.clone(), - ); } - - let ( - batch_number, - timestamp, - index_repeated_storage_changes, - new_state_root, - number_l1_txns, - priority_operations_hash, - bootloader_contents_hash, - event_queue_state_hash, - sys_logs, - total_pubdata, - ) = batch; - - assert_eq!(bootloader_contents_hash.len(), 32); - assert_eq!(event_queue_state_hash.len(), 32); - - let mut bootloader_contents_hash_buffer = [0u8; 32]; - bootloader_contents_hash_buffer.copy_from_slice(&bootloader_contents_hash); - - let mut event_queue_state_hash_buffer = [0u8; 32]; - event_queue_state_hash_buffer.copy_from_slice(&event_queue_state_hash); - - assert!( - sys_logs.len() % L2ToL1Log::SERIALIZED_SIZE == 0, - "sys logs length should be a factor of serialized size" - ); - let state_diff_hash_sys_log = sys_logs - .chunks(L2ToL1Log::SERIALIZED_SIZE) - .into_iter() - .map(L2ToL1Log::from_slice) - // The value 2 comes from the key in this enum https://github.com/matter-labs/era-system-contracts/blob/d42f707cbe6938a76fa29f4bf76203af1e13f51f/contracts/Constants.sol#L90 - .find(|log| log.key == H256::from_low_u64_be(2_u64)) - .unwrap(); - - let system_logs_hash = keccak256(sys_logs); - - Ok(BlockAuxilaryOutput { - system_logs_hash, - state_diff_hash: state_diff_hash_sys_log.value.to_fixed_bytes(), - bootloader_heap_initial_content_hash: bootloader_contents_hash_buffer, - event_queue_state_hash: event_queue_state_hash_buffer, - }) } pub fn to_fixed_bytes(ins: &[u8]) -> [u8; 32] { diff --git a/src/inputs.rs b/src/inputs.rs index 787630f..8bb575d 100644 --- a/src/inputs.rs +++ b/src/inputs.rs @@ -18,20 +18,19 @@ pub fn generate_inputs( use self::block_header::to_fixed_bytes; use sha3::{Digest, Keccak256}; - let input_fields = - if protocol_version.is_some() && protocol_version.unwrap() <= 22 { - vec![ - batch_l1_data.prev_batch_commitment.to_fixed_bytes(), - batch_l1_data.curr_batch_commitment.to_fixed_bytes(), - verifier_params.recursion_node_level_vk_hash, - verifier_params.recursion_leaf_level_vk_hash, - ] - } else { - vec![ - batch_l1_data.prev_batch_commitment.to_fixed_bytes(), - batch_l1_data.curr_batch_commitment.to_fixed_bytes(), - ] - }; + let input_fields = if protocol_version.is_some() && protocol_version.unwrap() <= 22 { + vec![ + batch_l1_data.prev_batch_commitment.to_fixed_bytes(), + batch_l1_data.curr_batch_commitment.to_fixed_bytes(), + verifier_params.recursion_node_level_vk_hash, + verifier_params.recursion_leaf_level_vk_hash, + ] + } else { + vec![ + batch_l1_data.prev_batch_commitment.to_fixed_bytes(), + batch_l1_data.curr_batch_commitment.to_fixed_bytes(), + ] + }; let encoded_input_params = input_fields.flatten(); let input_keccak_hash = to_fixed_bytes(Keccak256::digest(&encoded_input_params).as_slice()); diff --git a/src/main.rs b/src/main.rs index 2c4252d..4c6ab08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use serde::Deserialize; use std::io::Read; use std::{fs::File, process}; +mod batch; mod contract; mod inputs; mod outputs; @@ -186,9 +187,10 @@ async fn main() { .await .unwrap(); - let previous_batch_protocol_version = requests::fetch_batch_protocol_version(batch_number - 1, &network) - .await - .unwrap(); + let previous_batch_protocol_version = + requests::fetch_batch_protocol_version(batch_number - 1, &network) + .await + .unwrap(); println!("{}", "Fetching and validating the proof itself".on_blue()); if l1_rpc.is_none() { diff --git a/src/outputs.rs b/src/outputs.rs index 2c72ef1..618e469 100644 --- a/src/outputs.rs +++ b/src/outputs.rs @@ -32,6 +32,7 @@ pub enum StatusCode { BadCalldataLength, FailedToCallRPCJsonError, FailedToCallRPCResponseError, + FailedToParseProof, } #[derive(Default)] diff --git a/src/requests.rs b/src/requests.rs index 514d18a..f0be793 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -5,20 +5,22 @@ use circuit_definitions::circuit_definitions::aux_layer::ZkSyncSnarkWrapperCircu use circuit_definitions::snark_wrapper::franklin_crypto::bellman::bn256::Bn256; use circuit_definitions::snark_wrapper::franklin_crypto::bellman::plonk::better_better_cs::proof::Proof; use colored::Colorize; -use crypto::deserialize_proof; -use ethers::abi::{Abi, Function, Token, ParamType}; +use ethers::abi::{Abi, Function}; use ethers::contract::BaseContract; use ethers::providers::{Http, Middleware, Provider}; use ethers::types::TxHash; use once_cell::sync::Lazy; -use primitive_types::U256; use zksync_types::{ethabi, H256}; +use crate::batch::{parse_batch_proof, parse_commit_batch_info, CommitBatchInfo}; use crate::block_header::{self, BlockAuxilaryOutput, VerifierParams}; use crate::contract::get_diamond_proxy_address; use crate::outputs::StatusCode; use crate::snark_wrapper_verifier::L1BatchProofForL1; -use crate::utils::{get_abi_for_protocol_version, get_commit_function_for_protocol_version, get_prove_function_for_protocol_version}; +use crate::utils::{ + get_abi_for_protocol_version, get_commit_function_for_protocol_version, + get_prove_function_for_protocol_version, +}; pub static BLOCK_COMMIT_EVENT_SIGNATURE: Lazy = Lazy::new(|| { ethabi::long_signature( @@ -125,8 +127,7 @@ pub async fn fetch_l1_commit_data( (previous_batch_number, previous_protocol_version), (batch_number, current_protocol_version), ] { - let (function, fallback_function) = - get_commit_function_for_protocol_version(protocol_version); + let (function, _) = get_commit_function_for_protocol_version(protocol_version); let commit_tx = fetch_batch_commit_tx(b_number, network).await; @@ -149,13 +150,7 @@ pub async fn fetch_l1_commit_data( l1_block_number = tx.block_number.unwrap().as_u64(); calldata = tx.input.to_vec(); - let found_data = find_state_data_from_log( - b_number, - protocol_version, - &function, - fallback_function.clone(), - &calldata, - ).await; + let found_data = find_state_data_from_log(protocol_version, &function, &calldata); if found_data.is_err() || found_data.clone().unwrap().is_none() { return Err(StatusCode::InvalidLog); @@ -192,7 +187,8 @@ pub async fn fetch_l1_commit_data( } let (function, _) = get_commit_function_for_protocol_version(current_protocol_version); - let aux_output = block_header::parse_aux_data(&function, &calldata, current_protocol_version).await; + let aux_output = + block_header::parse_aux_data(&function, &calldata, current_protocol_version).await; if aux_output.is_err() { return Err(aux_output.err().unwrap()); @@ -282,109 +278,17 @@ pub async fn fetch_proof_from_l1( let l1_block_number = tx.block_number.unwrap().as_u64(); let calldata = tx.input.to_vec(); - let parsed_input = function.decode_input(&calldata[4..]).unwrap(); - - if protocol_version < 26 { - let Token::Tuple(proof) = parsed_input.as_slice().last().unwrap() else { - return Err(StatusCode::InvalidTupleTypes); - }; - - assert_eq!(proof.len(), 2); - - let Token::Array(serialized_proof) = proof[1].clone() else { - return Err(StatusCode::InvalidTupleTypes); - }; - - let proof = serialized_proof - .iter() - .filter_map(|e| { - if let Token::Uint(x) = e { - Some(x.clone()) - } else { - None - } - }) - .collect::>(); - - if network != "mainnet" && serialized_proof.len() == 0 { - let msg = format!( - "Proof doesn't exist for batch {} on network {}, exiting...", - batch_number.to_string().red(), - network.red() - ); - println!("{}", msg); - return Err(StatusCode::ProofDoesntExist); - } - - let x: Proof = deserialize_proof(proof); - Ok(( - L1BatchProofForL1 { - aggregation_result_coords: [[0u8; 32]; 4], - scheduler_proof: x, - }, - l1_block_number, - )) - } else { - let Token::Bytes(proof_data) = parsed_input.as_slice().last().unwrap() else { - return Err(StatusCode::InvalidTupleTypes); - }; - - let stored_batch_info_params = ParamType::Tuple( - vec![ - ParamType::Uint(64), - ParamType::FixedBytes(32), - ParamType::Uint(64), - ParamType::Uint(256), - ParamType::FixedBytes(32), - ParamType::FixedBytes(32), - ParamType::Uint(256), - ParamType::FixedBytes(32), - ] - ); - - let combined_params = vec![ - stored_batch_info_params.clone(), - ParamType::Array(Box::new(stored_batch_info_params)), - ParamType::Array(Box::new(ParamType::Uint(256))) - ]; - - let proof = ethers::core::abi::decode(&combined_params, &proof_data[1..]).unwrap(); - - assert_eq!(proof.len(), 3); - - let Token::Array(serialized_proof) = proof[2].clone() else { - return Err(StatusCode::InvalidTupleTypes); - }; - - let proof = serialized_proof - .iter() - .filter_map(|e| { - if let Token::Uint(x) = e { - Some(x.clone()) - } else { - None - } - }) - .collect::>(); - - if network != "mainnet" && serialized_proof.len() == 0 { - let msg = format!( - "Proof doesn't exist for batch {} on network {}, exiting...", - batch_number.to_string().red(), - network.red() - ); - println!("{}", msg); - return Err(StatusCode::ProofDoesntExist); - } - - let x: Proof = deserialize_proof(proof); - Ok(( + let proof = parse_batch_proof(&function, &calldata, protocol_version, network); + + match proof { + None => Err(StatusCode::FailedToParseProof), + Some(proof) => Ok(( L1BatchProofForL1 { aggregation_result_coords: [[0u8; 32]; 4], - scheduler_proof: x, + scheduler_proof: proof, }, l1_block_number, - )) + )), } } @@ -570,219 +474,34 @@ pub async fn fetch_batch_protocol_version( } } -async fn find_state_data_from_log( - batch_number: u64, +fn find_state_data_from_log( protocol_version: u16, function: &Function, - fallback_function: Option, calldata: &[u8], ) -> Result)>, StatusCode> { - let ( - _batch_number, - _timestamp, - index_repeated_storage_changes, - new_state_root, - _number_l1_txns, - _priority_operations_hash, - _bootloader_contents_hash, - _event_queue_state_hash, - _sys_logs, - _total_pubdata, - ) = parse_calldata_into_batch_commit( - batch_number, - protocol_version, - function, - fallback_function, - calldata - ).await.unwrap().unwrap(); - - Ok(Some((index_repeated_storage_changes.as_u64(), new_state_root))) -} - -async fn parse_calldata_into_batch_commit( - batch_number: u64, - protocol_version: u16, - function: &Function, - fallback_function: Option, - calldata: &[u8], -) -> Result, U256, Vec, Vec, Vec, Vec, Vec)>, StatusCode> { - use ethers::abi; - - if calldata.len() < 5 { - return Err(StatusCode::BadCalldataLength); - } - - let mut parsed_input = function.decode_input(&calldata[4..]).unwrap_or_else(|_| { - fallback_function - .unwrap() - .decode_input(&calldata[4..]) - .unwrap() - }); - - if protocol_version < 26 { - let second_param = parsed_input.pop().unwrap(); - let first_param = parsed_input.pop().unwrap(); - - let abi::Token::Tuple(first_param) = first_param else { - return Err(StatusCode::FailedToDeconstruct); - }; - - let abi::Token::Uint(previous_l2_block_number) = first_param[0].clone() else { - return Err(StatusCode::FailedToDeconstruct); - }; - if previous_l2_block_number.as_u64() >= batch_number { - return Err(StatusCode::InvalidLog); - } - let abi::Token::Uint(previous_enumeration_index) = first_param[2].clone() else { - return Err(StatusCode::FailedToDeconstruct); - }; - let _previous_enumeration_index = previous_enumeration_index.0[0]; - - let abi::Token::Array(inner) = second_param else { - return Err(StatusCode::FailedToDeconstruct); - }; - - let mut found_params = None; - - for inner in inner.into_iter() { - let abi::Token::Tuple(inner) = inner else { - return Err(StatusCode::FailedToDeconstruct); - }; - - let [ - abi::Token::Uint(batch_number), - abi::Token::Uint(timestamp), - abi::Token::Uint(index_repeated_storage_changes), - abi::Token::FixedBytes(new_state_root), - abi::Token::Uint(number_l1_txns), - abi::Token::FixedBytes(priority_operations_hash), - abi::Token::FixedBytes(bootloader_contents_hash), - abi::Token::FixedBytes(event_queue_state_hash), - abi::Token::Bytes(sys_logs), - abi::Token::Bytes(total_pubdata) - ] = - inner.as_slice() - else { - return Err(StatusCode::FailedToDeconstruct); - }; - - found_params = Some(( - batch_number.clone(), - timestamp.clone(), - index_repeated_storage_changes.clone(), - new_state_root.clone(), - number_l1_txns.clone(), - priority_operations_hash.clone(), - bootloader_contents_hash.clone(), - event_queue_state_hash.clone(), - sys_logs.clone(), - total_pubdata.clone(), - )); - - } - - Ok(found_params) - } else { - assert_eq!(parsed_input.len(), 4); - - let commit_data = parsed_input.pop().unwrap(); - - let abi::Token::Bytes(mut commit_data_bytes) = commit_data else { - return Err(StatusCode::FailedToDeconstruct); - }; - - commit_data_bytes = commit_data_bytes[1..].to_vec(); - - let stored_batch_info_params = ParamType::Tuple( - vec![ - ParamType::Uint(64), - ParamType::FixedBytes(32), - ParamType::Uint(64), - ParamType::Uint(256), - ParamType::FixedBytes(32), - ParamType::FixedBytes(32), - ParamType::Uint(256), - ParamType::FixedBytes(32), - ] - ); - - let commit_batch_info_params = ParamType::Tuple( - vec![ - ParamType::Uint(64), - ParamType::Uint(64), - ParamType::Uint(64), - ParamType::FixedBytes(32), - ParamType::Uint(256), - ParamType::FixedBytes(32), - ParamType::FixedBytes(32), - ParamType::FixedBytes(32), - ParamType::Bytes, - ParamType::Bytes, - ] - ); - - let combined_params = vec![ - stored_batch_info_params, - ParamType::Array(Box::new(commit_batch_info_params)) - ]; - - let res = ethers::core::abi::decode(&combined_params, &commit_data_bytes); - - - if res.is_err() { - return Err(StatusCode::FailedToDeconstruct); - } - - let decoded_input = res.unwrap(); - - if decoded_input.len() != 2 { - return Err(StatusCode::FailedToDeconstruct); - } - - let abi::Token::Array(commit_batches) = decoded_input[1].clone() else { - return Err(StatusCode::FailedToDeconstruct); - }; - - if commit_batches.len() != 1 { - return Err(StatusCode::FailedToDeconstruct); + let batch = parse_commit_batch_info(function, calldata, protocol_version); + + match batch { + None => Err(StatusCode::FailedToDeconstruct), + Some(batch_commit) => { + let CommitBatchInfo { + batch_number: _, + timestamp: _, + index_repeated_storage_changes, + new_state_root, + number_l1_txns: _, + priority_operations_hash: _, + bootloader_contents_hash: _, + event_queue_state_hash: _, + sys_logs: _, + total_pubdata: _, + } = batch_commit; + + Ok(Some(( + index_repeated_storage_changes.as_u64(), + new_state_root, + ))) } - - let abi::Token::Tuple(commit_batch) = commit_batches[0].clone() else { - return Err(StatusCode::FailedToDeconstruct); - }; - - if commit_batch.len() != 10 { - return Err(StatusCode::FailedToDeconstruct); - }; - - let [ - abi::Token::Uint(batch_number), - abi::Token::Uint(timestamp), - abi::Token::Uint(index_repeated_storage_changes), - abi::Token::FixedBytes(new_state_root), - abi::Token::Uint(number_l1_txns), - abi::Token::FixedBytes(priority_operations_hash), - abi::Token::FixedBytes(bootloader_contents_hash), - abi::Token::FixedBytes(event_queue_state_hash), - abi::Token::Bytes(sys_logs), - abi::Token::Bytes(total_pubdata) - ] = commit_batch.as_slice() - else { - return Err(StatusCode::FailedToDeconstruct); - }; - - Ok(Some(( - batch_number.clone(), - timestamp.clone(), - index_repeated_storage_changes.clone(), - new_state_root.clone(), - number_l1_txns.clone(), - priority_operations_hash.clone(), - bootloader_contents_hash.clone(), - event_queue_state_hash.clone(), - sys_logs.clone(), - total_pubdata.clone(), - ))) } } diff --git a/src/utils.rs b/src/utils.rs index 249898f..22af5a1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -32,7 +32,7 @@ pub fn get_scheduler_key_override( batch_number: u64, ) -> Option { // This override is needed because we discovered a deviation between our in and out of circuit - // vms. The choice was made to update the verifier vs bumping the protocol version as it would have + // vms. The choice was made to update the verifier vs bumping the protocol version as it would have // required a batch rollback. if network == "sepolia" { if protocol_version == "24" { @@ -56,7 +56,9 @@ pub fn get_abi_for_protocol_version(protocol_version: u16) -> Abi { } } -pub fn get_commit_function_for_protocol_version(protocol_version: u16) -> (Function, Option) { +pub fn get_commit_function_for_protocol_version( + protocol_version: u16, +) -> (Function, Option) { let contract_abi = get_abi_for_protocol_version(protocol_version); let function_name = if protocol_version < 23 { "commitBatches" @@ -69,7 +71,9 @@ pub fn get_commit_function_for_protocol_version(protocol_version: u16) -> (Funct (function, None) } -pub fn get_prove_function_for_protocol_version(protocol_version: u16) -> (Function, Option) { +pub fn get_prove_function_for_protocol_version( + protocol_version: u16, +) -> (Function, Option) { let contract_abi = get_abi_for_protocol_version(protocol_version); let function_name = if protocol_version < 23 { "proveBatches"