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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
use super::mint_token::TokenIdentifier;
use crate::{crypto::hash::Hash, interfaces::Value};
use chain_impl_mockchain::{account::SpendingCounterIncreasing, accounting::account, block::Epoch};
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, convert::TryInto};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct DelegationType {
    pools: Vec<(Hash, u8)>,
}

impl DelegationType {
    pub fn pools(&self) -> Vec<(Hash, u8)> {
        self.pools.clone()
    }
}

impl From<account::DelegationType> for DelegationType {
    fn from(dt: account::DelegationType) -> Self {
        match dt {
            account::DelegationType::NonDelegated => DelegationType { pools: Vec::new() },
            account::DelegationType::Full(h) => DelegationType {
                pools: vec![(h.into(), 1)],
            },
            account::DelegationType::Ratio(v) => DelegationType {
                pools: v
                    .pools()
                    .iter()
                    .map(|(h, pp)| (h.clone().into(), *pp))
                    .collect(),
            },
        }
    }
}

impl From<DelegationType> for account::DelegationType {
    fn from(dt: DelegationType) -> Self {
        if dt.pools.is_empty() {
            account::DelegationType::NonDelegated
        } else if dt.pools.len() == 1 {
            account::DelegationType::Full(dt.pools[0].0.into_digest_of())
        } else {
            let v: u32 = dt.pools.iter().map(|(_, i)| (*i as u32)).sum();
            match v.try_into() {
                Err(error) => panic!("delegation type pool overflow: {}", error),
                Ok(parts) => {
                    let ratio = account::DelegationRatio::new(
                        parts,
                        dt.pools()
                            .iter()
                            .map(|(h, pp)| (h.into_digest_of(), *pp))
                            .collect(),
                    )
                    .expect("Assume this is always correct for a delegation type");
                    account::DelegationType::Ratio(ratio)
                }
            }
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct LastRewards {
    epoch: Epoch,
    reward: Value,
}

impl LastRewards {
    #[inline]
    pub fn epoch(&self) -> &Epoch {
        &self.epoch
    }

    #[inline]
    pub fn reward(&self) -> &Value {
        &self.reward
    }
}

/// represent the current state of an account in the ledger
///
/// This type is different from the [`UTxOInfo`] which represents another
/// kind of mean to manipulate assets in the blockchain.
///
/// [`UTxOInfo`]: ./struct.UTxOInfo.html
///
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AccountState {
    delegation: DelegationType,
    value: Value,
    counters: [u32; SpendingCounterIncreasing::LANES],
    tokens: BTreeMap<TokenIdentifier, Value>,
    last_rewards: LastRewards,
}

impl AccountState {
    /// retrieve the identifier to the stake pool this account is delegating its
    /// stake to.
    ///
    /// `None` means this account is not delegating its stake.
    #[inline]
    pub fn delegation(&self) -> &DelegationType {
        &self.delegation
    }

    /// the current fund associated to this account
    #[inline]
    pub fn value(&self) -> &Value {
        &self.value
    }

    /// The transaction counters for spending lanes.
    /// A counter in one of the existing lanes is used as part of the parameter
    /// when adding a new account input to a transaction.
    ///
    #[inline]
    pub fn counters(&self) -> [u32; SpendingCounterIncreasing::LANES] {
        self.counters
    }

    /// the last rewards transfered to account
    #[inline]
    pub fn last_rewards(&self) -> &LastRewards {
        &self.last_rewards
    }

    /// the current tokens associated to this account
    #[inline]
    pub fn tokens(&self) -> &BTreeMap<TokenIdentifier, Value> {
        &self.tokens
    }
}

/* ---------------- Conversion --------------------------------------------- */

impl From<account::LastRewards> for LastRewards {
    fn from(lr: account::LastRewards) -> Self {
        Self {
            epoch: lr.epoch,
            reward: lr.reward.into(),
        }
    }
}

impl From<LastRewards> for account::LastRewards {
    fn from(lr: LastRewards) -> Self {
        Self {
            epoch: lr.epoch,
            reward: lr.reward.into(),
        }
    }
}

impl<E> From<account::AccountState<E>> for AccountState {
    fn from(account: account::AccountState<E>) -> Self {
        let counters = account.spending.get_valid_counters();
        AccountState {
            delegation: account.delegation().clone().into(),
            value: account.value().into(),
            counters: [
                counters[0].into(),
                counters[1].into(),
                counters[2].into(),
                counters[3].into(),
                counters[4].into(),
                counters[5].into(),
                counters[6].into(),
                counters[7].into(),
            ],
            tokens: account
                .tokens
                .iter()
                .map(|(identifier, value)| {
                    (
                        TokenIdentifier::from(identifier.clone()),
                        Value::from(*value),
                    )
                })
                .collect(),
            last_rewards: account.last_rewards.into(),
        }
    }
}

impl<'a, E> From<&'a account::AccountState<E>> for AccountState {
    fn from(account: &'a account::AccountState<E>) -> Self {
        let counters = account.spending.get_valid_counters();
        AccountState {
            delegation: account.delegation().clone().into(),
            value: account.value().into(),
            counters: [
                counters[0].into(),
                counters[1].into(),
                counters[2].into(),
                counters[3].into(),
                counters[4].into(),
                counters[5].into(),
                counters[6].into(),
                counters[7].into(),
            ],
            tokens: account
                .tokens
                .iter()
                .map(|(identifier, value)| {
                    (
                        TokenIdentifier::from(identifier.clone()),
                        Value::from(*value),
                    )
                })
                .collect(),
            last_rewards: account.last_rewards.clone().into(),
        }
    }
}