Skip to content

Commit cf785d4

Browse files
committed
fix: remove RefCell adapter, implement RwLock sentry_interface
1 parent e4739e4 commit cf785d4

File tree

9 files changed

+125
-88
lines changed

9 files changed

+125
-88
lines changed

adapter/src/dummy.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl Adapter for DummyAdapter {
4242
})
4343
}
4444

45-
fn unlock(&self) -> AdapterResult<()> {
45+
fn unlock(&mut self) -> AdapterResult<()> {
4646
Ok(())
4747
}
4848

@@ -77,7 +77,7 @@ impl Adapter for DummyAdapter {
7777
}
7878
}
7979

80-
fn session_from_token(&self, token: &str) -> AdapterResult<Session> {
80+
fn session_from_token(&mut self, token: &str) -> AdapterResult<Session> {
8181
let identity = self
8282
.authorization_tokens
8383
.iter()
@@ -95,7 +95,7 @@ impl Adapter for DummyAdapter {
9595
}
9696
}
9797

98-
fn get_auth(&self, _validator: &ValidatorDesc) -> AdapterResult<String> {
98+
fn get_auth(&mut self, _validator: &str) -> AdapterResult<String> {
9999
let who = self
100100
.session_tokens
101101
.iter()

adapter/src/ethereum.rs

+34-38
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use primitives::{
1111
};
1212
use serde::{Deserialize, Serialize};
1313
use serde_json::Value;
14-
use std::cell::RefCell;
1514
use std::collections::HashMap;
1615
use std::error::Error;
1716
use std::fs;
@@ -39,10 +38,10 @@ pub struct EthereumAdapter {
3938
keystore_pwd: Password,
4039
config: Config,
4140
// Auth tokens that we have verified (tokenId => session)
42-
session_tokens: RefCell<HashMap<String, Session>>,
41+
session_tokens: HashMap<String, Session>,
4342
// Auth tokens that we've generated to authenticate with someone (address => token)
44-
authorization_tokens: RefCell<HashMap<String, String>>,
45-
wallet: RefCell<Option<SafeAccount>>,
43+
authorization_tokens: HashMap<String, String>,
44+
wallet: Option<SafeAccount>,
4645
}
4746

4847
// Enables EthereumAdapter to be able to
@@ -81,14 +80,14 @@ impl Adapter for EthereumAdapter {
8180
address,
8281
keystore_json,
8382
keystore_pwd: keystore_pwd.into(),
84-
session_tokens: RefCell::new(HashMap::new()),
85-
authorization_tokens: RefCell::new(HashMap::new()),
86-
wallet: RefCell::new(None),
83+
session_tokens: HashMap::new(),
84+
authorization_tokens: HashMap::new(),
85+
wallet: None,
8786
config: config.to_owned(),
8887
})
8988
}
9089

91-
fn unlock(&self) -> AdapterResult<()> {
90+
fn unlock(&mut self) -> AdapterResult<()> {
9291
let account = SafeAccount::from_file(
9392
serde_json::from_value(self.keystore_json.clone())
9493
.map_err(|_| map_error("Invalid keystore json provided"))?,
@@ -97,7 +96,7 @@ impl Adapter for EthereumAdapter {
9796
)
9897
.map_err(|_| map_error("Failed to create account"))?;
9998

100-
self.wallet.replace(Some(account));
99+
self.wallet = Some(account);
101100

102101
Ok(())
103102
}
@@ -107,18 +106,18 @@ impl Adapter for EthereumAdapter {
107106
}
108107

109108
fn sign(&self, state_root: &str) -> AdapterResult<String> {
110-
let message = Message::from_slice(&hash_message(state_root));
111-
match self.wallet.borrow().clone() {
112-
Some(wallet) => {
113-
let wallet_sign = wallet
114-
.sign(&self.keystore_pwd, &message)
115-
.map_err(|_| map_error("failed to sign messages"))?;
116-
let signature: Signature = wallet_sign.into_electrum().into();
117-
Ok(format!("0x{}", signature))
118-
}
119-
None => Err(AdapterError::Configuration(
109+
if let Some(wallet) = &self.wallet {
110+
let message = Message::from_slice(&hash_message(state_root));
111+
let wallet_sign = wallet
112+
.sign(&self.keystore_pwd, &message)
113+
.map_err(|_| map_error("failed to sign messages"))?;
114+
let signature: Signature = wallet_sign.into_electrum().into();
115+
116+
Ok(format!("0x{}", signature))
117+
} else {
118+
Err(AdapterError::Configuration(
120119
"Unlock the wallet before signing".to_string(),
121-
)),
120+
))
122121
}
123122
}
124123

@@ -136,7 +135,7 @@ impl Adapter for EthereumAdapter {
136135
let signature = Signature::from_electrum(&decoded_signature);
137136
let message = Message::from_slice(&hash_message(state_root));
138137

139-
verify_address(&address, &signature, &message).or(Ok(false))
138+
verify_address(&address, &signature, &message).or_else(|_| Ok(false))
140139
}
141140

142141
fn validate_channel(&self, channel: &Channel) -> AdapterResult<bool> {
@@ -179,15 +178,14 @@ impl Adapter for EthereumAdapter {
179178
Ok(true)
180179
}
181180

182-
fn session_from_token(&self, token: &str) -> AdapterResult<Session> {
181+
fn session_from_token(&mut self, token: &str) -> AdapterResult<Session> {
183182
if token.len() < 16 {
184183
return Err(AdapterError::Failed("invaild token id".to_string()));
185184
}
186185

187186
let token_id = token[token.len() - 16..].to_string();
188187

189-
let mut session_tokens = self.session_tokens.borrow_mut();
190-
if let Some(token) = session_tokens.get(&token_id) {
188+
if let Some(token) = self.session_tokens.get(&token_id) {
191189
return Ok(token.to_owned());
192190
}
193191

@@ -241,29 +239,27 @@ impl Adapter for EthereumAdapter {
241239
},
242240
};
243241

244-
session_tokens.insert(token_id, sess.clone());
242+
self.session_tokens.insert(token_id, sess.clone());
245243
Ok(sess)
246244
}
247245

248-
fn get_auth(&self, validator: &ValidatorDesc) -> AdapterResult<String> {
249-
let mut authorization_tokens = self.authorization_tokens.borrow_mut();
250-
match (
251-
self.wallet.borrow().clone(),
252-
authorization_tokens.get(&validator.id),
253-
) {
246+
fn get_auth(&mut self, validator_id: &str) -> AdapterResult<String> {
247+
let validator = validator_id.to_owned();
248+
match (&self.wallet, self.authorization_tokens.get(&validator)) {
254249
(Some(_), Some(token)) => Ok(token.to_owned()),
255250
(Some(wallet), None) => {
256251
let era = Utc::now().timestamp() as f64 / 60000.0;
257252
let payload = Payload {
258-
id: validator.id.clone(),
253+
id: validator.clone(),
259254
era: era.floor() as i64,
260255
identity: None,
261256
address: None,
262257
};
263-
let token = ewt_sign(&wallet, &self.keystore_pwd, &payload)
258+
let token = ewt_sign(wallet, &self.keystore_pwd, &payload)
264259
.map_err(|_| map_error("Failed to sign token"))?;
265260

266-
authorization_tokens.insert(validator.id.clone(), token.clone());
261+
self.authorization_tokens
262+
.insert(validator.clone(), token.clone());
267263

268264
Ok(token)
269265
}
@@ -420,7 +416,7 @@ mod test {
420416

421417
#[test]
422418
fn should_init_and_unlock_ethereum_adapter() {
423-
let eth_adapter = setup_eth_adapter();
419+
let mut eth_adapter = setup_eth_adapter();
424420
let unlock = eth_adapter.unlock().expect("should unlock eth adapter");
425421

426422
assert_eq!((), unlock, "failed to unlock eth adapter");
@@ -429,7 +425,7 @@ mod test {
429425
#[test]
430426
fn should_get_whoami_sign_and_verify_messages() {
431427
// whoami
432-
let eth_adapter = setup_eth_adapter();
428+
let mut eth_adapter = setup_eth_adapter();
433429
let whoami = eth_adapter.whoami();
434430
assert_eq!(
435431
whoami, "0x2bDeAFAE53940669DaA6F519373f686c1f3d3393",
@@ -460,7 +456,7 @@ mod test {
460456

461457
#[test]
462458
fn should_generate_correct_ewt_sign_and_verify() {
463-
let eth_adapter = setup_eth_adapter();
459+
let mut eth_adapter = setup_eth_adapter();
464460
eth_adapter.unlock().expect("should unlock eth adapter");
465461

466462
let payload = Payload {
@@ -469,7 +465,7 @@ mod test {
469465
address: Some(eth_adapter.whoami()),
470466
identity: None,
471467
};
472-
let wallet = eth_adapter.wallet.borrow().clone();
468+
let wallet = eth_adapter.wallet.clone();
473469
let response = ewt_sign(&wallet.unwrap(), &eth_adapter.keystore_pwd, &payload)
474470
.expect("failed to generate ewt signature");
475471
let expected =

primitives/src/adapter.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::channel_validator::ChannelValidator;
2-
use crate::validator::ValidatorDesc;
32
use crate::{Channel, Config};
43
use std::collections::HashMap;
54
use std::error::Error;
@@ -56,7 +55,7 @@ pub trait Adapter: ChannelValidator + Clone + Debug {
5655
fn init(opts: AdapterOptions, config: &Config) -> AdapterResult<Self::Output>;
5756

5857
/// Unlock adapter
59-
fn unlock(&self) -> AdapterResult<()>;
58+
fn unlock(&mut self) -> AdapterResult<()>;
6059

6160
/// Get Adapter whoami
6261
fn whoami(&self) -> String;
@@ -71,8 +70,8 @@ pub trait Adapter: ChannelValidator + Clone + Debug {
7170
fn validate_channel(&self, channel: &Channel) -> AdapterResult<bool>;
7271

7372
/// Get user session from token
74-
fn session_from_token(&self, token: &str) -> AdapterResult<Session>;
73+
fn session_from_token(&mut self, token: &str) -> AdapterResult<Session>;
7574

7675
/// Gets authentication for specific validator
77-
fn get_auth(&self, validator: &ValidatorDesc) -> AdapterResult<String>;
76+
fn get_auth(&mut self, validator_id: &str) -> AdapterResult<String>;
7877
}

validator_worker/src/error.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1-
#![deny(clippy::all)]
2-
31
use serde::{Deserialize, Serialize};
2+
use std::error::Error;
3+
use std::fmt::{Display, Formatter, Result};
4+
5+
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
6+
pub enum ValidatorWorker {
7+
Configuration(String),
8+
Failed(String),
9+
}
10+
11+
impl Error for ValidatorWorker {}
412

5-
#[derive(Serialize, Deserialize, Debug, Clone)]
6-
pub enum ValidatorWorkerError {
7-
ConfigurationError(String),
8-
InvalidValidatorEntry(String),
13+
impl Display for ValidatorWorker {
14+
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
15+
match self {
16+
ValidatorWorker::Configuration(error) => write!(f, "Configuration error: {}", error),
17+
ValidatorWorker::Failed(error) => write!(f, "error: {}", error),
18+
}
19+
}
920
}

validator_worker/src/follower.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ async fn on_new_state<'a, A: Adapter + 'static>(
7272
)));
7373
}
7474

75-
if !iface.adapter.verify(
75+
let adapter = iface
76+
.adapter
77+
.read()
78+
.expect("on_new_state: failed to acquire read lock adapter");
79+
80+
if !adapter.verify(
7681
&iface.channel.spec.validators.leader().id,
7782
&proposed_state_root,
7883
&new_state.signature,
@@ -98,7 +103,7 @@ async fn on_new_state<'a, A: Adapter + 'static>(
98103
)));
99104
}
100105

101-
let signature = iface.adapter.sign(&new_state.state_root)?;
106+
let signature = adapter.sign(&new_state.state_root)?;
102107
let health_threshold = u64::from(iface.config.health_threshold_promilles).into();
103108

104109
iface.propagate(&[&MessageTypes::ApproveState(ApproveState {

validator_worker/src/heartbeat.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ async fn send_heartbeat<A: Adapter + 'static>(iface: &SentryApi<A>) -> Result<()
2323

2424
let state_root_raw = get_signable_state_root(&iface.channel.id, &info_root_raw)?;
2525
let state_root = hex::encode(state_root_raw);
26-
let signature = iface.adapter.sign(&state_root)?;
26+
let signature = iface
27+
.adapter
28+
.read()
29+
.expect("send_heartbeat: failed to acquire adapter read lock")
30+
.sign(&state_root)?;
2731

2832
let message_types = MessageTypes::Heartbeat(Heartbeat {
2933
signature,

validator_worker/src/leader.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ fn on_new_accounting<A: Adapter + 'static>(
2525
let state_root_raw = get_state_root_hash(&iface, &balances)?;
2626
let state_root = hex::encode(state_root_raw);
2727

28-
let signature = iface.adapter.sign(&state_root)?;
28+
let signature = iface
29+
.adapter
30+
.read()
31+
.expect("on_new_accounting: failed to acquire read lock")
32+
.sign(&state_root)?;
2933

3034
iface.propagate(&[&MessageTypes::NewState(NewState {
3135
state_root,

validator_worker/src/lib.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55

66
use std::error::Error;
77

8+
use crate::sentry_interface::SentryApi;
89
use adapter::{get_balance_leaf, get_signable_state_root};
910
use primitives::adapter::Adapter;
1011
use primitives::merkle_tree::MerkleTree;
1112
use primitives::BalancesMap;
1213

13-
use crate::sentry_interface::SentryApi;
14-
1514
pub use self::sentry_interface::all_channels;
1615

1716
pub mod error;
@@ -54,6 +53,7 @@ mod test {
5453
use primitives::config::configuration;
5554
use primitives::util::tests::prep_db::{AUTH, DUMMY_CHANNEL, IDS};
5655
use primitives::{BalancesMap, Channel};
56+
use std::sync::{Arc, RwLock};
5757

5858
fn setup_iface(channel: &Channel) -> SentryApi<DummyAdapter> {
5959
let adapter_options = AdapterOptions {
@@ -66,7 +66,13 @@ mod test {
6666
let config = configuration("development", None).expect("Dev config should be available");
6767
let dummy_adapter = DummyAdapter::init(adapter_options, &config).expect("init adadpter");
6868

69-
SentryApi::new(dummy_adapter, &channel, &config, false).expect("should succeed")
69+
SentryApi::new(
70+
Arc::new(RwLock::new(dummy_adapter)),
71+
&channel,
72+
&config,
73+
false,
74+
)
75+
.expect("should succeed")
7076
}
7177

7278
#[test]

0 commit comments

Comments
 (0)