simperby_governance/
lib.rs

1use serde::{Deserialize, Serialize};
2use simperby_core::utils::get_timestamp;
3use simperby_core::*;
4use simperby_network::*;
5use std::collections::{BTreeMap, BTreeSet};
6use std::sync::Arc;
7use tokio::sync::RwLock;
8
9pub type Error = eyre::Error;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct GovernanceStatus {
13    /// Agenda hashes and their voters.
14    pub votes: BTreeMap<Hash256, BTreeMap<PublicKey, Signature>>,
15}
16
17#[derive(Clone, Debug, Serialize, Deserialize)]
18#[serde(transparent)]
19pub struct Vote {
20    pub agenda_hash: Hash256,
21}
22
23impl ToHash256 for Vote {
24    fn to_hash256(&self) -> Hash256 {
25        self.agenda_hash
26    }
27}
28
29impl DmsMessage for Vote {
30    const DMS_TAG: &'static str = "governance";
31
32    fn check(&self) -> Result<(), Error> {
33        Ok(())
34    }
35
36    /// Agenda hash cryptographically contains the information of height. It's safe to ignore `dms_key`.
37    fn commit(
38        &self,
39        _dms_key: &DmsKey,
40        private_key: &PrivateKey,
41    ) -> Result<MessageCommitmentProof, CryptoError>
42    where
43        Self: Sized,
44    {
45        Signature::sign(self.to_hash256(), private_key).map(|signature| MessageCommitmentProof {
46            committer: private_key.public_key(),
47            signature,
48        })
49    }
50
51    fn verify_commitment(
52        &self,
53        proof: &MessageCommitmentProof,
54        _dms_key: &DmsKey,
55    ) -> Result<(), CryptoError> {
56        proof.signature.verify(self.to_hash256(), &proof.committer)
57    }
58}
59
60pub struct Governance {
61    dms: Arc<RwLock<Dms<Vote>>>,
62    fi: FinalizationInfo,
63    /// Note that this is not stored in the storage.
64    /// That's because the set of all verified agendas can be derived from repository.
65    verified_agendas: BTreeSet<Hash256>,
66}
67
68impl Governance {
69    pub async fn new(
70        dms: Arc<RwLock<Dms<Vote>>>,
71        fi: FinalizationInfo,
72        verified_agendas: BTreeSet<Hash256>,
73    ) -> Result<Self, Error> {
74        // TODO: this must set the DMS to accept messages only from
75        // the eligible governance set for this height.
76        Ok(Self {
77            dms,
78            fi,
79            verified_agendas,
80        })
81    }
82
83    pub async fn read(&self) -> Result<GovernanceStatus, Error> {
84        let votes = self.dms.read().await.read_messages().await?;
85        let mut result = BTreeMap::<Hash256, BTreeMap<PublicKey, Signature>>::default();
86        for vote in votes {
87            for committers in vote.committers {
88                result
89                    .entry(vote.message.to_hash256())
90                    .or_default()
91                    .insert(committers.committer, committers.signature);
92            }
93        }
94        let status = GovernanceStatus { votes: result };
95        Ok(status)
96    }
97
98    pub async fn register_verified_agenda_hash(
99        &mut self,
100        agenda_hash: Hash256,
101    ) -> Result<(), Error> {
102        self.verified_agendas.insert(agenda_hash);
103        Ok(())
104    }
105
106    pub async fn get_eligible_agendas(&self) -> Result<Vec<(Hash256, AgendaProof)>, Error> {
107        let governance_set = self
108            .fi
109            .reserved_state
110            .get_governance_set()
111            // TODO: handle integrity error
112            .unwrap()
113            .into_iter()
114            .collect::<BTreeMap<_, _>>();
115        let governance_state = self.read().await?;
116        let votes: Vec<(Hash256, VotingPower)> = governance_state
117            .votes
118            .iter()
119            .map(|(agenda, votes)| {
120                (
121                    *agenda,
122                    votes
123                        .keys()
124                        .map(|voter| governance_set.get(voter).unwrap())
125                        .sum(),
126                )
127            })
128            .filter(|(agenda, _)| self.verified_agendas.contains(agenda))
129            .collect();
130        let mut result = Vec::new();
131        let total_voting_power = governance_set.values().sum::<VotingPower>();
132        for (agenda, voted_power) in votes {
133            if voted_power * 2 > total_voting_power {
134                let proof: Vec<_> = governance_state.votes[&agenda]
135                    .iter()
136                    .map(|(k, s)| TypedSignature::<Agenda>::new(s.clone(), k.clone()))
137                    .collect();
138                result.push((
139                    agenda,
140                    AgendaProof {
141                        height: self.fi.header.height + 1,
142                        agenda_hash: agenda,
143                        proof,
144                        timestamp: get_timestamp(),
145                    },
146                ));
147            }
148        }
149        Ok(result)
150    }
151
152    pub async fn vote(&mut self, agenda_hash: Hash256) -> Result<(), Error> {
153        self.dms
154            .write()
155            .await
156            .commit_message(&Vote { agenda_hash })
157            .await?;
158        Ok(())
159    }
160
161    pub async fn flush(&self) -> Result<(), Error> {
162        Ok(())
163    }
164
165    pub async fn update(&mut self) -> Result<(), Error> {
166        Ok(())
167    }
168
169    pub fn get_dms(&self) -> Arc<RwLock<Dms<Vote>>> {
170        Arc::clone(&self.dms)
171    }
172}