Skip to content

Commit 4314a96

Browse files
committed
adapter - dummy:
- Possible to setup multiple chains - use GANACHE_CONFIG to ease the setup process of the adapter - Create a HeaderToken which contains the ChainId - docs - config - remove dummy.toml config - fix tests
1 parent 032b0db commit 4314a96

File tree

13 files changed

+181
-212
lines changed

13 files changed

+181
-212
lines changed

adapter/src/dummy.rs

Lines changed: 106 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::{
77
};
88
use async_trait::async_trait;
99

10+
use parse_display::{Display, FromStr};
1011
use primitives::{
1112
config::ChainInfo, Address, ChainId, ChainOf, Channel, ToETHChecksum, ValidatorId,
1213
};
@@ -17,26 +18,6 @@ pub use self::deposit::Deposits;
1718

1819
pub type Adapter<S> = crate::Adapter<Dummy, S>;
1920

20-
#[cfg(feature = "test-util")]
21-
#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
22-
pub mod test_util {
23-
use once_cell::sync::Lazy;
24-
use primitives::{
25-
config::{ChainInfo, TokenInfo, DUMMY_CONFIG},
26-
Chain,
27-
};
28-
pub static DUMMY_TOKEN: Lazy<TokenInfo> =
29-
Lazy::new(|| DUMMY_CONFIG.chains["Dummy"].tokens["DUMMY"].clone());
30-
31-
pub static DUMMY_CHAIN_INFO: Lazy<ChainInfo> =
32-
Lazy::new(|| DUMMY_CONFIG.chains["Dummy"].clone());
33-
34-
/// The Dummy Chain to be used with this adapter
35-
/// The Chain is not applicable to the adapter, however, it is required for
36-
/// applications because of the `authentication` & [`Channel`] interactions.
37-
pub static DUMMY_CHAIN: Lazy<Chain> = Lazy::new(|| DUMMY_CHAIN_INFO.chain.clone());
38-
}
39-
4021
#[derive(Debug, Clone)]
4122
pub struct Options {
4223
/// The identity used for the Adapter.
@@ -46,7 +27,7 @@ pub struct Options {
4627
pub dummy_auth_tokens: HashMap<Address, String>,
4728
/// The [`ChainInfo`] that will be used for the [`Session`]s and
4829
/// also for the deposits.
49-
pub dummy_chain: ChainInfo,
30+
pub dummy_chains: Vec<ChainInfo>,
5031
}
5132

5233
/// Dummy adapter implementation intended for testing.
@@ -56,7 +37,7 @@ pub struct Dummy {
5637
identity: ValidatorId,
5738
/// Static authentication tokens (address => token)
5839
authorization_tokens: HashMap<Address, String>,
59-
chain_info: ChainInfo,
40+
chains: Vec<ChainInfo>,
6041
deposits: Deposits,
6142
}
6243

@@ -65,7 +46,7 @@ impl Dummy {
6546
Self {
6647
identity: opts.dummy_identity,
6748
authorization_tokens: opts.dummy_auth_tokens,
68-
chain_info: opts.dummy_chain,
49+
chains: opts.dummy_chains,
6950
deposits: Default::default(),
7051
}
7152
}
@@ -130,24 +111,45 @@ impl Locked for Dummy {
130111
}
131112

132113
/// Finds the authorization token from the configured values
133-
/// and creates a [`Session`] out of it using a [`ChainId`] of `1`.
134-
async fn session_from_token(&self, token: &str) -> Result<Session, crate::Error> {
135-
let identity = self
114+
/// and creates a [`Session`] out of it by using the ChainId included in the header:
115+
///
116+
/// `{Auth token}:chain_id:{ChainId}`
117+
///
118+
/// # Examples
119+
///
120+
/// `AUTH_awesomeLeader:chain_id:1`
121+
/// `AUTH_awesomeAdvertiser:chain_id:1337`
122+
async fn session_from_token(&self, header_token: &str) -> Result<Session, crate::Error> {
123+
let header_token = header_token.parse::<HeaderToken>().map_err(|_parse| {
124+
Error::authentication(format!("Dummy Authentication token format should be in the format: `{{Auth Token}}:chain_id:{{Chain Id}}` but '{header_token}' was provided"))
125+
})?;
126+
127+
// find the chain
128+
let chain_info = self
129+
.chains
130+
.iter()
131+
.find(|chain_info| chain_info.chain.chain_id == header_token.chain_id)
132+
.ok_or_else(|| {
133+
Error::authentication(format!("Unknown chain id {:?}", header_token.chain_id))
134+
})?;
135+
136+
// find the authentication token
137+
let (identity, _) = self
136138
.authorization_tokens
137139
.iter()
138-
.find(|(_, address_token)| *address_token == token);
139-
140-
match identity {
141-
Some((address, _token)) => Ok(Session {
142-
uid: *address,
143-
era: 0,
144-
chain: self.chain_info.chain.clone(),
145-
}),
146-
None => Err(Error::authentication(format!(
147-
"No identity found that matches authentication token: {}",
148-
token
149-
))),
150-
}
140+
.find(|(_, address_token)| *address_token == &header_token.token)
141+
.ok_or_else(|| {
142+
Error::authentication(format!(
143+
"No identity found that matches authentication token: {}",
144+
&header_token.token
145+
))
146+
})?;
147+
148+
Ok(Session {
149+
uid: *identity,
150+
era: 0,
151+
chain: chain_info.chain.clone(),
152+
})
151153
}
152154

153155
async fn get_deposit(
@@ -163,15 +165,26 @@ impl Locked for Dummy {
163165
));
164166
}
165167

166-
if self.chain_info.chain != channel_context.chain
167-
|| self
168-
.chain_info
169-
.find_token(channel_context.context.token)
170-
.is_none()
168+
// Check if the combination of Chain & Token are set in the dummy adapter configuration
171169
{
172-
return Err(Error::adapter(
173-
"Channel's Token & Chain not aligned with Dummy adapter's chain".to_string(),
174-
));
170+
let found_chain = self
171+
.chains
172+
.iter()
173+
.find(|chain_info| chain_info.chain == channel_context.chain)
174+
.ok_or_else(|| {
175+
Error::adapter(
176+
"Channel Chain not found in Dummy adapter's configuration".to_string(),
177+
)
178+
})?;
179+
180+
let _found_token = found_chain
181+
.find_token(channel_context.context.token)
182+
.ok_or_else(|| {
183+
Error::adapter(format!(
184+
"Channel Token not found in configured adapter chain: {:?}",
185+
found_chain.chain.chain_id
186+
))
187+
})?;
175188
}
176189

177190
self.deposits
@@ -199,16 +212,25 @@ impl Unlocked for Dummy {
199212
}
200213

201214
// requires Unlocked
202-
fn get_auth(&self, _for_chain: ChainId, _intended_for: ValidatorId) -> Result<String, Error> {
203-
self.authorization_tokens
215+
// Builds the authentication token as:
216+
// `{Auth token}:chain_id:{Chain Id}`
217+
fn get_auth(&self, for_chain: ChainId, _intended_for: ValidatorId) -> Result<String, Error> {
218+
let token = self
219+
.authorization_tokens
204220
.get(&self.identity.to_address())
205221
.cloned()
206222
.ok_or_else(|| {
207223
Error::authentication(format!(
208224
"No auth token for this identity: {}",
209225
self.identity
210226
))
211-
})
227+
})?;
228+
229+
Ok(HeaderToken {
230+
token,
231+
chain_id: for_chain,
232+
}
233+
.to_string())
212234
}
213235
}
214236

@@ -220,6 +242,19 @@ impl Unlockable for Dummy {
220242
}
221243
}
222244

245+
/// The dummy Header token used for the `Bearer` `Authorization` header
246+
///
247+
/// The format for the header token is:
248+
/// `{Auth token}:chain_id:{Chain Id}`
249+
#[derive(Debug, Clone, Display, FromStr)]
250+
#[display("{token}:chain_id:{chain_id}")]
251+
pub struct HeaderToken {
252+
/// the Authentication Token
253+
pub token: String,
254+
/// The [`ChainId`] for which we authenticate
255+
pub chain_id: ChainId,
256+
}
257+
223258
mod deposit {
224259
use crate::primitives::Deposit;
225260
use dashmap::DashMap;
@@ -274,32 +309,30 @@ mod deposit {
274309
#[cfg(test)]
275310
mod test {
276311
use primitives::{
312+
config::GANACHE_CONFIG,
277313
test_util::{CREATOR, DUMMY_CAMPAIGN, IDS, LEADER, PUBLISHER},
278314
BigNum, ChainOf,
279315
};
280316

281-
use super::{
282-
test_util::{DUMMY_CHAIN, DUMMY_CHAIN_INFO, DUMMY_TOKEN},
283-
*,
284-
};
317+
use crate::ethereum::test_util::{GANACHE_1337, GANACHE_INFO_1337};
318+
319+
use super::*;
285320

286321
#[tokio::test]
287322
async fn test_deposits_calls() {
288-
let channel = Channel {
289-
token: DUMMY_TOKEN.address,
290-
..DUMMY_CAMPAIGN.channel
291-
};
292-
293-
let channel_context = ChainOf {
294-
context: channel,
295-
token: DUMMY_TOKEN.clone(),
296-
chain: DUMMY_CHAIN.clone(),
297-
};
323+
let channel_context = ChainOf::new(
324+
GANACHE_1337.clone(),
325+
GANACHE_INFO_1337
326+
.find_token(DUMMY_CAMPAIGN.channel.token)
327+
.cloned()
328+
.unwrap(),
329+
)
330+
.with_channel(DUMMY_CAMPAIGN.channel);
298331

299332
let dummy_client = Dummy::init(Options {
300333
dummy_identity: IDS[&LEADER],
301334
dummy_auth_tokens: Default::default(),
302-
dummy_chain: DUMMY_CHAIN_INFO.clone(),
335+
dummy_chains: GANACHE_CONFIG.chains.values().cloned().collect(),
303336
});
304337

305338
let creator = *CREATOR;
@@ -347,16 +380,21 @@ mod test {
347380
fn test_set_deposit_to_none_should_panic_on_non_mocked_deposits() {
348381
let channel = DUMMY_CAMPAIGN.channel;
349382

383+
let token = GANACHE_INFO_1337
384+
.find_token(channel.token)
385+
.cloned()
386+
.unwrap();
387+
350388
let channel_context = ChainOf {
351389
context: channel,
352-
token: DUMMY_TOKEN.clone(),
353-
chain: DUMMY_CHAIN.clone(),
390+
token,
391+
chain: GANACHE_1337.clone(),
354392
};
355393

356394
let dummy_client = Dummy::init(Options {
357395
dummy_identity: IDS[&LEADER],
358396
dummy_auth_tokens: Default::default(),
359-
dummy_chain: DUMMY_CHAIN_INFO.clone(),
397+
dummy_chains: GANACHE_CONFIG.chains.values().cloned().collect(),
360398
});
361399

362400
// It should panic when no deposit is set and we try to set it to None

docs/config/dummy.toml

Lines changed: 0 additions & 66 deletions
This file was deleted.

primitives/src/chain.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@ use serde::{Deserialize, Serialize};
22
use std::fmt;
33

44
use crate::{config::TokenInfo, util::ApiUrl, Address, Campaign, Channel};
5-
use parse_display::Display;
5+
use parse_display::{Display, FromStr};
66

77
/// The Id of the chain
88
///
99
/// # Ethereum Virtual Machine
1010
///
1111
/// For all the EVM-compatible Chain IDs visit <https://chainid.network>
12-
#[derive(Serialize, Deserialize, Hash, Clone, Copy, Eq, PartialEq, Display)]
12+
#[derive(Serialize, Deserialize, Hash, Clone, Copy, Eq, PartialEq, Display, FromStr)]
1313
#[serde(transparent)]
1414
pub struct ChainId(u32);
1515

1616
impl ChainId {
17-
/// # Panics:
17+
/// # Panics
1818
///
1919
/// If `id` is `0`.
2020
pub fn new(id: u32) -> Self {

primitives/src/config.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,6 @@ pub static GANACHE_CONFIG: Lazy<Config> = Lazy::new(|| {
2121
.expect("Failed to parse ganache.toml config file")
2222
});
2323

24-
#[cfg(feature = "test-util")]
25-
#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
26-
pub static DUMMY_CONFIG: Lazy<Config> = Lazy::new(|| {
27-
Config::try_toml(include_str!("../../docs/config/dummy.toml"))
28-
.expect("Failed to parse ganache.toml config file")
29-
});
30-
3124
#[derive(Debug, Deserialize, PartialEq, Eq, Clone, Copy)]
3225
#[serde(rename_all = "camelCase")]
3326
/// The environment in which the application is running

0 commit comments

Comments
 (0)