commonware_sync/
lib.rs

1//! Synchronize state between a server and client.
2//!
3//! This library how to use [commonware_storage::adb::any::sync] to synchronize a client's
4//! [commonware_storage::adb::any::Any] database to a server's database.
5//!
6//! It includes network protocols, database configuration, and utilities for creating test data.
7//!
8//! The sync example showcases how to:
9//! - Create and configure a [commonware_storage::adb::any::Any] database
10//! - Implement a network-based [commonware_storage::adb::any::sync::resolver::Resolver] for fetching operations
11//! - Use [commonware_storage::adb::any::sync] to synchronize the client's database state with the server's state
12
13use commonware_cryptography::Hasher as CryptoHasher;
14use commonware_storage::adb::any::Config;
15
16pub mod error;
17pub use error::Error;
18pub mod protocol;
19pub use protocol::*;
20pub mod resolver;
21pub use resolver::Resolver;
22
23/// Hasher type used in the database.
24pub type Hasher = commonware_cryptography::sha256::Sha256;
25
26/// Key type used in the database.
27pub type Key = commonware_cryptography::sha256::Digest;
28
29/// Value type used in the database.
30pub type Value = commonware_cryptography::sha256::Digest;
31
32/// Database type alias.
33pub type Database<E> = commonware_storage::adb::any::Any<E, Key, Value, Hasher, Translator>;
34
35/// Operation type alias.
36pub type Operation = commonware_storage::adb::operation::Fixed<Key, Value>;
37
38/// Translator type for the database.
39pub type Translator = commonware_storage::translator::EightCap;
40
41/// Returns the version of the crate.
42pub fn crate_version() -> &'static str {
43    env!("CARGO_PKG_VERSION")
44}
45
46/// Create a database configuration with appropriate partitioning.
47pub fn create_adb_config() -> Config<Translator> {
48    Config {
49        mmr_journal_partition: "mmr_journal".into(),
50        mmr_metadata_partition: "mmr_metadata".into(),
51        mmr_items_per_blob: 4096,
52        mmr_write_buffer: 1024,
53        log_journal_partition: "log_journal".into(),
54        log_items_per_blob: 4096,
55        log_write_buffer: 1024,
56        translator: Translator::default(),
57        thread_pool: None,
58        buffer_pool: commonware_runtime::buffer::PoolRef::new(1024, 10),
59        pruning_delay: 10,
60    }
61}
62
63/// Create deterministic test operations for demonstration purposes.
64///
65/// This function creates a sequence of Update operations followed by
66/// periodic Commit operations. The operations are deterministic based
67/// on the count and seed parameters.
68pub fn create_test_operations(count: usize, seed: u64) -> Vec<Operation> {
69    let mut operations = Vec::new();
70    let mut hasher = <Hasher as CryptoHasher>::new();
71
72    for i in 0..count {
73        let key = {
74            hasher.update(&i.to_be_bytes());
75            hasher.update(&seed.to_be_bytes());
76            hasher.finalize()
77        };
78
79        let value = {
80            hasher.update(&key);
81            hasher.update(b"value");
82            hasher.finalize()
83        };
84
85        operations.push(Operation::Update(key, value));
86
87        // Add a commit operation every 10 operations
88        if (i + 1) % 10 == 0 {
89            operations.push(Operation::Commit(i as u64 + 1));
90        }
91    }
92
93    // Always end with a commit
94    operations.push(Operation::Commit(count as u64));
95    operations
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101
102    #[test]
103    fn test_create_test_operations() {
104        let ops = create_test_operations(5, 12345);
105        assert_eq!(ops.len(), 6); // 5 operations + 1 commit
106
107        // Verify the last operation is a commit
108        if let Operation::Commit(loc) = &ops[5] {
109            assert_eq!(*loc, 5);
110        } else {
111            panic!("Last operation should be a commit");
112        }
113    }
114
115    #[test]
116    fn test_deterministic_operations() {
117        // Operations should be deterministic based on seed
118        let ops1 = create_test_operations(3, 12345);
119        let ops2 = create_test_operations(3, 12345);
120        assert_eq!(ops1, ops2);
121
122        // Different seeds should produce different operations
123        let ops3 = create_test_operations(3, 54321);
124        assert_ne!(ops1, ops3);
125    }
126}