1
+ use std:: collections:: HashMap ;
1
2
use std:: sync:: Arc ;
2
3
use std:: time:: { Duration , SystemTime } ;
3
4
4
5
use rocket:: tokio:: sync:: RwLock ;
6
+ use serde:: { Deserialize , Serialize } ;
5
7
6
8
use mixnet_contract:: MixNodeBond ;
7
9
use validator_client:: Config ;
8
10
11
+ pub ( crate ) type LocationCache = HashMap < String , Location > ;
12
+
13
+ #[ derive( Clone , Debug , JsonSchema , Serialize , Deserialize ) ]
14
+ pub ( crate ) struct Location {
15
+ pub ( crate ) two_letter_iso_country_code : String ,
16
+ pub ( crate ) three_letter_iso_country_code : String ,
17
+ pub ( crate ) country_name : String ,
18
+ }
19
+
20
+ #[ derive( Clone , Debug ) ]
21
+ pub ( crate ) struct MixNodeBondWithLocation {
22
+ pub ( crate ) location : Option < Location > ,
23
+ pub ( crate ) bond : MixNodeBond ,
24
+ }
25
+
9
26
#[ derive( Clone , Debug ) ]
10
27
pub ( crate ) struct MixNodesResult {
11
28
pub ( crate ) valid_until : SystemTime ,
12
- pub ( crate ) value : Vec < MixNodeBond > ,
29
+ pub ( crate ) value : HashMap < String , MixNodeBondWithLocation > ,
30
+ location_cache : LocationCache ,
13
31
}
14
32
15
33
#[ derive( Clone ) ]
@@ -21,12 +39,42 @@ impl ThreadsafeMixNodesResult {
21
39
pub ( crate ) fn new ( ) -> Self {
22
40
ThreadsafeMixNodesResult {
23
41
inner : Arc :: new ( RwLock :: new ( MixNodesResult {
24
- value : vec ! [ ] ,
42
+ value : HashMap :: new ( ) ,
25
43
valid_until : SystemTime :: now ( ) - Duration :: from_secs ( 60 ) , // in the past
44
+ location_cache : LocationCache :: new ( ) ,
26
45
} ) ) ,
27
46
}
28
47
}
29
48
49
+ pub ( crate ) fn attach ( location_cache : LocationCache ) -> Self {
50
+ ThreadsafeMixNodesResult {
51
+ inner : Arc :: new ( RwLock :: new ( MixNodesResult {
52
+ value : HashMap :: new ( ) ,
53
+ valid_until : SystemTime :: now ( ) - Duration :: from_secs ( 60 ) , // in the past
54
+ location_cache,
55
+ } ) ) ,
56
+ }
57
+ }
58
+
59
+ pub ( crate ) async fn get_location_cache ( & self ) -> LocationCache {
60
+ self . inner . read ( ) . await . location_cache . clone ( )
61
+ }
62
+
63
+ pub ( crate ) async fn set_location ( & self , identity_key : & str , location : Location ) {
64
+ let mut guard = self . inner . write ( ) . await ;
65
+
66
+ // cache the location for this mix node so that it can be used when the mix node list is refreshed
67
+ guard
68
+ . location_cache
69
+ . insert ( identity_key. to_string ( ) , location. clone ( ) ) ;
70
+
71
+ // add the location to the mix node
72
+ guard
73
+ . value
74
+ . entry ( identity_key. to_string ( ) )
75
+ . and_modify ( |item| item. location = Some ( location) ) ;
76
+ }
77
+
30
78
pub ( crate ) async fn get ( & self ) -> MixNodesResult {
31
79
// check ttl
32
80
let valid_until = self . inner . clone ( ) . read ( ) . await . valid_until ;
@@ -48,9 +96,24 @@ impl ThreadsafeMixNodesResult {
48
96
async fn refresh ( & self ) {
49
97
// get mixnodes and cache the new value
50
98
let value = retrieve_mixnodes ( ) . await ;
99
+ let location_cache = self . inner . read ( ) . await . location_cache . clone ( ) ;
51
100
self . inner . write ( ) . await . clone_from ( & MixNodesResult {
52
- value,
101
+ value : value
102
+ . iter ( )
103
+ . map ( |bond| {
104
+ (
105
+ bond. mix_node . identity_key . to_string ( ) ,
106
+ MixNodeBondWithLocation {
107
+ bond : bond. clone ( ) ,
108
+ location : location_cache
109
+ . get ( & bond. mix_node . identity_key . to_string ( ) )
110
+ . cloned ( ) , // add the location, if we've located this mix node before
111
+ } ,
112
+ )
113
+ } )
114
+ . collect ( ) ,
53
115
valid_until : SystemTime :: now ( ) + Duration :: from_secs ( 60 * 10 ) , // valid for 10 minutes
116
+ location_cache,
54
117
} ) ;
55
118
}
56
119
}
0 commit comments