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