The input of Log_Demuxer receives log_queue, consisting of a request to storage, events, L1messages request, and a request to the precompiles ecrecover, sha256, and keccak256. It divides this queue into six new queues. See our diagram.
Start
The function of circuits is demultiplex_storage_logs_enty_point. We start for allocation of queue witnesses:
So long as tail is some equivalent of the merkle tree root and head is an equivalent of the current node hash, we provide some path witness when we pop elements and require that we properly end up in the root. So we must prove that element of head is zero:
pubfnenforce_trivial_head<CS:ConstraintSystem<F>>(&self, cs:&mut CS) {let zero_num =Num::zero(cs);for el in self.head.iter() {Num::enforce_equal(cs, el, &zero_num); }}
Depends on start_flag we select which queue observable_input or fsm_input(internal intermediate queue) we took:
let state =QueueState::conditionally_select( cs, structured_input.start_flag,&structured_input.observable_input.initial_log_queue_state,&structured_input.hidden_fsm_input.initial_log_queue_state,);
Wrap the state and witnesses in StorageLogQueue, thereby preparing the input data for inner part:
The last step is to form the final state. The flag completed shows us if initial_queue is empty or not. If not, we fill fsm_output. If it is empty, we select observable_output for the different queues.
Finally, we compute a commitment to PublicInput and allocate it as witness variables.
let compact_form =ClosedFormInputCompactForm::from_full_form(cs, &structured_input, round_function);let input_commitment =commit_variable_length_encodable_item(cs, &compact_form, round_function);for el in input_commitment.iter() {let gate =PublicInputGate::new(el.get_variable()); gate.add_to_cs(cs);}
Inner part
This is the logic part of the circuit. It depends on the main queue storage_log_queue, which separates the other queues. After we have dealt with the initial precompile, we need to allocate constant addresses for keccak_precompile_address, sha256_precompile_address, ecrecover_precompile_address and allocate constants for STORAGE_AUX_BYTE, EVENT_AUX_BYTE, L1_MESSAGE_AUX_BYTE, PRECOMPILE_AUX_BYTE. Execution happens when we pop all elements from storage_log_queue. We have appropriate flags for this, which depend on each other:
let queue_is_empty = storage_log_queue.is_empty(cs);let execute = queue_is_empty.negated(cs);
Here, we choose flags depending on the popped element data: