@@ -11,6 +11,45 @@ use crate::{chain::PublicKeyHash, get_environment, transaction::StakeTransaction
11
11
12
12
use super :: prelude:: * ;
13
13
14
+ /// Message for querying stakes
15
+ #[ derive( Clone , Debug , Deserialize , Eq , PartialEq , Serialize ) ]
16
+ pub enum QueryStakesKey < Address : Default + Ord > {
17
+ /// Query stakes by validator address
18
+ Validator ( Address ) ,
19
+ /// Query stakes by withdrawer address
20
+ Withdrawer ( Address ) ,
21
+ /// Query stakes by validator and withdrawer addresses
22
+ Key ( StakeKey < Address > ) ,
23
+ }
24
+
25
+ impl < Address : Default + Ord > Default for QueryStakesKey < Address > {
26
+ fn default ( ) -> Self {
27
+ QueryStakesKey :: Validator ( Address :: default ( ) )
28
+ }
29
+ }
30
+
31
+ impl < Address : Default + Ord , T > From < ( Option < T > , Option < T > ) > for QueryStakesKey < Address >
32
+ where
33
+ T : Into < Address > ,
34
+ {
35
+ fn from ( val : ( Option < T > , Option < T > ) ) -> Self {
36
+ let validator = val. 0 ;
37
+ let withdrawer = val. 1 ;
38
+
39
+ if validator. is_some ( ) && withdrawer. is_some ( ) {
40
+ QueryStakesKey :: Key ( StakeKey {
41
+ validator : validator. unwrap ( ) . into ( ) ,
42
+ withdrawer : withdrawer. unwrap ( ) . into ( ) ,
43
+ } )
44
+ } else if validator. is_some ( ) {
45
+ QueryStakesKey :: Validator ( validator. unwrap ( ) . into ( ) )
46
+ // } else if withdrawer.is_some() {
47
+ } else {
48
+ QueryStakesKey :: Withdrawer ( withdrawer. unwrap ( ) . into ( ) )
49
+ }
50
+ }
51
+ }
52
+
14
53
/// The main data structure that provides the "stakes tracker" functionality.
15
54
///
16
55
/// This structure holds indexes of stake entries. Because the entries themselves are reference
24
63
{
25
64
/// A listing of all the stakers, indexed by their address.
26
65
by_key : BTreeMap < StakeKey < Address > , SyncStake < Address , Coins , Epoch , Power > > ,
66
+ /// A listing of all the stakers, indexed by validator.
67
+ by_validator : BTreeMap < Address , SyncStake < Address , Coins , Epoch , Power > > ,
68
+ /// A listing of all the stakers, indexed by withdrawer.
69
+ by_withdrawer : BTreeMap < Address , SyncStake < Address , Coins , Epoch , Power > > ,
27
70
/// A listing of all the stakers, indexed by their coins and address.
28
71
///
29
72
/// Because this uses a compound key to prevent duplicates, if we want to know which addresses
@@ -83,7 +126,15 @@ where
83
126
addresses : key,
84
127
} ;
85
128
self . by_coins . remove ( & key) ;
86
- self . by_coins . insert ( key, stake. clone ( ) ) ;
129
+ self . by_coins . insert ( key. clone ( ) , stake. clone ( ) ) ;
130
+
131
+ let validator_key = key. clone ( ) . addresses . validator ;
132
+ self . by_validator . remove ( & validator_key) ;
133
+ self . by_validator . insert ( validator_key, stake. clone ( ) ) ;
134
+
135
+ let withdrawer_key = key. addresses . withdrawer ;
136
+ self . by_withdrawer . remove ( & withdrawer_key) ;
137
+ self . by_withdrawer . insert ( withdrawer_key, stake. clone ( ) ) ;
87
138
88
139
Ok ( stake. value . read ( ) ?. clone ( ) )
89
140
}
@@ -228,6 +279,39 @@ where
228
279
..Default :: default ( )
229
280
}
230
281
}
282
+
283
+ /// Query stakes based on different keys.
284
+ pub fn query_stakes < IQSK > ( & mut self , query : IQSK ) -> Option < Coins >
285
+ where
286
+ IQSK : Into < QueryStakesKey < Address > > ,
287
+ {
288
+ match query. into ( ) {
289
+ QueryStakesKey :: Key ( key) => self . query_by_key ( & key) ,
290
+ QueryStakesKey :: Validator ( validator) => self . query_by_validator ( & validator) ,
291
+ QueryStakesKey :: Withdrawer ( withdrawer) => self . query_by_withdrawer ( & withdrawer) ,
292
+ }
293
+ }
294
+
295
+ /// Query stakes by stake key.
296
+ fn query_by_key ( & self , key : & StakeKey < Address > ) -> Option < Coins > {
297
+ self . by_key
298
+ . get_key_value ( key)
299
+ . and_then ( |entry| entry. 1 . value . read ( ) . map ( |stake| stake. coins ) . ok ( ) )
300
+ }
301
+
302
+ /// Query stakes by validator address.
303
+ fn query_by_validator ( & self , validator : & Address ) -> Option < Coins > {
304
+ self . by_validator
305
+ . get_key_value ( validator)
306
+ . and_then ( |entry| entry. 1 . value . read ( ) . map ( |stake| stake. coins ) . ok ( ) )
307
+ }
308
+
309
+ /// Query stakes by withdrawer address.
310
+ fn query_by_withdrawer ( & self , withdrawer : & Address ) -> Option < Coins > {
311
+ self . by_withdrawer
312
+ . get_key_value ( withdrawer)
313
+ . and_then ( |entry| entry. 1 . value . read ( ) . map ( |stake| stake. coins ) . ok ( ) )
314
+ }
231
315
}
232
316
233
317
/// Adds stake, based on the data from a stake transaction.
@@ -591,4 +675,27 @@ mod tests {
591
675
]
592
676
) ;
593
677
}
678
+
679
+ #[ test]
680
+ fn test_query_stakes ( ) {
681
+ // First, lets create a setup with a few stakers
682
+ let mut stakes = Stakes :: < String , u64 , u64 , u64 > :: with_minimum ( 5 ) ;
683
+ let alice = "Alice" ;
684
+ let bob = "Bob" ;
685
+ let charlie = "Charlie" ;
686
+ let david = "David" ;
687
+ let erin = "Erin" ;
688
+
689
+ let alice_charlie = ( alice, charlie) ;
690
+ let bob_david = ( bob, david) ;
691
+ let charlie_erin = ( charlie, erin) ;
692
+
693
+ stakes. add_stake ( alice_charlie, 10 , 0 ) . unwrap ( ) ;
694
+ stakes. add_stake ( bob_david, 20 , 20 ) . unwrap ( ) ;
695
+ stakes. add_stake ( charlie_erin, 30 , 30 ) . unwrap ( ) ;
696
+
697
+ let result = stakes. query_stakes ( QueryStakesKey :: Key ( alice_charlie. into ( ) ) ) ;
698
+
699
+ assert_eq ! ( result, Some ( 10 ) )
700
+ }
594
701
}
0 commit comments