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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use std::time::{SystemTime, UNIX_EPOCH};
use vit_servicing_station_tests::common::raw_snapshot::RawSnapshot as RawSnapshotRequest;

/// Extensions for `MainnetWalletStateExtension` struct
pub trait MainnetWalletStateExtension {
    /// Converts to `RawSnapshotRequest`
    ///
    /// # Errors
    ///
    /// At any internal error while creating a snapshot
    fn try_into_raw_snapshot_request(
        self,
        parameters: SnapshotParameters,
    ) -> Result<RawSnapshotRequest, Error>;
}

impl MainnetWalletStateExtension for Vec<MainnetWalletState> {
    fn try_into_raw_snapshot_request(
        self,
        _parameters: SnapshotParameters,
    ) -> Result<RawSnapshotRequest, Error> {
        /*
        let (db_sync, _, _) = self
            .into_iter()
            .fold(
                MainnetNetworkBuilder::default(),
                MainnetNetworkBuilder::with,
            )
            .build();
        let _db = MockDbProvider::from(db_sync);
        */
        //let (outputs, _errs) =
        //    voting_tools_rs::voting_power(&db, VotingPowerArgs::default()).unwrap();
        //outputs.try_into_raw_snapshot_request(parameters)
        Ok(RawSnapshotRequest::default())
    }
}

/// Extensions for collection of voting tools `Output` struct
pub trait OutputsExtension {
    /// Converts to `RawSnapshotRequest`
    ///
    /// # Errors
    ///
    /// At any internal error while creating a snapshot
    fn try_into_raw_snapshot_request(
        self,
        parameters: SnapshotParameters,
    ) -> Result<RawSnapshotRequest, Error>;
}

impl OutputsExtension for Vec<SnapshotEntry> {
    fn try_into_raw_snapshot_request(
        self,
        parameters: SnapshotParameters,
    ) -> Result<RawSnapshotRequest, Error> {
        let mut regs = Vec::new();

        for output in self {
            regs.push(output.try_into_voting_registration()?);
        }

        Ok(RawSnapshotRequest {
            tag: parameters.tag.clone(),
            content: RawSnapshotInput {
                snapshot: regs.into(),
                update_timestamp: SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .expect("Time went backwards")
                    .as_secs()
                    .try_into()?,
                min_stake_threshold: parameters.min_stake_threshold,
                voting_power_cap: parameters.voting_power_cap,
                direct_voters_group: parameters.direct_voters_group.clone(),
                representatives_group: parameters.representatives_group,
                dreps: parameters.dreps,
            },
        })
    }
}

use jormungandr_lib::crypto::account::Identifier;
use mainnet_lib::wallet_state::{MainnetWalletState, TemplateError};
use mainnet_lib::SnapshotParameters;
use num_traits::ToPrimitive;
use snapshot_lib::registration::{
    Delegations as VotingDelegations, RewardAddress, StakeAddress, VotingRegistration,
};
use vit_servicing_station_lib::v0::endpoints::snapshot::RawSnapshotInput;
use voting_tools_rs::{SnapshotEntry, VotingKey, VotingPurpose};

/// Extensions for voting tools `Output` struct
pub trait OutputExtension {
    /// Converts to `VotingRegistration`
    ///
    /// # Errors
    ///
    /// At any internal error while creating a voting registration from output
    fn try_into_voting_registration(self) -> Result<VotingRegistration, Error>;
}

impl OutputExtension for SnapshotEntry {
    fn try_into_voting_registration(self) -> Result<VotingRegistration, Error> {
        Ok(VotingRegistration {
            stake_public_key: StakeAddress(self.stake_key.to_string()),
            voting_power: self
                .voting_power
                .to_u64()
                .ok_or_else(|| {
                    Error::CannotConvertFromOutput("cannot extract voting power".to_string())
                })?
                .into(),
            reward_address: RewardAddress(hex::encode(&self.rewards_address.0)),
            delegations: match self.voting_key {
                VotingKey::Direct(legacy) => VotingDelegations::Legacy(
                    Identifier::from_hex(&legacy.to_hex())
                        .expect("to_hex() always returns valid hex"),
                ),
                VotingKey::Delegated(delegated) => {
                    let mut new = vec![];
                    for (key, weight) in delegated {
                        new.push((
                            Identifier::from_hex(&key.to_hex())
                                .expect("to_hex() always returns valid hex"),
                            weight
                                .to_u32()
                                .expect("this tool expects voting powers that fit into a u32"),
                        ));
                    }
                    VotingDelegations::New(new)
                }
            },
            voting_purpose: Some(*self.voting_purpose.unwrap_or(VotingPurpose::CATALYST)),

            nonce: self.nonce,
        })
    }
}

/// Conversion related errors
#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// Errors derived from time conversion
    #[error("cannot convert time milliseconds since start of the epoch")]
    TimeConversion(#[from] std::num::TryFromIntError),
    /// Error related to incorrect conversion
    #[error("cannot convert voting registration from voting tools output due to: {0}")]
    CannotConvertFromOutput(String),
    /// Error related to snapshot conversion
    #[error(transparent)]
    Snapshot(#[from] snapshot_lib::Error),
    /// Error related to building mock snapshot
    #[error(transparent)]
    Template(#[from] TemplateError),
}