-
Notifications
You must be signed in to change notification settings - Fork 326
/
client.rs
135 lines (120 loc) · 4.83 KB
/
client.rs
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
use core::convert::Infallible;
use core::time::Duration;
use crossbeam_channel::Receiver;
use tracing::{debug, span, trace, warn};
use ibc::events::IbcEvent;
use crate::util::task::{spawn_background_task, Next, TaskError, TaskHandle};
use crate::{
chain::handle::ChainHandle,
foreign_client::{ForeignClient, HasExpiredOrFrozenError, MisbehaviourResults},
telemetry,
};
use super::WorkerCmd;
pub fn spawn_refresh_client<ChainA: ChainHandle, ChainB: ChainHandle>(
mut client: ForeignClient<ChainA, ChainB>,
) -> Option<TaskHandle> {
if client.is_expired_or_frozen() {
warn!(
client = %client.id,
"skipping refresh client task on frozen client",
);
None
} else {
Some(spawn_background_task(
span!(
tracing::Level::ERROR,
"refresh",
client = %client.id,
src_chain = %client.src_chain.id(),
dst_chain = %client.dst_chain.id(),
),
Some(Duration::from_secs(1)),
move || {
let res = client.refresh().map_err(|e| {
if e.is_expired_or_frozen_error() {
TaskError::Fatal(e)
} else {
TaskError::Ignore(e)
}
})?;
if res.is_some() {
telemetry!(ibc_client_updates, &client.dst_chain.id(), &client.id, 1);
}
Ok(Next::Continue)
},
))
}
}
pub fn detect_misbehavior_task<ChainA: ChainHandle, ChainB: ChainHandle>(
receiver: Receiver<WorkerCmd>,
client: ForeignClient<ChainB, ChainA>,
) -> Option<TaskHandle> {
if client.is_expired_or_frozen() {
warn!(
client = %client.id(),
"skipping detect misbehavior task on frozen client",
);
return None;
}
let mut first_check_done = false;
let handle = spawn_background_task(
span!(
tracing::Level::ERROR,
"DetectMisbehaviorWorker",
client = %client.id,
src_chain = %client.src_chain.id(),
dst_chain = %client.dst_chain.id(),
),
Some(Duration::from_millis(600)),
move || -> Result<Next, TaskError<Infallible>> {
if !first_check_done {
first_check_done = true;
let _span = span!(
tracing::Level::DEBUG,
"DetectMisbehaviorFirstCheck",
client = %client.id,
src_chain = %client.src_chain.id(),
dst_chain = %client.dst_chain.id(),
)
.entered();
debug!("doing first check");
let misbehavior_result = client.detect_misbehaviour_and_submit_evidence(None);
trace!("detect misbehavior result: {:?}", misbehavior_result);
}
if let Ok(cmd) = receiver.try_recv() {
match cmd {
WorkerCmd::IbcEvents { batch } => {
trace!("received batch: {:?}", batch);
for event in batch.events {
if let IbcEvent::UpdateClient(update) = event {
debug!("checking misbehavior for updated client");
let misbehavior_result =
client.detect_misbehaviour_and_submit_evidence(Some(update));
trace!("detect misbehavior result: {:?}", misbehavior_result);
match misbehavior_result {
MisbehaviourResults::ValidClient => {}
MisbehaviourResults::VerificationError => {
// can retry in next call
}
MisbehaviourResults::EvidenceSubmitted(_) => {
// if evidence was submitted successfully then exit
return Ok(Next::Abort);
}
MisbehaviourResults::CannotExecute => {
// skip misbehaviour checking if chain does not have support for it (i.e. client
// update event does not include the header)
return Ok(Next::Abort);
}
}
}
}
}
WorkerCmd::NewBlock { .. } => {}
WorkerCmd::ClearPendingPackets => {}
}
}
Ok(Next::Continue)
},
);
Some(handle)
}