Skip to content

Commit b5732ce

Browse files
author
Ivo Georgiev
authored
Merge pull request #186 from AdExNetwork/fix-game-theoretical-failure
Fix game theoretical failure
2 parents 660666e + 3c0ba80 commit b5732ce

File tree

5 files changed

+108
-106
lines changed

5 files changed

+108
-106
lines changed

docs/config/dev.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ msgs_find_limit = 10
88

99
heartbeat_time = 30000
1010
health_threshold_promilles = 950
11+
health_unsignable_promilles = 750
1112
propagation_timeout = 1000
1213

1314
list_timeout = 5000
@@ -24,4 +25,4 @@ creators_whitelist = []
2425
minimal_deposit = "0"
2526
minimal_fee = "0"
2627
token_address_whitelist = []
27-
validators_whitelist = []
28+
validators_whitelist = []

docs/config/prod.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ msgs_find_limit = 10
1010

1111
heartbeat_time = 60000
1212
health_threshold_promilles = 970
13+
health_unsignable_promilles = 770
1314
propagation_timeout = 3000
1415

1516
list_timeout = 10000

primitives/src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct Config {
2525
pub channels_find_limit: u32,
2626
pub events_find_limit: u32,
2727
pub health_threshold_promilles: u32,
28+
pub health_unsignable_promilles: u32,
2829
pub propagation_timeout: u32,
2930
pub fetch_timeout: u32,
3031
pub list_timeout: u32,

validator_worker/src/core/follower_rules.rs

Lines changed: 93 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,7 @@ pub fn is_valid_transition(channel: &Channel, prev: &BalancesMap, next: &Balance
1515
sum_next >= sum_prev && sum_next <= deposit && prev_checks
1616
}
1717

18-
pub fn is_healthy(
19-
channel: &Channel,
20-
our: &BalancesMap,
21-
approved: &BalancesMap,
22-
health_threshold: &BigNum,
23-
) -> bool {
18+
pub fn get_health(channel: &Channel, our: &BalancesMap, approved: &BalancesMap) -> u64 {
2419
let sum_our: BigNum = our.values().sum();
2520

2621
let zero = BigNum::from(0);
@@ -30,26 +25,21 @@ pub fn is_healthy(
3025
.sum();
3126

3227
if sum_approved_mins >= sum_our {
33-
return true;
28+
return 1_000;
3429
}
3530

36-
let deposit = &channel.deposit_amount;
37-
let health_threshold_neg = &BigNum::from(1_000) - health_threshold;
38-
let acceptable_difference = deposit * &health_threshold_neg / &BigNum::from(1_000);
39-
40-
sum_our - sum_approved_mins < acceptable_difference
31+
let diff = sum_our - sum_approved_mins;
32+
let health_penalty = diff * &BigNum::from(1_000) / &channel.deposit_amount;
33+
1_000 - health_penalty.to_u64().unwrap_or(1_000)
4134
}
4235

4336
#[cfg(test)]
4437
mod test {
45-
use lazy_static::lazy_static;
4638
use primitives::util::tests::prep_db::DUMMY_CHANNEL;
4739

4840
use super::*;
4941

50-
lazy_static! {
51-
static ref HEALTH_THRESHOLD: BigNum = BigNum::from(950);
52-
}
42+
const HEALTH_THRESHOLD: u64 = 950;
5343

5444
fn get_dummy_channel<T: Into<BigNum>>(deposit: T) -> Channel {
5545
Channel {
@@ -161,107 +151,114 @@ mod test {
161151
}
162152

163153
#[test]
164-
fn is_healthy_the_approved_balance_tree_gte_our_accounting_is_healthy() {
154+
fn get_health_the_approved_balance_tree_gte_our_accounting_is_healthy() {
165155
let channel = get_dummy_channel(50);
166156
let our = vec![("a".into(), 50.into())].into_iter().collect();
167-
assert!(is_healthy(&channel, &our, &our, &HEALTH_THRESHOLD));
168-
169-
assert!(is_healthy(
170-
&channel,
171-
&our,
172-
&vec![("a".into(), 60.into())].into_iter().collect(),
173-
&HEALTH_THRESHOLD
174-
));
157+
assert!(get_health(&channel, &our, &our) >= HEALTH_THRESHOLD);
158+
159+
assert!(
160+
get_health(
161+
&channel,
162+
&our,
163+
&vec![("a".into(), 60.into())].into_iter().collect()
164+
) >= HEALTH_THRESHOLD
165+
);
175166
}
176167

177168
#[test]
178-
fn is_healthy_the_approved_balance_tree_is_positive_our_accounting_is_0_and_it_is_healthy() {
169+
fn get_health_the_approved_balance_tree_is_positive_our_accounting_is_0_and_it_is_healthy() {
179170
let approved = vec![("a".into(), 50.into())].into_iter().collect();
180171

181-
assert!(is_healthy(
182-
&get_dummy_channel(50),
183-
&BalancesMap::default(),
184-
&approved,
185-
&HEALTH_THRESHOLD
186-
));
172+
assert!(
173+
get_health(&get_dummy_channel(50), &BalancesMap::default(), &approved)
174+
>= HEALTH_THRESHOLD
175+
);
187176
}
188177

189178
#[test]
190-
fn is_healthy_the_approved_balance_tree_has_less_but_within_margin_it_is_healthy() {
179+
fn get_health_the_approved_balance_tree_has_less_but_within_margin_it_is_healthy() {
191180
let channel = get_dummy_channel(80);
192181

193-
assert!(is_healthy(
194-
&channel,
195-
&vec![("a".into(), 80.into())].into_iter().collect(),
196-
&vec![("a".into(), 79.into())].into_iter().collect(),
197-
&HEALTH_THRESHOLD
198-
));
199-
200-
assert!(is_healthy(
201-
&channel,
202-
&vec![("a".into(), 2.into())].into_iter().collect(),
203-
&vec![("a".into(), 1.into())].into_iter().collect(),
204-
&HEALTH_THRESHOLD
205-
));
182+
assert!(
183+
get_health(
184+
&channel,
185+
&vec![("a".into(), 80.into())].into_iter().collect(),
186+
&vec![("a".into(), 79.into())].into_iter().collect()
187+
) >= HEALTH_THRESHOLD
188+
);
189+
190+
assert!(
191+
get_health(
192+
&channel,
193+
&vec![("a".into(), 2.into())].into_iter().collect(),
194+
&vec![("a".into(), 1.into())].into_iter().collect()
195+
) >= HEALTH_THRESHOLD
196+
);
206197
}
207198

208199
#[test]
209-
fn is_healthy_the_approved_balance_tree_has_less_it_is_unhealthy() {
200+
fn get_health_the_approved_balance_tree_has_less_it_is_unhealthy() {
210201
let channel = get_dummy_channel(80);
211202

212-
assert!(!is_healthy(
213-
&channel,
214-
&vec![("a".into(), 80.into())].into_iter().collect(),
215-
&vec![("a".into(), 70.into())].into_iter().collect(),
216-
&HEALTH_THRESHOLD
217-
));
203+
assert!(
204+
get_health(
205+
&channel,
206+
&vec![("a".into(), 80.into())].into_iter().collect(),
207+
&vec![("a".into(), 70.into())].into_iter().collect()
208+
) < HEALTH_THRESHOLD
209+
);
218210
}
219211

220212
#[test]
221-
fn is_healthy_they_have_the_same_sum_but_different_entities_are_earning() {
213+
fn get_health_they_have_the_same_sum_but_different_entities_are_earning() {
222214
let channel = get_dummy_channel(80);
223215

224-
assert!(!is_healthy(
225-
&channel,
226-
&vec![("a".into(), 80.into())].into_iter().collect(),
227-
&vec![("b".into(), 80.into())].into_iter().collect(),
228-
&HEALTH_THRESHOLD
229-
));
230-
231-
assert!(!is_healthy(
232-
&channel,
233-
&vec![("a".into(), 80.into())].into_iter().collect(),
234-
&vec![("b".into(), 40.into()), ("a".into(), 40.into())]
235-
.into_iter()
236-
.collect(),
237-
&HEALTH_THRESHOLD
238-
));
239-
240-
assert!(!is_healthy(
241-
&channel,
242-
&vec![("a".into(), 80.into())].into_iter().collect(),
243-
&vec![("b".into(), 20.into()), ("a".into(), 60.into())]
244-
.into_iter()
245-
.collect(),
246-
&HEALTH_THRESHOLD
247-
));
248-
249-
assert!(is_healthy(
250-
&channel,
251-
&vec![("a".into(), 80.into())].into_iter().collect(),
252-
&vec![("b".into(), 2.into()), ("a".into(), 78.into())]
253-
.into_iter()
254-
.collect(),
255-
&HEALTH_THRESHOLD
256-
));
257-
258-
assert!(is_healthy(
259-
&channel,
260-
&vec![("a".into(), 100.into()), ("b".into(), 1.into())]
261-
.into_iter()
262-
.collect(),
263-
&vec![("a".into(), 100.into())].into_iter().collect(),
264-
&HEALTH_THRESHOLD
265-
));
216+
assert!(
217+
get_health(
218+
&channel,
219+
&vec![("a".into(), 80.into())].into_iter().collect(),
220+
&vec![("b".into(), 80.into())].into_iter().collect()
221+
) < HEALTH_THRESHOLD
222+
);
223+
224+
assert!(
225+
get_health(
226+
&channel,
227+
&vec![("a".into(), 80.into())].into_iter().collect(),
228+
&vec![("b".into(), 40.into()), ("a".into(), 40.into())]
229+
.into_iter()
230+
.collect()
231+
) < HEALTH_THRESHOLD
232+
);
233+
234+
assert!(
235+
get_health(
236+
&channel,
237+
&vec![("a".into(), 80.into())].into_iter().collect(),
238+
&vec![("b".into(), 20.into()), ("a".into(), 60.into())]
239+
.into_iter()
240+
.collect()
241+
) < HEALTH_THRESHOLD
242+
);
243+
244+
assert!(
245+
get_health(
246+
&channel,
247+
&vec![("a".into(), 80.into())].into_iter().collect(),
248+
&vec![("b".into(), 2.into()), ("a".into(), 78.into())]
249+
.into_iter()
250+
.collect()
251+
) >= HEALTH_THRESHOLD
252+
);
253+
254+
assert!(
255+
get_health(
256+
&channel,
257+
&vec![("a".into(), 100.into()), ("b".into(), 1.into())]
258+
.into_iter()
259+
.collect(),
260+
&vec![("a".into(), 100.into())].into_iter().collect()
261+
) >= HEALTH_THRESHOLD
262+
);
266263
}
267264
}

validator_worker/src/follower.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use primitives::adapter::Adapter;
44
use primitives::validator::{ApproveState, MessageTypes, NewState, RejectState};
55
use primitives::BalancesMap;
66

7-
use crate::core::follower_rules::{is_healthy, is_valid_transition};
7+
use crate::core::follower_rules::{get_health, is_valid_transition};
88
use crate::heartbeat::heartbeat;
99
use crate::sentry_interface::SentryApi;
1010
use crate::{get_state_root_hash, producer};
@@ -14,6 +14,7 @@ enum InvalidNewState {
1414
RootHash,
1515
Signature,
1616
Transition,
17+
Health,
1718
}
1819

1920
enum NewStateResult {
@@ -82,20 +83,20 @@ async fn on_new_state<'a, A: Adapter + 'static>(
8283
return Ok(on_error(&iface, &new_state, InvalidNewState::Transition).await);
8384
}
8485

86+
let health = get_health(&iface.channel, balances, &proposed_balances);
87+
if health < u64::from(iface.config.health_unsignable_promilles) {
88+
return Ok(on_error(&iface, &new_state, InvalidNewState::Health).await);
89+
}
90+
8591
let signature = iface.adapter.sign(&new_state.state_root)?;
86-
let health_threshold = u64::from(iface.config.health_threshold_promilles).into();
87-
let health = is_healthy(
88-
&iface.channel,
89-
balances,
90-
&proposed_balances,
91-
&health_threshold,
92-
);
92+
let health_threshold = u64::from(iface.config.health_threshold_promilles);
93+
let is_healthy = health >= health_threshold;
9394

9495
iface
9596
.propagate(&[&MessageTypes::ApproveState(ApproveState {
9697
state_root: proposed_state_root,
9798
signature,
98-
is_healthy: health,
99+
is_healthy,
99100
})])
100101
.await;
101102

@@ -112,6 +113,7 @@ async fn on_error<'a, A: Adapter + 'static>(
112113
RootHash => "InvalidRootHash",
113114
Signature => "InvalidSignature",
114115
Transition => "InvalidTransition",
116+
Health => "TooLowHealth",
115117
}
116118
.to_string();
117119

0 commit comments

Comments
 (0)