1
1
use std:: collections:: BTreeMap ;
2
2
3
+ use serde:: { Deserialize , Serialize } ;
4
+
3
5
use crate :: { BigNum , Channel , DomainError , ValidatorDesc } ;
4
6
use num:: rational:: Ratio ;
5
7
6
- pub type BalancesMap = BTreeMap < String , BigNum > ;
8
+ type InnerBTreeMap = BTreeMap < String , BigNum > ;
7
9
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) ?;
10
+ #[ derive( Default , Clone , Debug , Serialize , Deserialize , PartialEq ) ]
11
+ #[ serde( transparent) ]
12
+ pub struct BalancesMap ( InnerBTreeMap ) ;
13
13
14
- let mut balances_after_fees = BTreeMap :: default ( ) ;
15
- let mut total = BigNum :: from ( 0 ) ;
14
+ impl BalancesMap {
15
+ pub fn apply_fees ( & self , on_channel : & Channel ) -> Result < Self , DomainError > {
16
+ let distribution = Distribution :: new ( & self . 0 , & on_channel) ?;
16
17
17
- for ( key , value ) in balances . iter ( ) {
18
- let adjusted_balance = value * & distribution . ratio ;
18
+ let mut balances_after_fees = BTreeMap :: default ( ) ;
19
+ let mut total = BigNum :: from ( 0 ) ;
19
20
20
- total += & adjusted_balance;
21
- balances_after_fees. insert ( key. clone ( ) , adjusted_balance) ;
22
- }
21
+ for ( key, value) in self . 0 . iter ( ) {
22
+ let adjusted_balance = value * & distribution. ratio ;
23
23
24
- let rounding_error = distribution. rounding_error ( & total) ?;
24
+ total += & adjusted_balance;
25
+ balances_after_fees. insert ( key. clone ( ) , adjusted_balance) ;
26
+ }
25
27
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
- ) ;
28
+ let rounding_error = distribution. rounding_error ( & total) ?;
32
29
33
- Ok ( balances_after_fees)
34
- }
35
-
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
- } ;
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
+ ) ;
50
36
51
- if fee_rounded > 0 . into ( ) {
52
- let entry = balances
53
- . entry ( validator. id . clone ( ) . into ( ) )
54
- . or_insert_with ( || 0 . into ( ) ) ;
37
+ Ok ( Self ( balances_after_fees) )
38
+ }
55
39
56
- * entry += & fee_rounded;
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
+ }
57
62
}
58
- }
59
63
60
- balances
64
+ balances
65
+ }
61
66
}
62
67
63
68
#[ derive( Debug ) ]
@@ -77,7 +82,7 @@ struct Distribution {
77
82
}
78
83
79
84
impl Distribution {
80
- pub fn new ( for_balances : & BalancesMap , on_channel : & Channel ) -> Result < Self , DomainError > {
85
+ pub fn new ( for_balances : & InnerBTreeMap , on_channel : & Channel ) -> Result < Self , DomainError > {
81
86
let deposit = on_channel. deposit_amount . clone ( ) ;
82
87
83
88
let total_distributed: BigNum = for_balances. iter ( ) . map ( |( _, balance) | balance) . sum ( ) ;
@@ -139,60 +144,63 @@ mod test {
139
144
140
145
mod applying_fee_returns_the_same_tree_with_zero_fees {
141
146
use super :: * ;
142
- fn setup_balances_map ( balances_map : & BalancesMap ) -> BalancesMap {
147
+ fn setup_balances_map ( tree : & InnerBTreeMap ) -> BalancesMap {
143
148
let channel = get_zero_fee_channel ( ) ;
144
149
145
- let balances_after_fee = get_balances_after_fees_tree ( balances_map, & channel)
150
+ let balances_map = BalancesMap ( tree. clone ( ) ) ;
151
+
152
+ let balances_after_fee = balances_map
153
+ . apply_fees ( & channel)
146
154
. expect ( "Calculation of fees failed" ) ;
147
155
148
156
balances_after_fee
149
157
}
150
158
151
159
#[ test]
152
160
fn case_1_three_values ( ) {
153
- let balances_map : BalancesMap = vec ! [
161
+ let tree : InnerBTreeMap = vec ! [
154
162
( "a" . to_string( ) , 1001 . into( ) ) ,
155
163
( "b" . to_string( ) , 3124 . into( ) ) ,
156
164
( "c" . to_string( ) , 122 . into( ) ) ,
157
165
]
158
166
. into_iter ( )
159
167
. collect ( ) ;
160
168
161
- assert_eq ! ( setup_balances_map( & balances_map ) , balances_map ) ;
169
+ assert_eq ! ( setup_balances_map( & tree ) . 0 , tree ) ;
162
170
}
163
171
164
172
#[ test]
165
173
fn case_2_three_simple_values ( ) {
166
- let balances_map : BalancesMap = vec ! [
174
+ let tree : InnerBTreeMap = vec ! [
167
175
( "a" . to_string( ) , 1 . into( ) ) ,
168
176
( "b" . to_string( ) , 2 . into( ) ) ,
169
177
( "c" . to_string( ) , 3 . into( ) ) ,
170
178
]
171
179
. into_iter ( )
172
180
. collect ( ) ;
173
181
174
- assert_eq ! ( setup_balances_map( & balances_map ) , balances_map ) ;
182
+ assert_eq ! ( setup_balances_map( & tree ) . 0 , tree ) ;
175
183
}
176
184
177
185
#[ test]
178
186
fn case_3_one_value ( ) {
179
- let balances_map = vec ! [ ( "a" . to_string( ) , BigNum :: from( 1 ) ) ]
187
+ let tree : InnerBTreeMap = vec ! [ ( "a" . to_string( ) , BigNum :: from( 1 ) ) ]
180
188
. into_iter ( )
181
189
. collect ( ) ;
182
190
183
- assert_eq ! ( setup_balances_map( & balances_map ) , balances_map ) ;
191
+ assert_eq ! ( setup_balances_map( & tree ) . 0 , tree ) ;
184
192
}
185
193
186
194
#[ test]
187
195
fn case_4_two_values ( ) {
188
- let balances_map = vec ! [
196
+ let tree : InnerBTreeMap = vec ! [
189
197
( "a" . to_string( ) , 1 . into( ) ) ,
190
198
( "b" . to_string( ) , 99_999 . into( ) ) ,
191
199
]
192
200
. into_iter ( )
193
201
. collect ( ) ;
194
202
195
- assert_eq ! ( setup_balances_map( & balances_map ) , balances_map ) ;
203
+ assert_eq ! ( setup_balances_map( & tree ) . 0 , tree ) ;
196
204
}
197
205
198
206
fn get_zero_fee_channel ( ) -> Channel {
@@ -210,30 +218,33 @@ mod test {
210
218
mod applying_fee_correctly {
211
219
use super :: * ;
212
220
213
- fn setup_balances_after_fee ( balances_map : BalancesMap ) -> BalancesMap {
221
+ fn setup_balances_after_fee ( tree : InnerBTreeMap ) -> BalancesMap {
214
222
let leader = get_validator ( "one" , Some ( 50 . into ( ) ) ) ;
215
223
let follower = get_validator ( "two" , Some ( 50 . into ( ) ) ) ;
216
224
217
225
let spec = get_channel_spec ( ValidatorsOption :: Pair { leader, follower } ) ;
218
226
let mut channel = get_channel ( "apply fees" , & None , Some ( spec) ) ;
219
227
channel. deposit_amount = 10_000 . into ( ) ;
220
228
221
- let balances_after_fee = get_balances_after_fees_tree ( & balances_map, & channel)
229
+ let balances_map = BalancesMap ( tree) ;
230
+
231
+ let balances_after_fee = balances_map
232
+ . apply_fees ( & channel)
222
233
. expect ( "Calculation of fees failed" ) ;
223
234
224
235
balances_after_fee
225
236
}
226
237
227
238
#[ test]
228
239
fn case_1_partially_distributed ( ) {
229
- let balances_map = vec ! [
240
+ let tree = vec ! [
230
241
( "a" . to_string( ) , 1_000 . into( ) ) ,
231
242
( "b" . to_string( ) , 1_200 . into( ) ) ,
232
243
]
233
244
. into_iter ( )
234
245
. collect ( ) ;
235
246
236
- let expected_balances : BalancesMap = vec ! [
247
+ let expected_tree : InnerBTreeMap = vec ! [
237
248
( "a" . to_string( ) , 990 . into( ) ) ,
238
249
( "b" . to_string( ) , 1_188 . into( ) ) ,
239
250
( "one" . to_string( ) , 11 . into( ) ) ,
@@ -242,30 +253,27 @@ mod test {
242
253
. into_iter ( )
243
254
. collect ( ) ;
244
255
245
- let balances_after_fee = setup_balances_after_fee ( balances_map ) ;
256
+ let balances_after_fee = setup_balances_after_fee ( tree ) . 0 ;
246
257
let actual_sum: BigNum = balances_after_fee. iter ( ) . map ( |( _, v) | v) . sum ( ) ;
247
258
248
259
assert_eq ! (
249
- expected_balances
250
- . iter( )
251
- . map( |( _, value) | value)
252
- . sum:: <BigNum >( ) ,
260
+ expected_tree. iter( ) . map( |( _, value) | value) . sum:: <BigNum >( ) ,
253
261
actual_sum
254
262
) ;
255
- assert_eq ! ( expected_balances , balances_after_fee) ;
263
+ assert_eq ! ( expected_tree , balances_after_fee) ;
256
264
}
257
265
258
266
#[ test]
259
- fn case_2_partially_distributed_with_validator_in_the_input_balances_map ( ) {
260
- let balances_map = vec ! [
267
+ fn case_2_partially_distributed_with_validator_in_the_input_tree ( ) {
268
+ let tree = vec ! [
261
269
( "a" . to_string( ) , 100 . into( ) ) ,
262
270
( "b" . to_string( ) , 2_000 . into( ) ) ,
263
271
( "one" . to_string( ) , 200 . into( ) ) ,
264
272
]
265
273
. into_iter ( )
266
274
. collect ( ) ;
267
275
268
- let expected_balances : BalancesMap = vec ! [
276
+ let expected_tree : InnerBTreeMap = vec ! [
269
277
( "a" . to_string( ) , 99 . into( ) ) ,
270
278
( "b" . to_string( ) , 1_980 . into( ) ) ,
271
279
( "one" . to_string( ) , 209 . into( ) ) ,
@@ -274,23 +282,20 @@ mod test {
274
282
. into_iter ( )
275
283
. collect ( ) ;
276
284
277
- let balances_after_fee = setup_balances_after_fee ( balances_map ) ;
285
+ let balances_after_fee = setup_balances_after_fee ( tree ) . 0 ;
278
286
let actual_sum: BigNum = balances_after_fee. iter ( ) . map ( |( _, v) | v) . sum ( ) ;
279
287
280
288
assert_eq ! (
281
- expected_balances
282
- . iter( )
283
- . map( |( _, value) | value)
284
- . sum:: <BigNum >( ) ,
289
+ expected_tree. iter( ) . map( |( _, value) | value) . sum:: <BigNum >( ) ,
285
290
actual_sum
286
291
) ;
287
- assert_eq ! ( expected_balances , balances_after_fee) ;
292
+ assert_eq ! ( expected_tree , balances_after_fee) ;
288
293
}
289
294
290
295
#[ test]
291
296
/// also testing the rounding error correction
292
297
fn case_3_fully_distributed ( ) {
293
- let balances_map = vec ! [
298
+ let tree = vec ! [
294
299
( "a" . to_string( ) , 105 . into( ) ) ,
295
300
( "b" . to_string( ) , 195 . into( ) ) ,
296
301
( "c" . to_string( ) , 700 . into( ) ) ,
@@ -300,7 +305,7 @@ mod test {
300
305
. into_iter ( )
301
306
. collect ( ) ;
302
307
303
- let expected_balances : BalancesMap = vec ! [
308
+ let expected_tree : InnerBTreeMap = vec ! [
304
309
( "a" . to_string( ) , 103 . into( ) ) ,
305
310
( "b" . to_string( ) , 193 . into( ) ) ,
306
311
( "c" . to_string( ) , 693 . into( ) ) ,
@@ -312,23 +317,20 @@ mod test {
312
317
. into_iter ( )
313
318
. collect ( ) ;
314
319
315
- let balances_after_fee = setup_balances_after_fee ( balances_map ) ;
320
+ let balances_after_fee = setup_balances_after_fee ( tree ) . 0 ;
316
321
let actual_sum: BigNum = balances_after_fee. iter ( ) . map ( |( _, v) | v) . sum ( ) ;
317
322
318
323
assert_eq ! (
319
- expected_balances
320
- . iter( )
321
- . map( |( _, value) | value)
322
- . sum:: <BigNum >( ) ,
324
+ expected_tree. iter( ) . map( |( _, value) | value) . sum:: <BigNum >( ) ,
323
325
actual_sum
324
326
) ;
325
- assert_eq ! ( expected_balances , balances_after_fee) ;
327
+ assert_eq ! ( expected_tree , balances_after_fee) ;
326
328
}
327
329
}
328
330
329
331
#[ test]
330
332
fn errors_when_fees_larger_that_deposit ( ) {
331
- let balances_map = vec ! [ ( "a" . to_string( ) , 10 . into( ) ) , ( "b" . to_string( ) , 10 . into( ) ) ]
333
+ let tree : InnerBTreeMap = vec ! [ ( "a" . to_string( ) , 10 . into( ) ) , ( "b" . to_string( ) , 10 . into( ) ) ]
332
334
. into_iter ( )
333
335
. collect ( ) ;
334
336
@@ -338,7 +340,10 @@ mod test {
338
340
let mut channel = get_channel ( "zero fees" , & None , Some ( spec) ) ;
339
341
channel. deposit_amount = 1_000 . into ( ) ;
340
342
341
- let domain_error = get_balances_after_fees_tree ( & balances_map, & channel)
343
+ let balances_map = BalancesMap ( tree. clone ( ) ) ;
344
+
345
+ let domain_error = balances_map
346
+ . apply_fees ( & channel)
342
347
. expect_err ( "Should be DomainError not allow fees sum to exceed the deposit" ) ;
343
348
344
349
assert_eq ! (
0 commit comments