@@ -7,13 +7,16 @@ use std::collections::BTreeSet;
77
88use crate :: { agent:: Agent , cose:: CoseClient , store} ;
99
10+ const MILLISECONDS : u64 = 1_000_000 ;
11+
1012#[ derive( CandidType , Deserialize , Serialize ) ]
1113pub struct StateInfo {
1214 pub ecdsa_key_name : String ,
1315 pub proxy_token_public_key : String ,
1416 pub proxy_token_refresh_interval : u64 , // seconds
1517 pub agents : Vec < Agent > ,
1618 pub managers : BTreeSet < Principal > ,
19+ pub callers : u64 ,
1720 pub subnet_size : u64 ,
1821 pub service_fee : u64 , // in cycles
1922 pub incoming_cycles : u128 ,
@@ -22,8 +25,8 @@ pub struct StateInfo {
2225}
2326
2427#[ ic_cdk:: query]
25- fn get_state ( ) -> Result < StateInfo , String > {
26- let s = store:: state:: with ( |s| StateInfo {
28+ fn state_info ( ) -> StateInfo {
29+ store:: state:: with ( |s| StateInfo {
2730 ecdsa_key_name : s. ecdsa_key_name . clone ( ) ,
2831 proxy_token_public_key : s. proxy_token_public_key . clone ( ) ,
2932 proxy_token_refresh_interval : s. proxy_token_refresh_interval ,
@@ -38,18 +41,18 @@ fn get_state() -> Result<StateInfo, String> {
3841 } )
3942 . collect ( ) ,
4043 managers : s. managers . clone ( ) ,
44+ callers : s. callers . len ( ) as u64 ,
4145 subnet_size : s. subnet_size ,
4246 service_fee : s. service_fee ,
4347 incoming_cycles : s. incoming_cycles ,
4448 uncollectible_cycles : s. uncollectible_cycles ,
4549 cose : s. cose . clone ( ) ,
46- } ) ;
47- Ok ( s)
50+ } )
4851}
4952
5053#[ ic_cdk:: query]
51- fn is_caller ( id : Principal ) -> Result < bool , String > {
52- store:: state:: with ( |s| Ok ( s . allowed_callers . contains ( & id) ) )
54+ fn caller_info ( id : Principal ) -> Option < ( u128 , u64 ) > {
55+ store:: state:: with ( |s| s . callers . get ( & id) . copied ( ) )
5356}
5457
5558#[ ic_cdk:: query]
@@ -75,7 +78,8 @@ async fn parallel_call_cost(req: CanisterHttpRequestArgument) -> u128 {
7578/// Proxy HTTP request by all agents in sequence until one returns an status <= 500 result.
7679#[ ic_cdk:: update]
7780async fn proxy_http_request ( req : CanisterHttpRequestArgument ) -> HttpResponse {
78- if !store:: state:: is_allowed ( & ic_cdk:: caller ( ) ) {
81+ let caller = ic_cdk:: caller ( ) ;
82+ if !store:: state:: is_allowed ( & caller) {
7983 return HttpResponse {
8084 status : Nat :: from ( 403u64 ) ,
8185 body : "caller is not allowed" . as_bytes ( ) . to_vec ( ) ,
@@ -92,6 +96,7 @@ async fn proxy_http_request(req: CanisterHttpRequestArgument) -> HttpResponse {
9296 } ;
9397 }
9498
99+ let balance = ic_cdk:: api:: call:: msg_cycles_available128 ( ) ;
95100 let calc = store:: state:: cycles_calculator ( ) ;
96101 store:: state:: receive_cycles (
97102 calc. ingress_cost ( ic_cdk:: api:: call:: arg_data_raw_size ( ) ) ,
@@ -106,20 +111,31 @@ async fn proxy_http_request(req: CanisterHttpRequestArgument) -> HttpResponse {
106111 Ok ( res) => {
107112 let cycles = calc. http_outcall_response_cost ( calc. count_response_bytes ( & res) , 1 ) ;
108113 store:: state:: receive_cycles ( cycles, true ) ;
114+ store:: state:: update_caller_state (
115+ & caller,
116+ balance - ic_cdk:: api:: call:: msg_cycles_available128 ( ) ,
117+ ic_cdk:: api:: time ( ) / MILLISECONDS ,
118+ ) ;
109119 return res;
110120 }
111121 Err ( res) => last_err = Some ( res) ,
112122 }
113123 }
114124
125+ store:: state:: update_caller_state (
126+ & caller,
127+ balance - ic_cdk:: api:: call:: msg_cycles_available128 ( ) ,
128+ ic_cdk:: api:: time ( ) / MILLISECONDS ,
129+ ) ;
115130 last_err. unwrap ( )
116131}
117132
118133/// Proxy HTTP request by all agents in parallel and return the result if all are the same,
119134/// or a 500 HttpResponse with all result.
120135#[ ic_cdk:: update]
121136async fn parallel_call_all_ok ( req : CanisterHttpRequestArgument ) -> HttpResponse {
122- if !store:: state:: is_allowed ( & ic_cdk:: caller ( ) ) {
137+ let caller = ic_cdk:: caller ( ) ;
138+ if !store:: state:: is_allowed ( & caller) {
123139 return HttpResponse {
124140 status : Nat :: from ( 403u64 ) ,
125141 body : "caller is not allowed" . as_bytes ( ) . to_vec ( ) ,
@@ -136,14 +152,15 @@ async fn parallel_call_all_ok(req: CanisterHttpRequestArgument) -> HttpResponse
136152 } ;
137153 }
138154
155+ let balance = ic_cdk:: api:: call:: msg_cycles_available128 ( ) ;
139156 let calc = store:: state:: cycles_calculator ( ) ;
140157 let cycles = calc. ingress_cost ( ic_cdk:: api:: call:: arg_data_raw_size ( ) )
141158 + calc. http_outcall_request_cost ( calc. count_request_bytes ( & req) , agents. len ( ) ) ;
142159 store:: state:: receive_cycles ( cycles, false ) ;
143160
144161 let results =
145162 futures:: future:: try_join_all ( agents. iter ( ) . map ( |agent| agent. call ( req. clone ( ) ) ) ) . await ;
146- match results {
163+ let result = match results {
147164 Err ( res) => res,
148165 Ok ( res) => {
149166 let mut results = res. into_iter ( ) ;
@@ -164,22 +181,30 @@ async fn parallel_call_all_ok(req: CanisterHttpRequestArgument) -> HttpResponse
164181 let mut buf = vec ! [ ] ;
165182 into_writer ( & inconsistent_results, & mut buf)
166183 . expect ( "failed to encode inconsistent results" ) ;
167- return HttpResponse {
184+ HttpResponse {
168185 status : Nat :: from ( 500u64 ) ,
169186 body : buf,
170187 headers : vec ! [ ] ,
171- } ;
188+ }
189+ } else {
190+ base_result
172191 }
173-
174- base_result
175192 }
176- }
193+ } ;
194+
195+ store:: state:: update_caller_state (
196+ & caller,
197+ balance - ic_cdk:: api:: call:: msg_cycles_available128 ( ) ,
198+ ic_cdk:: api:: time ( ) / MILLISECONDS ,
199+ ) ;
200+ result
177201}
178202
179203/// Proxy HTTP request by all agents in parallel and return the first (status <= 500) result.
180204#[ ic_cdk:: update]
181205async fn parallel_call_any_ok ( req : CanisterHttpRequestArgument ) -> HttpResponse {
182- if !store:: state:: is_allowed ( & ic_cdk:: caller ( ) ) {
206+ let caller = ic_cdk:: caller ( ) ;
207+ if !store:: state:: is_allowed ( & caller) {
183208 return HttpResponse {
184209 status : Nat :: from ( 403u64 ) ,
185210 body : "caller is not allowed" . as_bytes ( ) . to_vec ( ) ,
@@ -196,6 +221,7 @@ async fn parallel_call_any_ok(req: CanisterHttpRequestArgument) -> HttpResponse
196221 } ;
197222 }
198223
224+ let balance = ic_cdk:: api:: call:: msg_cycles_available128 ( ) ;
199225 let calc = store:: state:: cycles_calculator ( ) ;
200226 let cycles = calc. ingress_cost ( ic_cdk:: api:: call:: arg_data_raw_size ( ) )
201227 + calc. http_outcall_request_cost ( calc. count_request_bytes ( & req) , agents. len ( ) ) ;
@@ -204,13 +230,20 @@ async fn parallel_call_any_ok(req: CanisterHttpRequestArgument) -> HttpResponse
204230 let result =
205231 futures:: future:: select_ok ( agents. iter ( ) . map ( |agent| agent. call ( req. clone ( ) ) . boxed ( ) ) )
206232 . await ;
207- match result {
233+ let result = match result {
208234 Ok ( ( res, _) ) => {
209235 let cycles =
210236 calc. http_outcall_response_cost ( calc. count_response_bytes ( & res) , agents. len ( ) ) ;
211237 store:: state:: receive_cycles ( cycles, true ) ;
212238 res
213239 }
214240 Err ( res) => res,
215- }
241+ } ;
242+
243+ store:: state:: update_caller_state (
244+ & caller,
245+ balance - ic_cdk:: api:: call:: msg_cycles_available128 ( ) ,
246+ ic_cdk:: api:: time ( ) / MILLISECONDS ,
247+ ) ;
248+ result
216249}
0 commit comments