1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
use crate::{builder::Wallet, config::CommitteeTemplate};
use chain_crypto::bech32::Bech32;
use chain_vote::{
    committee::MemberCommunicationPublicKey, MemberCommunicationKey, MemberPublicKey,
};
use jormungandr_lib::interfaces::CommitteeIdDef;
use thor::{
    wallet::committee::{
        CommitteeCommunicationData, CommitteeCommunicationDataManager, CommitteeMembershipData,
        CommitteeMembershipDataManager,
    },
    CommitteeDataManager, WalletAlias,
};

pub fn generate_committee_data(
    wallets: &[Wallet],
    committees_templates: &[CommitteeTemplate],
) -> Result<CommitteeDataManager, Error> {
    let mut comm_manager = CommitteeCommunicationDataManager::default();
    let mut member_manager = CommitteeMembershipDataManager::default();

    let mut rng = rand::thread_rng();

    for committee_template in committees_templates.iter() {
        match committee_template {
            CommitteeTemplate::Generated {
                alias,
                member_pk,
                communication_pk,
            } => {
                let id: CommitteeIdDef = wallets
                    .iter()
                    .find(|w| w.has_alias(alias))
                    .ok_or_else(|| Error::CannotFindAlias(alias.clone()))?
                    .committee_id()?
                    .into();

                if let Some(member_pk) = member_pk {
                    member_manager
                        .committees_mut()
                        .push(CommitteeMembershipData::public(
                            id,
                            MemberPublicKey::try_from_bech32_str(member_pk)?,
                        ));
                } else if let Some(communication_pk) = communication_pk {
                    comm_manager
                        .committees_mut()
                        .push(CommitteeCommunicationData::public(
                            id,
                            MemberCommunicationPublicKey::try_from_bech32_str(communication_pk)?,
                        ));
                } else {
                    comm_manager
                        .committees_mut()
                        .push(CommitteeCommunicationData::private(
                            id,
                            MemberCommunicationKey::new(&mut rng),
                        ));
                }
            }
            CommitteeTemplate::External {
                id: hex,
                member_pk,
                communication_pk,
            } => {
                let id = CommitteeIdDef::from_hex(hex).unwrap();

                if let Some(member_pk) = member_pk {
                    member_manager
                        .committees_mut()
                        .push(CommitteeMembershipData::public(
                            id,
                            MemberPublicKey::try_from_bech32_str(member_pk)?,
                        ));
                } else if let Some(communication_pk) = communication_pk {
                    comm_manager
                        .committees_mut()
                        .push(CommitteeCommunicationData::public(
                            id,
                            MemberCommunicationPublicKey::try_from_bech32_str(communication_pk)?,
                        ));
                } else {
                    comm_manager
                        .committees_mut()
                        .push(CommitteeCommunicationData::private(
                            id,
                            MemberCommunicationKey::new(&mut rng),
                        ));
                }
            }
        }
    }

    Ok(CommitteeDataManager {
        communication: comm_manager.into(),
        membership: member_manager,
    })
}

#[derive(thiserror::Error, Debug)]
pub enum Error {
    #[error("cannot find alias '{0}' for any defined wallet")]
    CannotFindAlias(WalletAlias),
    #[error(transparent)]
    Wallet(#[from] crate::builder::settings::wallet::Error),
    #[error(transparent)]
    Bech3(#[from] chain_crypto::bech32::Error),
}