1use std::collections::{BTreeMap, BTreeSet};
5
6use itertools::Itertools;
7use namada_core::address::{Address, EstablishedAddressGen};
8use namada_core::arith::checked;
9use namada_core::collections::{HashMap, HashSet};
10use namada_core::hash::Hash;
11use namada_core::{arith, storage};
12use namada_events::extend::{InnerTxHash, TxHash};
13use namada_events::{Event, EventToEmit, EventType};
14use namada_gas::{
15 Gas, MEMORY_ACCESS_GAS_PER_BYTE, STORAGE_DELETE_GAS_PER_BYTE,
16 STORAGE_WRITE_GAS_PER_BYTE,
17};
18use namada_tx::data::InnerTxId;
19use patricia_tree::map::StringPatriciaMap;
20use thiserror::Error;
21
22#[allow(missing_docs)]
23#[derive(Error, Debug)]
24pub enum Error {
25 #[error("Trying to update a temporary value")]
26 UpdateTemporaryValue,
27 #[error(
28 "Trying to update a validity predicate that a new account that's not \
29 yet committed to storage"
30 )]
31 UpdateVpOfNewAccount,
32 #[error("Trying to delete a validity predicate")]
33 DeleteVp,
34 #[error("Trying to write a temporary value after deleting")]
35 WriteTempAfterDelete,
36 #[error("Trying to write a temporary value after writing")]
37 WriteTempAfterWrite,
38 #[error("Replay protection key: {0}")]
39 ReplayProtection(String),
40 #[error("Arithmetic {0}")]
41 Arith(#[from] arith::Error),
42 #[error("Sized-diff overflowed")]
43 SizeDiffOverflow,
44 #[error("Value length overflowed")]
45 ValueLenOverflow,
46}
47
48impl From<Error> for crate::Error {
49 fn from(value: Error) -> Self {
50 crate::Error::new(value)
51 }
52}
53
54pub type Result<T> = std::result::Result<T, Error>;
56
57#[derive(Clone, Debug, PartialEq, Eq)]
59pub enum StorageModification {
60 Write {
62 value: Vec<u8>,
64 },
65 Delete,
67 InitAccount {
71 vp_code_hash: Hash,
73 },
74}
75
76#[derive(Debug, Clone, PartialEq, Eq)]
79pub(crate) struct TxWriteLog {
80 address_gen: Option<EstablishedAddressGen>,
82 write_log: HashMap<storage::Key, StorageModification>,
84 tx_temp_log: HashMap<storage::Key, Vec<u8>>,
87 events: WriteLogEvents,
89}
90
91impl Default for TxWriteLog {
92 fn default() -> Self {
93 Self {
94 address_gen: None,
95 write_log: HashMap::with_capacity(100),
96 tx_temp_log: HashMap::with_capacity(1),
97 events: WriteLogEvents {
98 tree: StringPatriciaMap::new(),
99 },
100 }
101 }
102}
103
104#[derive(Debug, Clone, PartialEq, Eq)]
107pub(crate) struct BatchedTxWriteLog {
108 address_gen: Option<EstablishedAddressGen>,
110 write_log: HashMap<storage::Key, StorageModification>,
112}
113
114#[derive(Debug, Clone)]
116pub(crate) struct WriteLogEvents {
117 pub tree: StringPatriciaMap<HashSet<Event>>,
118}
119
120impl std::cmp::PartialEq for WriteLogEvents {
121 fn eq(&self, other: &WriteLogEvents) -> bool {
122 if self.tree.len() != other.tree.len() {
123 return false;
124 }
125
126 self.tree.iter().all(|(event_type, event_set)| {
127 other
128 .tree
129 .get(event_type)
130 .map(|other_event_set| event_set == other_event_set)
131 .unwrap_or_default()
132 })
133 }
134}
135
136impl std::cmp::Eq for WriteLogEvents {}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct WriteLog {
141 pub(crate) block_address_gen: Option<EstablishedAddressGen>,
143 pub(crate) block_write_log: HashMap<storage::Key, StorageModification>,
146 pub(crate) batch_write_log: Vec<BatchedTxWriteLog>,
150 pub(crate) tx_write_log: TxWriteLog,
152 pub(crate) replay_protection: HashSet<Hash>,
156}
157
158#[derive(Debug)]
160pub struct PrefixIter {
161 pub iter:
163 std::collections::btree_map::IntoIter<String, StorageModification>,
164}
165
166impl Iterator for PrefixIter {
167 type Item = (String, StorageModification);
168
169 fn next(&mut self) -> Option<Self::Item> {
170 self.iter.next()
171 }
172}
173
174impl Default for WriteLog {
175 fn default() -> Self {
176 Self {
177 block_address_gen: None,
178 block_write_log: HashMap::with_capacity(100_000),
179 batch_write_log: Vec::with_capacity(5),
180 tx_write_log: Default::default(),
181 replay_protection: HashSet::with_capacity(1_000),
182 }
183 }
184}
185
186impl WriteLog {
187 pub fn read(
190 &self,
191 key: &storage::Key,
192 ) -> std::result::Result<(Option<&StorageModification>, Gas), arith::Error>
193 {
194 match self
196 .tx_write_log
197 .write_log
198 .get(key)
199 .or_else(|| {
200 self.batch_write_log
203 .iter()
204 .rev()
205 .find_map(|log| log.write_log.get(key))
206 })
207 .or_else(|| {
208 self.block_write_log.get(key)
210 }) {
211 Some(v) => {
212 let gas = match &v {
213 StorageModification::Write { value } => {
214 checked!(key.len() + value.len())?
215 }
216 StorageModification::Delete => key.len(),
217 StorageModification::InitAccount { vp_code_hash } => {
218 checked!(key.len() + vp_code_hash.len())?
219 }
220 } as u64;
221 Ok((
222 Some(v),
223 checked!(gas * MEMORY_ACCESS_GAS_PER_BYTE)?.into(),
224 ))
225 }
226 None => {
227 let gas = key.len() as u64;
228 Ok((None, checked!(gas * MEMORY_ACCESS_GAS_PER_BYTE)?.into()))
229 }
230 }
231 }
232
233 pub fn read_pre(
237 &self,
238 key: &storage::Key,
239 ) -> std::result::Result<(Option<&StorageModification>, Gas), arith::Error>
240 {
241 for bucket in self
242 .batch_write_log
243 .iter()
244 .rev()
245 .map(|batch_log| &batch_log.write_log)
246 .chain([&self.block_write_log])
247 {
248 if let Some(v) = bucket.get(key) {
249 let gas = match &v {
250 StorageModification::Write { value } => {
251 checked!(key.len() + value.len())?
252 }
253 StorageModification::Delete => key.len(),
254 StorageModification::InitAccount { vp_code_hash } => {
255 checked!(key.len() + vp_code_hash.len())?
256 }
257 } as u64;
258 return Ok((
259 Some(v),
260 checked!(gas * MEMORY_ACCESS_GAS_PER_BYTE)?.into(),
261 ));
262 }
263 }
264 let gas = key.len() as u64;
265 Ok((None, checked!(gas * MEMORY_ACCESS_GAS_PER_BYTE)?.into()))
266 }
267
268 pub fn read_temp(
272 &self,
273 key: &storage::Key,
274 ) -> Result<(Option<&Vec<u8>>, Gas)> {
275 match self.tx_write_log.tx_temp_log.get(key) {
277 Some(value) => {
278 let gas = checked!(key.len() + value.len())? as u64;
279
280 Ok((
281 Some(value),
282 checked!(gas * MEMORY_ACCESS_GAS_PER_BYTE)?.into(),
283 ))
284 }
285 None => {
286 let gas = key.len() as u64;
287 Ok((None, checked!(gas * MEMORY_ACCESS_GAS_PER_BYTE)?.into()))
288 }
289 }
290 }
291
292 pub fn write(
298 &mut self,
299 key: &storage::Key,
300 value: Vec<u8>,
301 ) -> Result<(Gas, i64)> {
302 let len = value.len();
303 if self.tx_write_log.tx_temp_log.contains_key(key) {
304 return Err(Error::UpdateTemporaryValue);
305 }
306 let len_signed =
307 i64::try_from(len).map_err(|_| Error::ValueLenOverflow)?;
308 let size_diff = match self.tx_write_log.write_log.get(key) {
309 Some(prev) => match &prev {
310 StorageModification::Write { value } => {
311 let val_len = i64::try_from(value.len())
312 .map_err(|_| Error::ValueLenOverflow)?;
313 checked!(len_signed - val_len)?
314 }
315 StorageModification::Delete => len_signed,
316 StorageModification::InitAccount { .. } => {
317 return Err(Error::UpdateVpOfNewAccount);
324 }
325 },
326 None => len_signed,
329 };
330
331 self.tx_write_log
332 .write_log
333 .insert(key.clone(), StorageModification::Write { value });
334
335 let gas = checked!(key.len() + len)? as u64;
336 Ok((
337 checked!(gas * STORAGE_WRITE_GAS_PER_BYTE)?.into(),
338 size_diff,
339 ))
340 }
341
342 pub fn protocol_write(
348 &mut self,
349 key: &storage::Key,
350 value: Vec<u8>,
351 ) -> Result<()> {
352 if self.tx_write_log.tx_temp_log.contains_key(key) {
353 return Err(Error::UpdateTemporaryValue);
354 }
355 if let Some(prev) = self
356 .block_write_log
357 .insert(key.clone(), StorageModification::Write { value })
358 {
359 match prev {
360 StorageModification::InitAccount { .. } => {
361 return Err(Error::UpdateVpOfNewAccount);
362 }
363 StorageModification::Write { .. }
364 | StorageModification::Delete => {}
365 }
366 }
367 Ok(())
368 }
369
370 pub fn write_temp(
378 &mut self,
379 key: &storage::Key,
380 value: Vec<u8>,
381 ) -> Result<(Gas, i64)> {
382 if let Some(prev) = self.tx_write_log.write_log.get(key) {
383 match prev {
384 StorageModification::Write { .. } => {
385 return Err(Error::WriteTempAfterWrite);
387 }
388 StorageModification::Delete => {
389 return Err(Error::WriteTempAfterDelete);
390 }
391 StorageModification::InitAccount { .. } => {
392 return Err(Error::UpdateVpOfNewAccount);
393 }
394 }
395 }
396
397 let len = value.len();
398 let len_signed =
399 i64::try_from(len).map_err(|_| Error::ValueLenOverflow)?;
400 let size_diff = match self.tx_write_log.tx_temp_log.get(key) {
401 Some(prev) => {
402 let prev_len = i64::try_from(prev.len())
403 .map_err(|_| Error::ValueLenOverflow)?;
404 checked!(len_signed - prev_len)?
405 }
406 None => len_signed,
409 };
410
411 self.tx_write_log.tx_temp_log.insert(key.clone(), value);
412
413 let gas = checked!(key.len() + len)? as u64;
416 Ok((
417 checked!(gas * MEMORY_ACCESS_GAS_PER_BYTE)?.into(),
418 size_diff,
419 ))
420 }
421
422 pub fn delete(&mut self, key: &storage::Key) -> Result<(Gas, i64)> {
427 if key.is_validity_predicate().is_some() {
428 return Err(Error::DeleteVp);
429 }
430 let size_diff = match self.tx_write_log.write_log.get(key) {
431 Some(prev) => match &prev {
432 StorageModification::Write { value } => value.len(),
433 StorageModification::Delete => 0,
434 StorageModification::InitAccount { .. } => {
435 return Err(Error::DeleteVp);
436 }
437 },
438 None => 0,
441 };
442
443 self.tx_write_log
444 .write_log
445 .insert(key.clone(), StorageModification::Delete);
446 let gas = checked!(key.len() + size_diff)? as u64;
447 let size_diff = i64::try_from(size_diff)
448 .ok()
449 .and_then(i64::checked_neg)
450 .ok_or(Error::SizeDiffOverflow)?;
451 Ok((
452 checked!(gas * STORAGE_DELETE_GAS_PER_BYTE)?.into(),
453 size_diff,
454 ))
455 }
456
457 pub fn protocol_delete(&mut self, key: &storage::Key) -> Result<()> {
461 if key.is_validity_predicate().is_some() {
462 return Err(Error::DeleteVp);
463 }
464 if let Some(prev) = self
465 .block_write_log
466 .insert(key.clone(), StorageModification::Delete)
467 {
468 match prev {
469 StorageModification::InitAccount { .. } => {
470 return Err(Error::DeleteVp);
471 }
472 StorageModification::Write { .. }
473 | StorageModification::Delete => {}
474 }
475 };
476 Ok(())
477 }
478
479 pub fn init_account(
481 &mut self,
482 storage_address_gen: &EstablishedAddressGen,
483 vp_code_hash: Hash,
484 entropy_source: &[u8],
485 ) -> (Address, Gas) {
486 let address_gen = self
489 .tx_write_log
490 .address_gen
491 .get_or_insert_with(|| storage_address_gen.clone());
492 let addr = address_gen.generate_address(entropy_source);
493 let key = storage::Key::validity_predicate(&addr);
494 let gas = ((key
495 .len()
496 .checked_add(vp_code_hash.len())
497 .expect("Cannot overflow")) as u64)
498 .checked_mul(STORAGE_WRITE_GAS_PER_BYTE)
499 .expect("Canno overflow");
500 self.tx_write_log
501 .write_log
502 .insert(key, StorageModification::InitAccount { vp_code_hash });
503 (addr, gas.into())
504 }
505
506 pub fn emit_event<E: EventToEmit>(&mut self, event: E) -> Option<Gas> {
509 self.emit_event_with_tx_hashes(event, None)
510 }
511
512 pub fn emit_event_with_tx_hashes<E: EventToEmit>(
517 &mut self,
518 event: E,
519 inner_tx_id: Option<InnerTxId<'_>>,
520 ) -> Option<Gas> {
521 let mut event = event.into();
522 let gas_cost = event.emission_gas_cost(MEMORY_ACCESS_GAS_PER_BYTE);
523 if gas_cost.as_ref().is_some() {
524 let event_type = event.kind().to_string();
525 if !self.tx_write_log.events.tree.contains_key(&event_type) {
526 self.tx_write_log
527 .events
528 .tree
529 .insert(&event_type, HashSet::new());
530 }
531 if let Some(inner_tx_id) = inner_tx_id {
532 event.extend(TxHash(inner_tx_id.wrapper_hash()));
533 event.extend(InnerTxHash(inner_tx_id.inner_hash()));
534 }
535 self.tx_write_log
536 .events
537 .tree
538 .get_mut(&event_type)
539 .unwrap()
540 .insert(event);
541 }
542 gas_cost.map(|gas| gas.into())
543 }
544
545 pub fn get_keys(&self) -> BTreeSet<storage::Key> {
549 self.tx_write_log
550 .write_log
551 .iter()
552 .map(|(key, _modification)| key.clone())
553 .collect()
554 }
555
556 pub fn get_partitioned_keys(
562 &self,
563 ) -> (BTreeSet<&storage::Key>, HashSet<&Address>) {
564 use itertools::Either;
565 self.tx_write_log
566 .write_log
567 .iter()
568 .partition_map(|(key, value)| {
569 match (key.is_validity_predicate(), value) {
570 (
571 Some(address),
572 StorageModification::InitAccount { .. },
573 ) => Either::Right(address),
574 _ => Either::Left(key),
575 }
576 })
577 }
578
579 pub fn get_initialized_accounts(&self) -> Vec<Address> {
581 self.tx_write_log
582 .write_log
583 .iter()
584 .filter_map(|(key, value)| {
585 match (key.is_validity_predicate(), value) {
586 (
587 Some(address),
588 StorageModification::InitAccount { .. },
589 ) => Some(address.clone()),
590 _ => None,
591 }
592 })
593 .collect()
594 }
595
596 pub fn take_events(&mut self) -> BTreeSet<Event> {
598 std::mem::take(&mut self.tx_write_log.events.tree)
599 .into_iter()
600 .flat_map(|(_, event_set)| event_set)
601 .collect()
602 }
603
604 #[inline]
607 pub fn lookup_events_with_prefix<'this, 'ty: 'this>(
608 &'this self,
609 event_type: &'ty EventType,
610 ) -> impl Iterator<Item = &'this Event> + 'this {
611 self.tx_write_log
612 .events
613 .tree
614 .iter_prefix(event_type)
615 .flat_map(|(_, event_set)| event_set)
616 }
617
618 #[inline]
621 pub fn get_events_of<E: EventToEmit>(
622 &self,
623 ) -> impl Iterator<Item = &Event> {
624 self.tx_write_log
625 .events
626 .tree
627 .iter_prefix(E::DOMAIN)
628 .flat_map(|(_, event_set)| event_set)
629 }
630
631 #[inline]
633 pub fn get_events(&self) -> impl Iterator<Item = &Event> {
634 self.tx_write_log.events.tree.values().flatten()
635 }
636
637 pub fn commit_tx_to_batch(&mut self) {
641 let tx_write_log = std::mem::take(&mut self.tx_write_log);
642 let batched_log = BatchedTxWriteLog {
643 address_gen: tx_write_log.address_gen,
644 write_log: tx_write_log.write_log,
645 };
646
647 self.batch_write_log.push(batched_log);
648 }
649
650 pub fn drop_tx(&mut self) {
654 self.tx_write_log = Default::default();
655 }
656
657 pub fn commit_batch_and_current_tx(&mut self) {
659 self.commit_tx_to_batch();
660 self.commit_batch_only();
661 }
662
663 pub fn commit_batch_only(&mut self) {
667 for log in std::mem::take(&mut self.batch_write_log) {
668 self.block_write_log.extend(log.write_log);
669 self.block_address_gen = log.address_gen;
670 }
671 }
672
673 pub fn drop_batch(&mut self) {
675 self.drop_tx();
676 self.batch_write_log = Default::default();
677 }
678
679 pub fn verifiers_and_changed_keys(
686 &self,
687 verifiers_from_tx: &BTreeSet<Address>,
688 ) -> (BTreeSet<Address>, BTreeSet<storage::Key>) {
689 let changed_keys: BTreeSet<storage::Key> = self.get_keys();
690 let initialized_accounts = self.get_initialized_accounts();
691 let mut verifiers = verifiers_from_tx.clone();
692
693 for key in changed_keys.iter() {
695 if let Some(addr) = key.fst_address() {
696 if !verifiers_from_tx.contains(addr)
702 && !initialized_accounts.contains(addr)
703 {
704 verifiers.insert(addr.clone());
706 }
707 }
708 }
709 (verifiers, changed_keys)
710 }
711
712 pub fn iter_prefix_pre(&self, prefix: &storage::Key) -> PrefixIter {
715 let mut matches = BTreeMap::new();
716
717 for (key, modification) in self.block_write_log.iter().chain(
718 self.batch_write_log
719 .iter()
720 .flat_map(|batch_log| batch_log.write_log.iter()),
721 ) {
722 if key.split_prefix(prefix).is_some() {
723 matches.insert(key.to_string(), modification.clone());
724 }
725 }
726
727 let iter = matches.into_iter();
728 PrefixIter { iter }
729 }
730
731 pub fn iter_prefix_post(&self, prefix: &storage::Key) -> PrefixIter {
734 let mut matches = BTreeMap::new();
735
736 for (key, modification) in self.block_write_log.iter().chain(
737 self.batch_write_log
738 .iter()
739 .flat_map(|batch_log| batch_log.write_log.iter())
740 .chain(self.tx_write_log.write_log.iter()),
741 ) {
742 if key.split_prefix(prefix).is_some() {
743 matches.insert(key.to_string(), modification.clone());
744 }
745 }
746
747 let iter = matches.into_iter();
748 PrefixIter { iter }
749 }
750
751 pub fn has_replay_protection_entry(&self, hash: &Hash) -> bool {
753 self.replay_protection.contains(hash)
754 }
755
756 pub fn write_tx_hash(&mut self, hash: Hash) -> Result<()> {
758 if !self.replay_protection.insert(hash) {
759 return Err(Error::ReplayProtection(format!(
761 "Requested a write of hash {hash} which has already been \
762 processed"
763 )));
764 }
765
766 Ok(())
767 }
768
769 pub(crate) fn redundant_tx_hash(&mut self, hash: &Hash) -> Result<()> {
771 if !self.replay_protection.swap_remove(hash) {
772 return Err(Error::ReplayProtection(format!(
773 "Requested a redundant modification on hash {hash} which is \
774 unknown"
775 )));
776 }
777 Ok(())
778 }
779}
780
781#[allow(clippy::cast_possible_wrap)]
782#[cfg(test)]
783mod tests {
784 use assert_matches::assert_matches;
785 use namada_core::address;
786 use pretty_assertions::assert_eq;
787 use proptest::prelude::*;
788
789 use super::*;
790 use crate::StateRead;
791
792 #[test]
793 fn test_crud_value() {
794 let mut write_log = WriteLog::default();
795 let key =
796 storage::Key::parse("key").expect("cannot parse the key string");
797
798 let (value, gas) = write_log.read(&key).unwrap();
800 assert!(value.is_none());
801 assert_eq!(
802 gas,
803 ((key.len() as u64) * MEMORY_ACCESS_GAS_PER_BYTE).into()
804 );
805
806 let (gas, diff) = write_log.delete(&key).unwrap();
808 assert_eq!(
809 gas,
810 (key.len() as u64 * STORAGE_DELETE_GAS_PER_BYTE).into()
811 );
812 assert_eq!(diff, 0);
813
814 let inserted = "inserted".as_bytes().to_vec();
816 let (gas, diff) = write_log.write(&key, inserted.clone()).unwrap();
817 assert_eq!(
818 gas,
819 ((key.len() + inserted.len()) as u64 * STORAGE_WRITE_GAS_PER_BYTE)
820 .into()
821 );
822 assert_eq!(diff, inserted.len() as i64);
823
824 let (value, gas) = write_log.read(&key).unwrap();
826 match value.expect("no read value") {
827 StorageModification::Write { value } => {
828 assert_eq!(*value, inserted)
829 }
830 _ => panic!("unexpected read result"),
831 }
832 assert_eq!(
833 gas,
834 (((key.len() + inserted.len()) as u64)
835 * MEMORY_ACCESS_GAS_PER_BYTE)
836 .into()
837 );
838
839 let updated = "updated".as_bytes().to_vec();
841 let (gas, diff) = write_log.write(&key, updated.clone()).unwrap();
842 assert_eq!(
843 gas,
844 ((key.len() + updated.len()) as u64 * STORAGE_WRITE_GAS_PER_BYTE)
845 .into()
846 );
847 assert_eq!(diff, updated.len() as i64 - inserted.len() as i64);
848
849 let (gas, diff) = write_log.delete(&key).unwrap();
851 assert_eq!(
852 gas,
853 ((key.len() + updated.len()) as u64 * STORAGE_DELETE_GAS_PER_BYTE)
854 .into()
855 );
856 assert_eq!(diff, -(updated.len() as i64));
857
858 let (gas, diff) = write_log.delete(&key).unwrap();
860 assert_eq!(
861 gas,
862 (key.len() as u64 * STORAGE_DELETE_GAS_PER_BYTE).into()
863 );
864 assert_eq!(diff, 0);
865
866 let (value, gas) = write_log.read(&key).unwrap();
868 match &value.expect("no read value") {
869 StorageModification::Delete => {}
870 _ => panic!("unexpected result"),
871 }
872 assert_eq!(gas, (key.len() as u64 * MEMORY_ACCESS_GAS_PER_BYTE).into());
873
874 let reinserted = "reinserted".as_bytes().to_vec();
876 let (gas, diff) = write_log.write(&key, reinserted.clone()).unwrap();
877 assert_eq!(
878 gas,
879 ((key.len() + reinserted.len()) as u64
880 * STORAGE_WRITE_GAS_PER_BYTE)
881 .into()
882 );
883 assert_eq!(diff, reinserted.len() as i64);
884 }
885
886 #[test]
887 fn test_crud_account() {
888 let mut write_log = WriteLog::default();
889 let address_gen = EstablishedAddressGen::new("test");
890
891 let init_vp = "initialized".as_bytes().to_vec();
893 let vp_hash = Hash::sha256(init_vp);
894 let (addr, gas) = write_log.init_account(&address_gen, vp_hash, &[]);
895 let vp_key = storage::Key::validity_predicate(&addr);
896 assert_eq!(
897 gas,
898 ((vp_key.len() + vp_hash.len()) as u64
899 * STORAGE_WRITE_GAS_PER_BYTE)
900 .into()
901 );
902
903 let (value, gas) = write_log.read(&vp_key).unwrap();
905 match value.expect("no read value") {
906 StorageModification::InitAccount { vp_code_hash } => {
907 assert_eq!(*vp_code_hash, vp_hash)
908 }
909 _ => panic!("unexpected result"),
910 }
911 assert_eq!(
912 gas,
913 ((vp_key.len() + vp_hash.len()) as u64
914 * MEMORY_ACCESS_GAS_PER_BYTE)
915 .into()
916 );
917
918 let (_changed_keys, init_accounts) = write_log.get_partitioned_keys();
920 assert!(init_accounts.contains(&&addr));
921 assert_eq!(init_accounts.len(), 1);
922 }
923
924 #[test]
925 fn test_update_initialized_account_should_fail() {
926 let mut write_log = WriteLog::default();
927 let address_gen = EstablishedAddressGen::new("test");
928
929 let init_vp = "initialized".as_bytes().to_vec();
930 let vp_hash = Hash::sha256(init_vp);
931 let (addr, _) = write_log.init_account(&address_gen, vp_hash, &[]);
932 let vp_key = storage::Key::validity_predicate(&addr);
933
934 let updated_vp = "updated".as_bytes().to_vec();
936 let updated_vp_hash = Hash::sha256(updated_vp);
937 let result = write_log
938 .write(&vp_key, updated_vp_hash.to_vec())
939 .unwrap_err();
940 assert_matches!(result, Error::UpdateVpOfNewAccount);
941 }
942
943 #[test]
944 fn test_delete_initialized_account_should_fail() {
945 let mut write_log = WriteLog::default();
946 let address_gen = EstablishedAddressGen::new("test");
947
948 let init_vp = "initialized".as_bytes().to_vec();
949 let vp_hash = Hash::sha256(init_vp);
950 let (addr, _) = write_log.init_account(&address_gen, vp_hash, &[]);
951 let vp_key = storage::Key::validity_predicate(&addr);
952
953 let result = write_log.delete(&vp_key).unwrap_err();
955 assert_matches!(result, Error::DeleteVp);
956 }
957
958 #[test]
959 fn test_delete_vp_should_fail() {
960 let mut write_log = WriteLog::default();
961 let addr = address::testing::established_address_1();
962 let vp_key = storage::Key::validity_predicate(&addr);
963
964 let result = write_log.delete(&vp_key).unwrap_err();
966 assert_matches!(result, Error::DeleteVp);
967 }
968
969 #[test]
970 fn test_commit() {
971 let mut state = crate::testing::TestState::default();
972 let address_gen = EstablishedAddressGen::new("test");
973
974 let key1 =
975 storage::Key::parse("key1").expect("cannot parse the key string");
976 let key2 =
977 storage::Key::parse("key2").expect("cannot parse the key string");
978 let key3 =
979 storage::Key::parse("key3").expect("cannot parse the key string");
980 let key4 =
981 storage::Key::parse("key4").expect("cannot parse the key string");
982
983 let vp1 = Hash::sha256("vp1".as_bytes());
985 let (addr1, _) = state.write_log.init_account(&address_gen, vp1, &[]);
986 state.write_log.commit_batch_and_current_tx();
987
988 let val1 = "val1".as_bytes().to_vec();
990 let _ = state.write_log.write(&key1, val1.clone()).unwrap();
991 let _ = state.write_log.write(&key2, val1.clone()).unwrap();
992 let _ = state.write_log.write(&key3, val1.clone()).unwrap();
993 let _ = state.write_log.write_temp(&key4, val1.clone()).unwrap();
994 state.write_log.commit_batch_and_current_tx();
995
996 let val2 = "val2".as_bytes().to_vec();
998 let _ = state.write_log.write(&key1, val2.clone()).unwrap();
999 let _ = state.write_log.write(&key2, val2.clone()).unwrap();
1000 let _ = state.write_log.write(&key3, val2).unwrap();
1001 state.write_log.drop_tx();
1002
1003 let val3 = "val3".as_bytes().to_vec();
1005 let _ = state.write_log.delete(&key2).unwrap();
1006 let _ = state.write_log.write(&key3, val3.clone()).unwrap();
1007 state.write_log.commit_batch_and_current_tx();
1008
1009 state.commit_block().expect("commit failed");
1011
1012 let (vp_code_hash, _gas) = state
1013 .validity_predicate::<namada_parameters::Store<()>>(&addr1)
1014 .expect("vp read failed");
1015 assert_eq!(vp_code_hash, Some(vp1));
1016 let (value, _) = state.db_read(&key1).expect("read failed");
1017 assert_eq!(value.expect("no read value"), val1);
1018 let (value, _) = state.db_read(&key2).expect("read failed");
1019 assert!(value.is_none());
1020 let (value, _) = state.db_read(&key3).expect("read failed");
1021 assert_eq!(value.expect("no read value"), val3);
1022 let (value, _) = state.db_read(&key4).expect("read failed");
1023 assert_eq!(value, None);
1024 }
1025
1026 #[test]
1027 fn test_replay_protection_commit() {
1028 let mut state = crate::testing::TestState::default();
1029
1030 {
1031 let write_log = state.write_log_mut();
1032 write_log
1034 .write_tx_hash(Hash::sha256("tx1".as_bytes()))
1035 .unwrap();
1036 write_log
1037 .write_tx_hash(Hash::sha256("tx2".as_bytes()))
1038 .unwrap();
1039 write_log
1040 .write_tx_hash(Hash::sha256("tx3".as_bytes()))
1041 .unwrap();
1042 }
1043
1044 state.commit_block().expect("commit failed");
1046
1047 assert!(state.write_log.replay_protection.is_empty());
1048 for tx in ["tx1", "tx2", "tx3"] {
1049 let hash = Hash::sha256(tx.as_bytes());
1050 assert!(
1051 state
1052 .has_replay_protection_entry(&hash)
1053 .expect("read failed")
1054 );
1055 }
1056
1057 {
1058 let write_log = state.write_log_mut();
1059 write_log
1061 .write_tx_hash(Hash::sha256("tx4".as_bytes()))
1062 .unwrap();
1063 write_log
1064 .write_tx_hash(Hash::sha256("tx5".as_bytes()))
1065 .unwrap();
1066 write_log
1067 .write_tx_hash(Hash::sha256("tx6".as_bytes()))
1068 .unwrap();
1069
1070 write_log
1072 .redundant_tx_hash(&Hash::sha256("tx4".as_bytes()))
1073 .unwrap();
1074 }
1075
1076 state.commit_block().expect("commit failed");
1078
1079 assert!(state.write_log.replay_protection.is_empty());
1080 for tx in ["tx1", "tx2", "tx3", "tx5", "tx6"] {
1081 assert!(
1082 state
1083 .has_replay_protection_entry(&Hash::sha256(tx.as_bytes()))
1084 .expect("read failed")
1085 );
1086 }
1087 assert!(
1088 !state
1089 .has_replay_protection_entry(&Hash::sha256("tx4".as_bytes()))
1090 .expect("read failed")
1091 );
1092 {
1093 let write_log = state.write_log_mut();
1094 write_log
1095 .write_tx_hash(Hash::sha256("tx7".as_bytes()))
1096 .unwrap();
1097
1098 assert!(
1100 state
1101 .write_log
1102 .redundant_tx_hash(&Hash::sha256("tx8".as_bytes()))
1103 .is_err()
1104 );
1105
1106 }
1111 }
1112
1113 #[test]
1115 fn test_write_after_temp_disallowed() {
1116 let mut state = crate::testing::TestState::default();
1117
1118 let key1 =
1119 storage::Key::parse("key1").expect("cannot parse the key string");
1120 let val1 = "val1".as_bytes().to_vec();
1121 let _ = state.write_log.write_temp(&key1, val1.clone()).unwrap();
1123 assert!(matches!(
1124 state.write_log.write(&key1, val1.clone()),
1125 Err(Error::UpdateTemporaryValue)
1126 ));
1127 }
1128
1129 #[test]
1131 fn test_write_temp_after_write_disallowed() {
1132 let mut state = crate::testing::TestState::default();
1133
1134 let key1 =
1135 storage::Key::parse("key1").expect("cannot parse the key string");
1136 let val1 = "val1".as_bytes().to_vec();
1137 let _ = state.write_log.write(&key1, val1.clone()).unwrap();
1139 assert!(matches!(
1140 state.write_log.write_temp(&key1, val1.clone()),
1141 Err(Error::WriteTempAfterWrite)
1142 ));
1143 }
1144
1145 #[test]
1147 fn test_write_temp_after_delete_disallowed() {
1148 let mut state = crate::testing::TestState::default();
1149
1150 let key1 =
1151 storage::Key::parse("key1").expect("cannot parse the key string");
1152 let val1 = "val1".as_bytes().to_vec();
1153 let _ = state.write_log.delete(&key1).unwrap();
1155 assert!(matches!(
1156 state.write_log.write_temp(&key1, val1.clone()),
1157 Err(Error::WriteTempAfterDelete)
1158 ));
1159 }
1160
1161 prop_compose! {
1162 fn arb_verifiers_changed_key_tx_all_key()
1163 (verifiers_from_tx in testing::arb_verifiers_from_tx())
1164 (tx_write_log in testing::arb_tx_write_log(verifiers_from_tx.clone()),
1165 verifiers_from_tx in Just(verifiers_from_tx))
1166 -> (BTreeSet<Address>, HashMap<storage::Key, StorageModification>) {
1167 (verifiers_from_tx, tx_write_log)
1168 }
1169 }
1170
1171 proptest! {
1172 #[test]
1173 fn verifiers_changed_key_tx_all_key(
1174 (verifiers_from_tx, write_log) in arb_verifiers_changed_key_tx_all_key(),
1175 ) {
1176 verifiers_changed_key_tx_all_key_aux(verifiers_from_tx, write_log)
1177 }
1178
1179 #[test]
1180 fn test_batched_txs(modifications in testing::arb_batched_txs()) {
1181 test_batched_txs_aux(modifications)
1182 }
1183 }
1184
1185 fn verifiers_changed_key_tx_all_key_aux(
1196 verifiers_from_tx: BTreeSet<Address>,
1197 write_log: HashMap<storage::Key, StorageModification>,
1198 ) {
1199 let write_log = WriteLog {
1200 tx_write_log: super::TxWriteLog {
1201 write_log,
1202 ..Default::default()
1203 },
1204 ..WriteLog::default()
1205 };
1206
1207 let (verifiers, changed_keys) =
1208 write_log.verifiers_and_changed_keys(&verifiers_from_tx);
1209
1210 println!("verifiers_from_tx {:#?}", verifiers_from_tx);
1211 for verifier_from_tx in verifiers_from_tx {
1212 assert!(verifiers.contains(&verifier_from_tx));
1214 }
1215
1216 let (_changed_keys, initialized_accounts) =
1217 write_log.get_partitioned_keys();
1218 for key in changed_keys.iter() {
1219 if let Some(addr_from_key) = key.fst_address() {
1220 if !initialized_accounts.contains(addr_from_key) {
1221 assert!(verifiers.contains(addr_from_key));
1223 }
1224 }
1225 }
1226
1227 println!("verifiers {:#?}", verifiers);
1228 println!("changed_keys {:#?}", changed_keys);
1229 println!("initialized_accounts {:#?}", initialized_accounts);
1230 for initialized_account in initialized_accounts {
1231 assert!(!verifiers.contains(initialized_account));
1233 let vp_key = storage::Key::validity_predicate(initialized_account);
1235 assert!(changed_keys.contains(&vp_key));
1236 }
1237 }
1238
1239 fn test_batched_txs_aux(
1242 txs: Vec<HashMap<storage::Key, StorageModification>>,
1243 ) {
1244 let mut write_log = WriteLog::default();
1245
1246 for tx in txs {
1247 write_log.tx_write_log.write_log = tx;
1249
1250 let keys: HashSet<storage::Key> = write_log
1252 .batch_write_log
1253 .iter()
1254 .flat_map(|batch| batch.write_log.keys())
1255 .cloned()
1256 .collect();
1257
1258 for key in keys.clone() {
1260 let (modification, _gas) = write_log.read_pre(&key).unwrap();
1263 let modification = modification.unwrap();
1264
1265 let mut found_match = false;
1268 for (key_str, modification_from_iter) in
1269 write_log.iter_prefix_pre(&key)
1270 {
1271 if key_str == key.to_string() {
1273 found_match = true;
1274 assert_eq!(modification, &modification_from_iter);
1275 } else {
1276 assert!(key_str.contains(&key.to_string()));
1277 }
1278 }
1279 assert!(
1280 found_match,
1281 "Expected key {key} not found in iter_prefix_pre"
1282 );
1283 }
1284
1285 write_log.commit_tx_to_batch();
1287
1288 let keys: HashSet<storage::Key> = write_log
1290 .batch_write_log
1291 .iter()
1292 .flat_map(|batch| batch.write_log.keys())
1293 .chain(write_log.tx_write_log.write_log.keys())
1294 .cloned()
1295 .collect();
1296
1297 for key in keys.clone() {
1300 let (modification, _gas) = write_log.read(&key).unwrap();
1303 let modification = modification.unwrap();
1304
1305 let mut found_match = false;
1308 for (key_str, modification_from_iter) in
1309 write_log.iter_prefix_post(&key)
1310 {
1311 if key_str == key.to_string() {
1313 found_match = true;
1314 assert_eq!(modification, &modification_from_iter);
1315 } else {
1316 assert!(key_str.contains(&key.to_string()));
1317 }
1318 }
1319 assert!(
1320 found_match,
1321 "Expected key {key} not found in iter_prefix_post"
1322 );
1323 }
1324 }
1325 }
1326}
1327
1328#[cfg(any(test, feature = "testing"))]
1330pub mod testing {
1331 use namada_core::address::testing::arb_address;
1332 use namada_core::hash::HASH_LENGTH;
1333 use namada_core::storage::testing::arb_key;
1334 use proptest::collection;
1335 use proptest::prelude::{Just, Strategy, any, prop_oneof};
1336
1337 use super::*;
1338
1339 pub fn arb_tx_write_log(
1342 verifiers_from_tx: BTreeSet<Address>,
1343 ) -> impl Strategy<Value = HashMap<storage::Key, StorageModification>> + 'static
1344 {
1345 arb_key().prop_flat_map(move |key| {
1346 let can_init_account = key
1349 .is_validity_predicate()
1350 .map(|owner| !verifiers_from_tx.contains(owner))
1351 .unwrap_or_default();
1352 collection::hash_map(
1353 Just(key),
1354 arb_storage_modification(can_init_account),
1355 0..100,
1356 )
1357 .prop_map(|map| map.into_iter().collect())
1358 })
1359 }
1360
1361 pub fn arb_batched_txs()
1365 -> impl Strategy<Value = Vec<HashMap<storage::Key, StorageModification>>>
1366 + 'static {
1367 const COMMON_KEYS_LEN: usize = 10;
1368
1369 let common_keys = collection::vec(arb_key(), COMMON_KEYS_LEN);
1370 (
1371 common_keys,
1373 collection::vec(
1375 (
1377 collection::vec(
1378 arb_storage_modification(false),
1379 COMMON_KEYS_LEN,
1380 ),
1381 collection::hash_map(
1383 arb_key(),
1384 arb_storage_modification(false),
1385 1..10,
1386 ),
1387 ),
1388 1..10,
1389 ),
1390 )
1391 .prop_map(|(common_keys, modifications)| {
1392 modifications
1393 .into_iter()
1394 .map(|(common_key_modifications, other_modifications)| {
1395 common_keys
1396 .clone()
1397 .into_iter()
1398 .zip(common_key_modifications)
1399 .chain(other_modifications)
1400 .collect::<HashMap<_, _>>()
1401 })
1402 .collect::<Vec<_>>()
1403 })
1404 }
1405
1406 pub fn arb_verifiers_from_tx() -> impl Strategy<Value = BTreeSet<Address>> {
1408 collection::btree_set(arb_address(), 0..10)
1409 }
1410
1411 pub fn arb_storage_modification(
1413 can_init_account: bool,
1414 ) -> impl Strategy<Value = StorageModification> {
1415 if can_init_account {
1416 prop_oneof![
1417 any::<Vec<u8>>()
1418 .prop_map(|value| StorageModification::Write { value }),
1419 Just(StorageModification::Delete),
1420 any::<[u8; HASH_LENGTH]>().prop_map(|hash| {
1421 StorageModification::InitAccount {
1422 vp_code_hash: Hash(hash),
1423 }
1424 }),
1425 ]
1426 .boxed()
1427 } else {
1428 prop_oneof![
1429 any::<Vec<u8>>()
1430 .prop_map(|value| StorageModification::Write { value }),
1431 Just(StorageModification::Delete),
1432 ]
1433 .boxed()
1434 }
1435 }
1436}