@@ -32,6 +32,7 @@ mod live;
3232mod metrics;
3333mod ready;
3434mod revelation;
35+ mod explorer;
3536
3637pub type ChainId = String ;
3738
@@ -48,7 +49,9 @@ pub struct ApiMetrics {
4849
4950#[ derive( Clone ) ]
5051enum JournalLog {
51- Observed ,
52+ Observed {
53+ tx_hash : TxHash
54+ } ,
5255 FailedToReveal {
5356 reason : String ,
5457 } ,
@@ -60,6 +63,17 @@ enum JournalLog {
6063 }
6164}
6265
66+ impl JournalLog {
67+ pub fn get_tx_hash ( & self ) -> Option < TxHash > {
68+ match self {
69+ JournalLog :: Observed { tx_hash } => Some ( * tx_hash) ,
70+ JournalLog :: FailedToReveal { .. } => None ,
71+ JournalLog :: Revealed { tx_hash } => Some ( * tx_hash) ,
72+ JournalLog :: Landed { .. } => None ,
73+ }
74+ }
75+ }
76+
6377#[ derive( Clone ) ]
6478struct TimedJournalLog {
6579 pub timestamp : DateTime < chrono:: Utc > ,
@@ -77,8 +91,10 @@ type RequestKey = (ChainId, u64);
7791
7892#[ derive( Default ) ]
7993struct History {
80- pub by_time : VecDeque < RequestKey > ,
81- pub by_chain : BTreeMap < RequestKey , RequestJournal > ,
94+ pub by_hash : HashMap < TxHash , Vec < RequestKey > > ,
95+ pub by_chain_and_time : BTreeMap < ( ChainId , DateTime < chrono:: Utc > ) , RequestKey > ,
96+ pub by_time : BTreeMap < DateTime < chrono:: Utc > , RequestKey > ,
97+ pub by_request_key : HashMap < RequestKey , RequestJournal > ,
8298}
8399
84100impl History {
@@ -88,62 +104,81 @@ impl History {
88104 }
89105
90106 pub fn add ( & mut self , ( chain_id, sequence) : RequestKey , request_journal_log : TimedJournalLog ) {
91- // Add to the by_chain map
92107 let mut new_entry = false ;
93- let entry = self . by_chain . entry ( ( chain_id. clone ( ) , sequence) ) . or_insert_with ( || {
108+ let entry = self . by_request_key . entry ( ( chain_id. clone ( ) , sequence) ) . or_insert_with ( || {
94109 new_entry = true ;
95110 RequestJournal {
96111 chain_id : chain_id. clone ( ) ,
97112 sequence,
98113 journal : vec ! [ ] ,
99114 }
100115 } ) ;
116+ request_journal_log. log . get_tx_hash ( ) . map ( |tx_hash| {
117+ self . by_hash
118+ . entry ( tx_hash)
119+ . or_insert_with ( Vec :: new)
120+ . push ( ( chain_id. clone ( ) , sequence) ) ;
121+ } ) ;
101122 entry. journal . push ( request_journal_log) ;
102123 if new_entry {
103- self . by_time . push_back ( ( chain_id. clone ( ) , sequence) ) ;
124+ let current_time = chrono:: Utc :: now ( ) ;
125+ self . by_chain_and_time
126+ . insert ( ( chain_id. clone ( ) , current_time) , ( chain_id. clone ( ) , sequence) ) ;
127+ self . by_time
128+ . insert ( current_time, ( chain_id. clone ( ) , sequence) ) ;
129+
104130 if self . by_time . len ( ) > Self :: MAX_HISTORY {
105- let oldest_key = self . by_time . pop_front ( ) . unwrap ( ) ;
106- self . by_chain . remove ( & oldest_key) ;
131+ // TODO
107132 }
108133 }
109134 }
110135
111- pub fn get_request_logs ( & self , request_key : & RequestKey ) -> Option < & Vec < TimedJournalLog > > {
112- self . by_chain . get ( request_key) . map ( |entry| & entry . journal )
136+ pub fn get_request_logs ( & self , request_key : & RequestKey ) -> Option < & RequestJournal > {
137+ self . by_request_key . get ( request_key)
113138 }
114139
115- pub fn get_latest_requests ( & self , chain_id : Option < & ChainId > , limit : u64 ) -> Vec < RequestJournal > {
140+ pub fn get_request_logs_by_tx_hash ( & self , tx_hash : TxHash ) -> Option < Vec < & RequestJournal > > {
141+ self . by_hash . get ( & tx_hash) . map ( |request_keys| {
142+ request_keys. iter ( )
143+ . map ( |request_key| self . by_request_key . get ( request_key) . unwrap ( ) )
144+ . collect ( )
145+ } )
146+ }
147+
148+ pub fn get_latest_requests ( & self , chain_id : Option < & ChainId > , limit : u64 ,
149+ min_timestamp : Option < DateTime < chrono:: Utc > > ,
150+ max_timestamp : Option < DateTime < chrono:: Utc > > ) -> Vec < RequestJournal > {
116151 match chain_id {
117152 Some ( chain_id) => {
118- let range = self . by_chain . range ( ( chain_id. clone ( ) , 0 ) ..( chain_id. clone ( ) , u64 :: MAX ) ) ;
153+ let range = self . by_chain_and_time . range ( ( chain_id. clone ( ) , min_timestamp . unwrap_or ( DateTime :: < chrono :: Utc > :: MIN_UTC ) ) ..( chain_id. clone ( ) , max_timestamp . unwrap_or ( DateTime :: < chrono :: Utc > :: MAX_UTC ) ) ) ;
119154 range. rev ( )
120155 . take ( limit as usize )
121- . map ( |( _, entry) | entry. clone ( ) )
156+ . map ( |( _, request_key) | {
157+ self . by_request_key . get ( request_key) . unwrap ( ) . clone ( )
158+ } )
122159 . collect ( )
123160
124161 } ,
125162 None => {
126163 self . by_time
127- . iter ( )
164+ . range ( min_timestamp . unwrap_or ( DateTime :: < chrono :: Utc > :: MIN_UTC ) ..max_timestamp . unwrap_or ( DateTime :: < chrono :: Utc > :: MAX_UTC ) )
128165 . rev ( )
129166 . take ( limit as usize )
130- . map ( |request_key| {
131- self . by_chain . get ( request_key) . unwrap ( ) . clone ( )
167+ . map ( |( _time , request_key) | {
168+ self . by_request_key . get ( request_key) . unwrap ( ) . clone ( )
132169 } )
133170 . collect :: < Vec < _ > > ( )
134171 } ,
135172 }
136173 }
137-
138-
139174}
140175
141176
142177#[ derive( Clone ) ]
143178pub struct ApiState {
144179 pub chains : Arc < HashMap < ChainId , BlockchainState > > ,
145180
146- // pub history: Arc<History>
181+ pub history : Arc < RwLock < History > > ,
147182
148183 pub metrics_registry : Arc < RwLock < Registry > > ,
149184
@@ -170,6 +205,7 @@ impl ApiState {
170205 ApiState {
171206 chains : Arc :: new ( chains) ,
172207 metrics : Arc :: new ( metrics) ,
208+ history : Arc :: new ( RwLock :: new ( History :: new ( ) ) ) ,
173209 metrics_registry,
174210 }
175211 }
@@ -208,6 +244,7 @@ pub enum RestError {
208244 /// The server cannot currently communicate with the blockchain, so is not able to verify
209245 /// which random values have been requested.
210246 TemporarilyUnavailable ,
247+ BadFilterParameters ( String ) ,
211248 /// A catch-all error for all other types of errors that could occur during processing.
212249 Unknown ,
213250}
@@ -242,6 +279,11 @@ impl IntoResponse for RestError {
242279 "An unknown error occurred processing the request" ,
243280 )
244281 . into_response ( ) ,
282+ RestError :: BadFilterParameters ( message) => (
283+ StatusCode :: BAD_REQUEST ,
284+ format ! ( "Invalid filter parameters: {}" , message) ,
285+ )
286+ . into_response ( ) ,
245287 }
246288 }
247289}
0 commit comments