Skip to main content

coven_protocol/store_commit/
heads.rs

1use super::*;
2
3/// The wire body of one device's Store head. Every field here is signed.
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
5#[serde(deny_unknown_fields)]
6pub struct StoreDeviceHeadBody {
7    pub store_root_hash: ObjectHash,
8    pub author_registration: StoreDeviceRegistrationRef,
9    pub commit: StoreBatchCommitRef,
10    pub successor: SuccessorLink,
11}
12
13impl SignedBody for StoreDeviceHeadBody {
14    const DOMAIN: &'static [u8] = HEAD_DOMAIN;
15}
16
17pub type StoreDeviceHead = Signed<StoreDeviceHeadBody>;
18
19impl StoreDeviceHead {
20    pub fn signed(
21        store_root_hash: ObjectHash,
22        author_registration: StoreDeviceRegistrationRef,
23        commit: StoreBatchCommitRef,
24        successor: SuccessorLink,
25        signer: &UserKeypair,
26    ) -> Result<Self, StoreProtocolError> {
27        if commit.coord.sequence() == 0 {
28            return Err(StoreProtocolError::InvalidSequence(0));
29        }
30        Ok(Signed::sign(
31            StoreDeviceHeadBody {
32                store_root_hash,
33                author_registration,
34                commit,
35                successor,
36            },
37            signer,
38        ))
39    }
40
41    pub fn head_hash(&self) -> ObjectHash {
42        self.hash()
43    }
44
45    pub fn slot_sequence(&self) -> u64 {
46        self.commit.coord.sequence()
47    }
48
49    pub fn signature_is_valid_for(&self, expected_registration: &StoreDeviceRegistration) -> bool {
50        self.verify_by(&expected_registration.device_signing_pubkey)
51            .is_ok()
52    }
53
54    pub fn parse_at(
55        bytes: &[u8],
56        expected_store_root_hash: ObjectHash,
57        expected_registration: &StoreDeviceRegistration,
58        expected_ref: &StoreBatchCommitRef,
59    ) -> Result<Self, StoreProtocolError> {
60        let head: Self = crate::objects::decode_protocol_object(bytes)?;
61        head.require_version()?;
62        crate::objects::verify_store_root(expected_store_root_hash, head.store_root_hash)?;
63        head.author_registration
64            .verify_registration(expected_registration)?;
65        if &head.commit != expected_ref {
66            return Err(StoreProtocolError::Malformed(
67                "Store head activates a different exact commit".to_string(),
68            ));
69        }
70        if head.commit.coord.sequence() == 0 {
71            return Err(StoreProtocolError::InvalidSequence(0));
72        }
73        if !head.signature_is_valid_for(expected_registration) {
74            return Err(StoreProtocolError::InvalidSignature);
75        }
76        Ok(head)
77    }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
81#[serde(deny_unknown_fields)]
82pub struct StoreDeviceHeadRef {
83    pub head_hash: ObjectHash,
84    pub object: ExactObjectRef,
85}