coven_protocol/
store_commit.rs1use std::collections::BTreeMap;
4use std::collections::BTreeSet;
5use std::fmt;
6use std::str::FromStr;
7
8use serde::{Deserialize, Serialize};
9
10use super::membership::{
11 verify_membership_entry, AuthorHead, AuthorStreamId, MembershipChange, MembershipCoord,
12 MembershipEntry, MembershipEntryRef, MembershipGrantCreationAuthority, MembershipGrantId,
13 MembershipHeadRef, StoreMembershipConflictResolution, StoreMembershipConflictResolutionRef,
14};
15use crate::circle::{
16 AccessLeafId, CircleBootstrapCoverageRef, CircleBootstrapRef, CircleControlCoord,
17 CircleEpochId, CircleId, CircleMetadataCoord, CircleMetadataHeadRef,
18 CircleRosterConflictResolutionRef, CircleRosterCoord, CircleRosterHeadRef,
19};
20use crate::circle_control::StoreMembershipStateRef;
21use crate::objects::ObjectSlot;
22use crate::objects::{ExactObjectRef, ProviderDeviceBinding};
23use crate::write::WriteId;
24use coven_keys::encryption::KeyFingerprint;
25use coven_keys::keys::{self, UserKeypair};
26
27mod ack_snapshot;
28mod batch_commit;
29mod circle_ack;
30mod circle_snapshot;
31mod device_join;
32pub mod device_join_exchange;
33pub mod device_join_journal;
34mod device_state;
35mod heads;
36mod identifiers;
37mod membership_rollup;
38mod operation_refs;
39mod packages;
40mod protocol_root;
41mod publication;
42mod registration;
43mod retained_history;
44mod signed;
45mod validation;
46
47pub use ack_snapshot::*;
48pub use batch_commit::*;
49pub use circle_ack::*;
50pub use circle_snapshot::*;
51pub use device_join::*;
52pub use device_state::*;
53pub use heads::*;
54pub use identifiers::*;
55pub use membership_rollup::*;
56pub use packages::*;
57pub use protocol_root::*;
58pub use publication::*;
59pub use registration::*;
60pub use retained_history::*;
61pub use signed::{Signed, SignedBody};
62pub use validation::*;
63
64mod ordered_map_entries {
65 use std::collections::BTreeMap;
66
67 use serde::{Deserialize, Deserializer, Serialize, Serializer};
68
69 pub(super) fn serialize<K, V, S>(map: &BTreeMap<K, V>, serializer: S) -> Result<S::Ok, S::Error>
70 where
71 K: Ord + Serialize,
72 V: Serialize,
73 S: Serializer,
74 {
75 map.iter().collect::<Vec<_>>().serialize(serializer)
76 }
77
78 pub(super) fn deserialize<'de, K, V, D>(deserializer: D) -> Result<BTreeMap<K, V>, D::Error>
79 where
80 K: Ord + Deserialize<'de>,
81 V: Deserialize<'de>,
82 D: Deserializer<'de>,
83 {
84 let entries = Vec::<(K, V)>::deserialize(deserializer)?;
85 let entry_count = entries.len();
86 let map = entries.into_iter().collect::<BTreeMap<_, _>>();
87 if map.len() != entry_count {
88 return Err(serde::de::Error::custom(
89 "ordered map entries contain a duplicate key",
90 ));
91 }
92 Ok(map)
93 }
94}
95
96pub const STORE_PROTOCOL_VERSION: u32 = 1;
97
98pub(crate) const STORE_PROTOCOL_ROOT_SEMANTIC_PATH: &str = "store-v1/store-protocol-root";
99#[cfg(any(test, feature = "test-utils"))]
100pub const STORE_PROTOCOL_ROOT_LOGICAL_KEY: &str = "store-v1/store-protocol-root.json";
101pub(crate) const STORE_CANDIDATE_PREFIX: &str = "store-v1/candidates/";
102pub(crate) const STORE_HEAD_PREFIX: &str = "store-v1/heads/";
103pub(crate) const STORE_ACK_PREFIX: &str = "store-v1/acks/";
104pub(crate) const STORE_DEVICE_REGISTRATION_PREFIX: &str = "store-v1/devices/";
105pub(crate) const STORE_DEVICE_JOIN_ABANDONMENT_PREFIX: &str = "store-v1/device-join-abandonments/";
106pub(crate) const STORE_DEVICE_JOIN_CLEANUP_RECEIPT_PREFIX: &str =
107 "store-v1/device-join-cleanup-receipts/";
108pub(crate) const STORE_DEVICE_EXCLUSION_PROPOSAL_PREFIX: &str =
109 "store-v1/device-exclusion-proposals/";
110pub(crate) const STORE_DEVICE_EXCLUSION_OUTCOME_PREFIX: &str =
111 "store-v1/device-exclusion-outcomes/";
112pub(crate) const STORE_PROVIDER_ACCESS_GRANT_PREFIX: &str = "store-v1/provider-access/grants/";
113pub(crate) const STORE_OWNER_RECOVERY_PREFIX: &str = "store-v1/recovery/";
114pub(crate) const STORE_SNAPSHOT_META_PREFIX: &str = "store-v1/snapshots/";
115pub(crate) const STORE_SNAPSHOT_IMAGE_PREFIX: &str = "store-v1/snapshot-images/";
116pub(crate) const STORE_MEMBERSHIP_ENTRY_PREFIX: &str = "store-v1/membership/entries/";
117pub(crate) const STORE_MEMBERSHIP_HEAD_PREFIX: &str = "store-v1/membership/heads/";
118pub(crate) const STORE_MEMBERSHIP_ROLLUP_PREFIX: &str = "store-v1/membership-rollups/";
119
120const STORE_PROTOCOL_ROOT_DOMAIN: &[u8] = b"coven.store-protocol-root.v1\0";
121const COMMIT_DOMAIN: &[u8] = b"coven.store-batch-commit.v1\0";
122const HEAD_DOMAIN: &[u8] = b"coven.store-device-head.v1\0";
123const REGISTRATION_DOMAIN: &[u8] = b"coven.store-device-registration.v1\0";
124const DEVICE_READINESS_DOMAIN: &[u8] = b"coven.device-readiness.v1\0";
125const DEVICE_EXCLUSION_PROPOSAL_DOMAIN: &[u8] = b"coven.store-device-exclusion-proposal.v1\0";
126const DEVICE_EXCLUSION_DOMAIN: &[u8] = b"coven.store-device-exclusion.v1\0";
127const DEVICE_EXCLUSION_CANCELLATION_DOMAIN: &[u8] =
128 b"coven.store-device-exclusion-cancellation.v1\0";
129const OWNER_RECOVERY_NODE_DOMAIN: &[u8] = b"coven.owner-recovery-node.v1\0";
130const ACK_DOMAIN: &[u8] = b"coven.store-ack.v1\0";
131const CIRCLE_ACK_DOMAIN: &[u8] = b"coven.circle-ack.v1\0";
132const CIRCLE_SNAPSHOT_DOMAIN: &[u8] = b"coven.circle-snapshot-meta.v1\0";
133const SNAPSHOT_DOMAIN: &[u8] = b"coven.snapshot-meta.v1\0";
134const MEMBERSHIP_ROLLUP_DOMAIN: &[u8] = b"coven.store-membership-rollup.v1\0";
135const CANDIDATE_FAMILY_DOMAIN: &[u8] = b"coven.candidate-family.v1\0";
136const STREAM_ACTIVATION_ID_DOMAIN: &[u8] = b"coven.stream-activation-id.v1\0";
137const AUTHOR_STREAM_ID_DOMAIN: &[u8] = b"coven.author-stream-id.v1\0";
138const STORE_PUBLICATION_ENTRY_DOMAIN: &[u8] = b"coven.store-publication-entry.v1\0";
139const STORE_CURRENT_PUBLICATION_DOMAIN: &[u8] = b"coven.store-current-publication.v1\0";
140
141#[cfg(test)]
142#[path = "store_commit/tests.rs"]
143mod tests;