@@ -7,6 +7,7 @@ use crate::{
7
7
} ;
8
8
use async_trait:: async_trait;
9
9
10
+ use parse_display:: { Display , FromStr } ;
10
11
use primitives:: {
11
12
config:: ChainInfo , Address , ChainId , ChainOf , Channel , ToETHChecksum , ValidatorId ,
12
13
} ;
@@ -17,26 +18,6 @@ pub use self::deposit::Deposits;
17
18
18
19
pub type Adapter < S > = crate :: Adapter < Dummy , S > ;
19
20
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
-
40
21
#[ derive( Debug , Clone ) ]
41
22
pub struct Options {
42
23
/// The identity used for the Adapter.
@@ -46,7 +27,7 @@ pub struct Options {
46
27
pub dummy_auth_tokens : HashMap < Address , String > ,
47
28
/// The [`ChainInfo`] that will be used for the [`Session`]s and
48
29
/// also for the deposits.
49
- pub dummy_chain : ChainInfo ,
30
+ pub dummy_chains : Vec < ChainInfo > ,
50
31
}
51
32
52
33
/// Dummy adapter implementation intended for testing.
@@ -56,7 +37,7 @@ pub struct Dummy {
56
37
identity : ValidatorId ,
57
38
/// Static authentication tokens (address => token)
58
39
authorization_tokens : HashMap < Address , String > ,
59
- chain_info : ChainInfo ,
40
+ chains : Vec < ChainInfo > ,
60
41
deposits : Deposits ,
61
42
}
62
43
@@ -65,7 +46,7 @@ impl Dummy {
65
46
Self {
66
47
identity : opts. dummy_identity ,
67
48
authorization_tokens : opts. dummy_auth_tokens ,
68
- chain_info : opts. dummy_chain ,
49
+ chains : opts. dummy_chains ,
69
50
deposits : Default :: default ( ) ,
70
51
}
71
52
}
@@ -130,24 +111,45 @@ impl Locked for Dummy {
130
111
}
131
112
132
113
/// 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
136
138
. authorization_tokens
137
139
. 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
+ } )
151
153
}
152
154
153
155
async fn get_deposit (
@@ -163,15 +165,26 @@ impl Locked for Dummy {
163
165
) ) ;
164
166
}
165
167
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
171
169
{
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
+ } ) ?;
175
188
}
176
189
177
190
self . deposits
@@ -199,16 +212,25 @@ impl Unlocked for Dummy {
199
212
}
200
213
201
214
// 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
204
220
. get ( & self . identity . to_address ( ) )
205
221
. cloned ( )
206
222
. ok_or_else ( || {
207
223
Error :: authentication ( format ! (
208
224
"No auth token for this identity: {}" ,
209
225
self . identity
210
226
) )
211
- } )
227
+ } ) ?;
228
+
229
+ Ok ( HeaderToken {
230
+ token,
231
+ chain_id : for_chain,
232
+ }
233
+ . to_string ( ) )
212
234
}
213
235
}
214
236
@@ -220,6 +242,19 @@ impl Unlockable for Dummy {
220
242
}
221
243
}
222
244
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
+
223
258
mod deposit {
224
259
use crate :: primitives:: Deposit ;
225
260
use dashmap:: DashMap ;
@@ -274,32 +309,30 @@ mod deposit {
274
309
#[ cfg( test) ]
275
310
mod test {
276
311
use primitives:: {
312
+ config:: GANACHE_CONFIG ,
277
313
test_util:: { CREATOR , DUMMY_CAMPAIGN , IDS , LEADER , PUBLISHER } ,
278
314
BigNum , ChainOf ,
279
315
} ;
280
316
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 :: * ;
285
320
286
321
#[ tokio:: test]
287
322
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 ) ;
298
331
299
332
let dummy_client = Dummy :: init ( Options {
300
333
dummy_identity : IDS [ & LEADER ] ,
301
334
dummy_auth_tokens : Default :: default ( ) ,
302
- dummy_chain : DUMMY_CHAIN_INFO . clone ( ) ,
335
+ dummy_chains : GANACHE_CONFIG . chains . values ( ) . cloned ( ) . collect ( ) ,
303
336
} ) ;
304
337
305
338
let creator = * CREATOR ;
@@ -347,16 +380,21 @@ mod test {
347
380
fn test_set_deposit_to_none_should_panic_on_non_mocked_deposits ( ) {
348
381
let channel = DUMMY_CAMPAIGN . channel ;
349
382
383
+ let token = GANACHE_INFO_1337
384
+ . find_token ( channel. token )
385
+ . cloned ( )
386
+ . unwrap ( ) ;
387
+
350
388
let channel_context = ChainOf {
351
389
context : channel,
352
- token : DUMMY_TOKEN . clone ( ) ,
353
- chain : DUMMY_CHAIN . clone ( ) ,
390
+ token,
391
+ chain : GANACHE_1337 . clone ( ) ,
354
392
} ;
355
393
356
394
let dummy_client = Dummy :: init ( Options {
357
395
dummy_identity : IDS [ & LEADER ] ,
358
396
dummy_auth_tokens : Default :: default ( ) ,
359
- dummy_chain : DUMMY_CHAIN_INFO . clone ( ) ,
397
+ dummy_chains : GANACHE_CONFIG . chains . values ( ) . cloned ( ) . collect ( ) ,
360
398
} ) ;
361
399
362
400
// It should panic when no deposit is set and we try to set it to None
0 commit comments