Skip to content

Commit 27f50c8

Browse files
authored
Issue #102 mergeAggrs and mergePayoutsIntoBalances (#110)
* validator - domain - event - initial setup for the Events * validator - domain - event - `ad_unit` to the appropriate types and remove `ImpressionPricePerCase` * validator - domain - event - update * validator - domain - event - update types * validator - domain - event - update types * domain - balances_map - impl `sum()` method * validator - domain - event - partially impl `merge_aggregates` and update structs * merge_aggrs finish + testing * fix clippy warnings * validator - domain - event - fix impression ad_unit to Option and use `max` method
1 parent 83f805c commit 27f50c8

File tree

6 files changed

+337
-91
lines changed

6 files changed

+337
-91
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

domain/src/balances_map.rs

Lines changed: 84 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,63 @@
11
use std::collections::BTreeMap;
22

3-
use serde::{Deserialize, Serialize};
4-
53
use crate::{BigNum, Channel, DomainError, ValidatorDesc};
64
use num::rational::Ratio;
75

8-
type InnerBTreeMap = BTreeMap<String, BigNum>;
6+
pub type BalancesMap = BTreeMap<String, BigNum>;
97

10-
#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq)]
11-
#[serde(transparent)]
12-
pub struct BalancesMap(InnerBTreeMap);
8+
pub fn get_balances_after_fees_tree(
9+
balances: &BalancesMap,
10+
channel: &Channel,
11+
) -> Result<BalancesMap, DomainError> {
12+
let distribution = Distribution::new(balances, &channel)?;
1313

14-
impl BalancesMap {
15-
pub fn apply_fees(&self, on_channel: &Channel) -> Result<Self, DomainError> {
16-
let distribution = Distribution::new(&self.0, &on_channel)?;
14+
let mut balances_after_fees = BTreeMap::default();
15+
let mut total = BigNum::from(0);
1716

18-
let mut balances_after_fees = BTreeMap::default();
19-
let mut total = BigNum::from(0);
17+
for (key, value) in balances.iter() {
18+
let adjusted_balance = value * &distribution.ratio;
2019

21-
for (key, value) in self.0.iter() {
22-
let adjusted_balance = value * &distribution.ratio;
20+
total += &adjusted_balance;
21+
balances_after_fees.insert(key.clone(), adjusted_balance);
22+
}
2323

24-
total += &adjusted_balance;
25-
balances_after_fees.insert(key.clone(), adjusted_balance);
26-
}
24+
let rounding_error = distribution.rounding_error(&total)?;
2725

28-
let rounding_error = distribution.rounding_error(&total)?;
26+
let balances_after_fees = distribute_fee(
27+
balances_after_fees,
28+
rounding_error,
29+
distribution.fee_ratio,
30+
channel.spec.validators.into_iter(),
31+
);
2932

30-
let balances_after_fees = Self::distribute_fee(
31-
balances_after_fees,
32-
rounding_error,
33-
distribution.fee_ratio,
34-
on_channel.spec.validators.into_iter(),
35-
);
33+
Ok(balances_after_fees)
34+
}
3635

37-
Ok(Self(balances_after_fees))
38-
}
36+
fn distribute_fee<'a>(
37+
mut balances: BalancesMap,
38+
rounding_error: BigNum,
39+
fee_ratio: Ratio<BigNum>,
40+
validators: impl Iterator<Item = &'a ValidatorDesc>,
41+
) -> BalancesMap {
42+
for (index, validator) in validators.enumerate() {
43+
let fee = &validator.fee * &fee_ratio;
44+
45+
let fee_rounded = if index == 0 {
46+
&fee + &rounding_error
47+
} else {
48+
fee
49+
};
3950

40-
fn distribute_fee<'a>(
41-
mut balances: InnerBTreeMap,
42-
rounding_error: BigNum,
43-
fee_ratio: Ratio<BigNum>,
44-
validators: impl Iterator<Item = &'a ValidatorDesc>,
45-
) -> InnerBTreeMap {
46-
for (index, validator) in validators.enumerate() {
47-
let fee = &validator.fee * &fee_ratio;
48-
49-
let fee_rounded = if index == 0 {
50-
&fee + &rounding_error
51-
} else {
52-
fee
53-
};
54-
55-
if fee_rounded > 0.into() {
56-
let entry = balances
57-
.entry(validator.id.clone().into())
58-
.or_insert_with(|| 0.into());
59-
60-
*entry += &fee_rounded;
61-
}
62-
}
51+
if fee_rounded > 0.into() {
52+
let entry = balances
53+
.entry(validator.id.clone().into())
54+
.or_insert_with(|| 0.into());
6355

64-
balances
56+
*entry += &fee_rounded;
57+
}
6558
}
59+
60+
balances
6661
}
6762

6863
#[derive(Debug)]
@@ -82,7 +77,7 @@ struct Distribution {
8277
}
8378

8479
impl Distribution {
85-
pub fn new(for_balances: &InnerBTreeMap, on_channel: &Channel) -> Result<Self, DomainError> {
80+
pub fn new(for_balances: &BalancesMap, on_channel: &Channel) -> Result<Self, DomainError> {
8681
let deposit = on_channel.deposit_amount.clone();
8782

8883
let total_distributed: BigNum = for_balances.iter().map(|(_, balance)| balance).sum();
@@ -144,63 +139,60 @@ mod test {
144139

145140
mod applying_fee_returns_the_same_tree_with_zero_fees {
146141
use super::*;
147-
fn setup_balances_map(tree: &InnerBTreeMap) -> BalancesMap {
142+
fn setup_balances_map(balances_map: &BalancesMap) -> BalancesMap {
148143
let channel = get_zero_fee_channel();
149144

150-
let balances_map = BalancesMap(tree.clone());
151-
152-
let balances_after_fee = balances_map
153-
.apply_fees(&channel)
145+
let balances_after_fee = get_balances_after_fees_tree(balances_map, &channel)
154146
.expect("Calculation of fees failed");
155147

156148
balances_after_fee
157149
}
158150

159151
#[test]
160152
fn case_1_three_values() {
161-
let tree: InnerBTreeMap = vec![
153+
let balances_map: BalancesMap = vec![
162154
("a".to_string(), 1001.into()),
163155
("b".to_string(), 3124.into()),
164156
("c".to_string(), 122.into()),
165157
]
166158
.into_iter()
167159
.collect();
168160

169-
assert_eq!(setup_balances_map(&tree).0, tree);
161+
assert_eq!(setup_balances_map(&balances_map), balances_map);
170162
}
171163

172164
#[test]
173165
fn case_2_three_simple_values() {
174-
let tree: InnerBTreeMap = vec![
166+
let balances_map: BalancesMap = vec![
175167
("a".to_string(), 1.into()),
176168
("b".to_string(), 2.into()),
177169
("c".to_string(), 3.into()),
178170
]
179171
.into_iter()
180172
.collect();
181173

182-
assert_eq!(setup_balances_map(&tree).0, tree);
174+
assert_eq!(setup_balances_map(&balances_map), balances_map);
183175
}
184176

185177
#[test]
186178
fn case_3_one_value() {
187-
let tree: InnerBTreeMap = vec![("a".to_string(), BigNum::from(1))]
179+
let balances_map = vec![("a".to_string(), BigNum::from(1))]
188180
.into_iter()
189181
.collect();
190182

191-
assert_eq!(setup_balances_map(&tree).0, tree);
183+
assert_eq!(setup_balances_map(&balances_map), balances_map);
192184
}
193185

194186
#[test]
195187
fn case_4_two_values() {
196-
let tree: InnerBTreeMap = vec![
188+
let balances_map = vec![
197189
("a".to_string(), 1.into()),
198190
("b".to_string(), 99_999.into()),
199191
]
200192
.into_iter()
201193
.collect();
202194

203-
assert_eq!(setup_balances_map(&tree).0, tree);
195+
assert_eq!(setup_balances_map(&balances_map), balances_map);
204196
}
205197

206198
fn get_zero_fee_channel() -> Channel {
@@ -218,33 +210,30 @@ mod test {
218210
mod applying_fee_correctly {
219211
use super::*;
220212

221-
fn setup_balances_after_fee(tree: InnerBTreeMap) -> BalancesMap {
213+
fn setup_balances_after_fee(balances_map: BalancesMap) -> BalancesMap {
222214
let leader = get_validator("one", Some(50.into()));
223215
let follower = get_validator("two", Some(50.into()));
224216

225217
let spec = get_channel_spec(ValidatorsOption::Pair { leader, follower });
226218
let mut channel = get_channel("apply fees", &None, Some(spec));
227219
channel.deposit_amount = 10_000.into();
228220

229-
let balances_map = BalancesMap(tree);
230-
231-
let balances_after_fee = balances_map
232-
.apply_fees(&channel)
221+
let balances_after_fee = get_balances_after_fees_tree(&balances_map, &channel)
233222
.expect("Calculation of fees failed");
234223

235224
balances_after_fee
236225
}
237226

238227
#[test]
239228
fn case_1_partially_distributed() {
240-
let tree = vec![
229+
let balances_map = vec![
241230
("a".to_string(), 1_000.into()),
242231
("b".to_string(), 1_200.into()),
243232
]
244233
.into_iter()
245234
.collect();
246235

247-
let expected_tree: InnerBTreeMap = vec![
236+
let expected_balances: BalancesMap = vec![
248237
("a".to_string(), 990.into()),
249238
("b".to_string(), 1_188.into()),
250239
("one".to_string(), 11.into()),
@@ -253,27 +242,30 @@ mod test {
253242
.into_iter()
254243
.collect();
255244

256-
let balances_after_fee = setup_balances_after_fee(tree).0;
245+
let balances_after_fee = setup_balances_after_fee(balances_map);
257246
let actual_sum: BigNum = balances_after_fee.iter().map(|(_, v)| v).sum();
258247

259248
assert_eq!(
260-
expected_tree.iter().map(|(_, value)| value).sum::<BigNum>(),
249+
expected_balances
250+
.iter()
251+
.map(|(_, value)| value)
252+
.sum::<BigNum>(),
261253
actual_sum
262254
);
263-
assert_eq!(expected_tree, balances_after_fee);
255+
assert_eq!(expected_balances, balances_after_fee);
264256
}
265257

266258
#[test]
267-
fn case_2_partially_distributed_with_validator_in_the_input_tree() {
268-
let tree = vec![
259+
fn case_2_partially_distributed_with_validator_in_the_input_balances_map() {
260+
let balances_map = vec![
269261
("a".to_string(), 100.into()),
270262
("b".to_string(), 2_000.into()),
271263
("one".to_string(), 200.into()),
272264
]
273265
.into_iter()
274266
.collect();
275267

276-
let expected_tree: InnerBTreeMap = vec![
268+
let expected_balances: BalancesMap = vec![
277269
("a".to_string(), 99.into()),
278270
("b".to_string(), 1_980.into()),
279271
("one".to_string(), 209.into()),
@@ -282,20 +274,23 @@ mod test {
282274
.into_iter()
283275
.collect();
284276

285-
let balances_after_fee = setup_balances_after_fee(tree).0;
277+
let balances_after_fee = setup_balances_after_fee(balances_map);
286278
let actual_sum: BigNum = balances_after_fee.iter().map(|(_, v)| v).sum();
287279

288280
assert_eq!(
289-
expected_tree.iter().map(|(_, value)| value).sum::<BigNum>(),
281+
expected_balances
282+
.iter()
283+
.map(|(_, value)| value)
284+
.sum::<BigNum>(),
290285
actual_sum
291286
);
292-
assert_eq!(expected_tree, balances_after_fee);
287+
assert_eq!(expected_balances, balances_after_fee);
293288
}
294289

295290
#[test]
296291
/// also testing the rounding error correction
297292
fn case_3_fully_distributed() {
298-
let tree = vec![
293+
let balances_map = vec![
299294
("a".to_string(), 105.into()),
300295
("b".to_string(), 195.into()),
301296
("c".to_string(), 700.into()),
@@ -305,7 +300,7 @@ mod test {
305300
.into_iter()
306301
.collect();
307302

308-
let expected_tree: InnerBTreeMap = vec![
303+
let expected_balances: BalancesMap = vec![
309304
("a".to_string(), 103.into()),
310305
("b".to_string(), 193.into()),
311306
("c".to_string(), 693.into()),
@@ -317,20 +312,23 @@ mod test {
317312
.into_iter()
318313
.collect();
319314

320-
let balances_after_fee = setup_balances_after_fee(tree).0;
315+
let balances_after_fee = setup_balances_after_fee(balances_map);
321316
let actual_sum: BigNum = balances_after_fee.iter().map(|(_, v)| v).sum();
322317

323318
assert_eq!(
324-
expected_tree.iter().map(|(_, value)| value).sum::<BigNum>(),
319+
expected_balances
320+
.iter()
321+
.map(|(_, value)| value)
322+
.sum::<BigNum>(),
325323
actual_sum
326324
);
327-
assert_eq!(expected_tree, balances_after_fee);
325+
assert_eq!(expected_balances, balances_after_fee);
328326
}
329327
}
330328

331329
#[test]
332330
fn errors_when_fees_larger_that_deposit() {
333-
let tree: InnerBTreeMap = vec![("a".to_string(), 10.into()), ("b".to_string(), 10.into())]
331+
let balances_map = vec![("a".to_string(), 10.into()), ("b".to_string(), 10.into())]
334332
.into_iter()
335333
.collect();
336334

@@ -340,10 +338,7 @@ mod test {
340338
let mut channel = get_channel("zero fees", &None, Some(spec));
341339
channel.deposit_amount = 1_000.into();
342340

343-
let balances_map = BalancesMap(tree.clone());
344-
345-
let domain_error = balances_map
346-
.apply_fees(&channel)
341+
let domain_error = get_balances_after_fees_tree(&balances_map, &channel)
347342
.expect_err("Should be DomainError not allow fees sum to exceed the deposit");
348343

349344
assert_eq!(

domain/src/big_num.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ use std::ops::{Add, AddAssign, Div, Mul, Sub};
55
use std::str::FromStr;
66

77
use num::rational::Ratio;
8-
use num::Integer;
9-
use num_bigint::BigUint;
8+
use num::{BigUint, CheckedSub, Integer};
109
use num_derive::{Num, NumOps, One, Zero};
1110
use serde::{Deserialize, Deserializer, Serialize, Serializer};
1211

@@ -151,6 +150,12 @@ impl<'a> Sum<&'a BigNum> for BigNum {
151150
}
152151
}
153152

153+
impl CheckedSub for BigNum {
154+
fn checked_sub(&self, v: &Self) -> Option<Self> {
155+
self.0.checked_sub(&v.0).map(Self)
156+
}
157+
}
158+
154159
impl Mul<&Ratio<BigNum>> for &BigNum {
155160
type Output = BigNum;
156161

validator/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ domain = { version = "0.1", path = "../domain", features = ["repositories", "fix
1414
adapter = { version = "0.1", path = "../adapter", features = ["dummy-adapter"] }
1515
memory-repository = { version = "0.1", path = "../memory-repository" }
1616
chrono = { version = "0.4", features = ["serde"] }
17+
num-traits = "0.2"
1718
# Futures
1819
futures-preview = { version = "=0.3.0-alpha.16", features = ["compat", "io-compat"] }
1920
futures_legacy = { version = "0.1", package = "futures" }

validator/src/domain.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ pub use self::validator::{Validator, ValidatorError, ValidatorFuture};
44
pub use self::worker::{Worker, WorkerFuture};
55

66
pub mod channel;
7+
pub mod event;
78
pub mod validator;
89
pub mod worker;

0 commit comments

Comments
 (0)