From 31353f230e65d3e8ee45a961959d559008174ad6 Mon Sep 17 00:00:00 2001 From: Sebastien Chapuis Date: Sat, 9 Mar 2024 21:41:13 +0100 Subject: [PATCH] Implement `ZkappCommand::valid_size` --- ledger/src/scan_state/mod.rs | 27 ++++++ ledger/src/scan_state/transaction_logic.rs | 105 +++++++++++++++++++-- ledger/src/transaction_pool.rs | 10 +- 3 files changed, 130 insertions(+), 12 deletions(-) diff --git a/ledger/src/scan_state/mod.rs b/ledger/src/scan_state/mod.rs index db4a9b11e..ad2e968f3 100644 --- a/ledger/src/scan_state/mod.rs +++ b/ledger/src/scan_state/mod.rs @@ -11,3 +11,30 @@ pub mod snark_work; pub mod transaction_logic; pub mod zkapp_logic; pub use parallel_scan::SpacePartition; + +pub struct GenesisConstant { + pub protocol: (), + pub txpool_max_size: usize, + pub num_accounts: Option, + pub zkapp_proof_update_cost: f64, + pub zkapp_signed_single_update_cost: f64, + pub zkapp_signed_pair_update_cost: f64, + pub zkapp_transaction_cost_limit: f64, + pub max_event_elements: usize, + pub max_action_elements: usize, + pub zkapp_cmd_limit_hardcap: usize, +} + +// TODO: Not sure if any of those values are correct +pub const GENESIS_CONSTANT: GenesisConstant = GenesisConstant { + protocol: (), + txpool_max_size: 3000, + num_accounts: None, + zkapp_proof_update_cost: 10.26, + zkapp_signed_single_update_cost: 9.14, + zkapp_signed_pair_update_cost: 10.08, + zkapp_transaction_cost_limit: 69.45, + max_event_elements: 100, + max_action_elements: 100, + zkapp_cmd_limit_hardcap: 128, +}; diff --git a/ledger/src/scan_state/transaction_logic.rs b/ledger/src/scan_state/transaction_logic.rs index e7ee03ff1..9cda9da9e 100644 --- a/ledger/src/scan_state/transaction_logic.rs +++ b/ledger/src/scan_state/transaction_logic.rs @@ -886,7 +886,10 @@ pub mod zkapp_command { to_field_elements::ToFieldElements, transaction::Check, }, - scan_state::currency::{Balance, Length, MinMax, Sgn, Signed, Slot, SlotSpan}, + scan_state::{ + currency::{Balance, Length, MinMax, Sgn, Signed, Slot, SlotSpan}, + GenesisConstant, GENESIS_CONSTANT, + }, transaction_pool::VerificationKeyWire, zkapps::snark::zkapp_check::InSnarkCheck, AuthRequired, ControlTag, Inputs, MyCow, Permissions, SetVerificationKey, ToInputs, @@ -3344,9 +3347,9 @@ pub mod zkapp_command { } /// https://github.com/MinaProtocol/mina/blob/05c2f73d0f6e4f1341286843814ce02dcb3919e0/src/lib/mina_base/zkapp_command.ml#L68 - fn fold_impl(&self, init: A, fun: &mut F) -> A + fn fold_impl<'a, A, F>(&'a self, init: A, fun: &mut F) -> A where - F: FnMut(A, &AccUpdate) -> A, + F: FnMut(A, &'a AccUpdate) -> A, { let mut accum = init; for elem in self.iter() { @@ -3356,9 +3359,9 @@ pub mod zkapp_command { accum } - pub fn fold(&self, init: A, mut fun: F) -> A + pub fn fold<'a, A, F>(&'a self, init: A, mut fun: F) -> A where - F: FnMut(A, &AccUpdate) -> A, + F: FnMut(A, &'a AccUpdate) -> A, { self.fold_impl(init, &mut fun) } @@ -3676,8 +3679,98 @@ pub mod zkapp_command { }) } + fn zkapp_cost( + proof_segments: usize, + signed_single_segments: usize, + signed_pair_segments: usize, + ) -> f64 { + // (*10.26*np + 10.08*n2 + 9.14*n1 < 69.45*) + let GenesisConstant { + zkapp_proof_update_cost: proof_cost, + zkapp_signed_pair_update_cost: signed_pair_cost, + zkapp_signed_single_update_cost: signed_single_cost, + .. + } = GENESIS_CONSTANT; + + (proof_cost * (proof_segments as f64)) + + (signed_pair_cost * (signed_pair_segments as f64)) + + (signed_single_cost * (signed_single_segments as f64)) + } + + /// Zkapp_command transactions are filtered using this predicate + /// - when adding to the transaction pool + /// - in incoming blocks pub fn valid_size(&self) -> Result<(), String> { - todo!() + let Self { + account_updates, + fee_payer: _, + memo: _, + } = self; + + let events_elements = + |events: &[Event]| -> usize { events.iter().map(|Event(e)| e.len()).sum() }; + + let mut all_updates = Vec::with_capacity(128); + let (mut num_event_elements, mut num_action_elements) = (0, 0); + + account_updates.fold((), |_, account_update| { + num_event_elements += events_elements(account_update.body.events.events()); + num_action_elements += events_elements(account_update.body.actions.events()); + all_updates.push(account_update); + }); + + let group = vec![((), (), ())] + .into_iter() + .chain(all_updates.iter().map(|_| ((), (), ()))) + .collect::>(); + + let groups = crate::proofs::zkapp::group::group_by_zkapp_command_rev::<(), (), ()>( + vec![self], + vec![vec![((), (), ())], group], + ); + + let (mut proof_segments, mut signed_single_segments, mut signed_pair_segments) = + (0, 0, 0); + + for state in &groups { + use crate::proofs::zkapp::group::{SegmentBasic, ZkappCommandIntermediateState}; + + let ZkappCommandIntermediateState { spec, .. } = state; + match spec { + SegmentBasic::Proved => proof_segments += 1, + SegmentBasic::OptSigned => signed_single_segments += 1, + SegmentBasic::OptSignedOptSigned => signed_pair_segments += 1, + } + } + + let GenesisConstant { + zkapp_transaction_cost_limit: cost_limit, + max_event_elements, + max_action_elements, + .. + } = GENESIS_CONSTANT; + + let zkapp_cost_within_limit = + Self::zkapp_cost(proof_segments, signed_single_segments, signed_pair_segments) + < cost_limit; + let valid_event_elements = num_event_elements <= max_event_elements; + let valid_action_elements = num_action_elements <= max_action_elements; + + if zkapp_cost_within_limit && valid_event_elements && valid_action_elements { + return Ok(()); + } + + let err = [ + (zkapp_cost_within_limit, "zkapp transaction too expensive"), + (valid_event_elements, "too many event elements"), + (valid_action_elements, "too many action elements"), + ] + .iter() + .filter(|(b, _s)| !b) + .map(|(_b, s)| s) + .join(";"); + + Err(err) } /// https://github.com/MinaProtocol/mina/blob/2ff0292b637684ce0372e7b8e23ec85404dc5091/src/lib/mina_base/zkapp_command.ml#L997 diff --git a/ledger/src/transaction_pool.rs b/ledger/src/transaction_pool.rs index 194f5b563..55be6352f 100644 --- a/ledger/src/transaction_pool.rs +++ b/ledger/src/transaction_pool.rs @@ -1131,9 +1131,8 @@ impl IndexedPool { let to_drop: Vec<_> = drop_queue.into_iter().chain(dropped_for_balance).collect(); - let (head, _tail) = match to_drop.split_first() { - Some((head, tail)) => (head, tail), - None => continue, + let Some(head) = to_drop.first() else { + continue; }; self.remove_applicable_exn(head); @@ -1393,10 +1392,9 @@ impl TransactionPool { }; } - let commit_conflicts_locally_generated = dropped_commit_conflicts + let _commit_conflicts_locally_generated = dropped_commit_conflicts .iter() - .filter(|cmd| self.locally_generated_uncommitted.remove(cmd).is_some()) - .collect::>(); + .filter(|cmd| self.locally_generated_uncommitted.remove(cmd).is_some()); for cmd in locally_generated_dropped { // If the dropped transaction was included in the winning chain, it'll