@@ -4,7 +4,7 @@ use crate::errors::InternalError::{
44 DeprecatedSDKVersion , InvalidSDKVersion , MissingRequiredHeader ,
55} ;
66use crate :: externals:: get_reference_gas_price;
7- use crate :: key_server_options:: ServerMode ;
7+ use crate :: key_server_options:: { ClientKeyType , ServerMode } ;
88use crate :: metrics:: { call_with_duration, observation_callback, status_callback, Metrics } ;
99use crate :: metrics_push:: create_push_client;
1010use crate :: mvr:: mvr_forward_resolution;
@@ -155,17 +155,7 @@ impl Server {
155155 panic ! ( "Failed to load master keys: {}" , e) ;
156156 } ) ;
157157
158- let key_server_oid_to_pop = options
159- . get_supported_key_server_object_ids ( )
160- . into_iter ( )
161- . map ( |ks_oid| {
162- let key = master_keys
163- . get_key_for_key_server ( & ks_oid)
164- . expect ( "checked already" ) ;
165- let pop = create_proof_of_possession ( key, & ks_oid. into_bytes ( ) ) ;
166- ( ks_oid, pop)
167- } )
168- . collect ( ) ;
158+ let key_server_oid_to_pop = Self :: build_key_server_pop_map ( & options, & master_keys) . await ;
169159
170160 Server {
171161 sui_rpc_client,
@@ -175,6 +165,114 @@ impl Server {
175165 }
176166 }
177167
168+ /// Build the key_server_oid -> PoP HashMap for all server modes.
169+ /// Handles fetching from chain for Committee mode.
170+ async fn build_key_server_pop_map (
171+ options : & KeyServerOptions ,
172+ master_keys : & MasterKeys ,
173+ ) -> HashMap < ObjectID , MasterKeyPOP > {
174+ match & options. server_mode {
175+ ServerMode :: Open {
176+ key_server_object_id,
177+ } => {
178+ let key = master_keys
179+ . get_key_for_key_server ( key_server_object_id)
180+ . expect ( "checked already" ) ;
181+ let pop = create_proof_of_possession ( key, & key_server_object_id. into_bytes ( ) ) ;
182+ let mut map = HashMap :: new ( ) ;
183+ map. insert ( * key_server_object_id, pop) ;
184+ map
185+ }
186+ ServerMode :: Committee {
187+ member_address,
188+ committee_id,
189+ next_committee_id : _,
190+ } => {
191+ info ! ( "Committee mode - validating committee at startup" ) ;
192+
193+ // Create gRPC client for seal-committee helpers
194+ let network = match options. network {
195+ Network :: Mainnet => seal_committee:: Network :: Mainnet ,
196+ Network :: Testnet => seal_committee:: Network :: Testnet ,
197+ _ => panic ! ( "Unsupported network for Committee mode" ) ,
198+ } ;
199+ let mut grpc_client = seal_committee:: create_grpc_client ( network)
200+ . expect ( "Failed to create gRPC client" ) ;
201+
202+ // Fetch and verify committee is finalized
203+ let committee_addr = sui_sdk_types:: Address :: from_bytes ( committee_id. as_ref ( ) )
204+ . unwrap_or_else ( |e| panic ! ( "Invalid committee ID: {:?}" , e) ) ;
205+ if !seal_committee:: check_committee_finalized ( & mut grpc_client, & committee_addr)
206+ . await
207+ . unwrap_or_else ( |e| panic ! ( "Failed to check committee finalized: {:?}" , e) )
208+ {
209+ panic ! ( "Committee {} is not finalized" , committee_id) ;
210+ }
211+
212+ // Fetch KeyServer from committee's dynamic field
213+ let key_server_id =
214+ seal_committee:: fetch_key_server_id ( & mut grpc_client, & committee_addr)
215+ . await
216+ . unwrap_or_else ( |e| {
217+ panic ! ( "Failed to fetch KeyServer from committee: {:?}" , e)
218+ } ) ;
219+
220+ let key_server_oid = ObjectID :: new ( key_server_id. into_inner ( ) ) ;
221+
222+ // Fetch PartialKeyServer info for this member
223+ let partial_key_server_info = seal_committee:: fetch_partial_key_server_info (
224+ & mut grpc_client,
225+ & key_server_id,
226+ * member_address,
227+ )
228+ . await
229+ . unwrap_or_else ( |e| panic ! ( "Failed to fetch PartialKeyServer: {:?}" , e) )
230+ . unwrap_or_else ( || {
231+ panic ! ( "No PartialKeyServer found for member {}" , member_address)
232+ } ) ;
233+
234+ // Sign PoP over: key_server_oid || party_id || partial_pk
235+ let mut pop_message = Vec :: new ( ) ;
236+ pop_message. extend_from_slice ( & key_server_oid. into_bytes ( ) ) ;
237+ pop_message. extend_from_slice ( & partial_key_server_info. party_id . to_le_bytes ( ) ) ;
238+ pop_message. extend_from_slice ( & partial_key_server_info. partial_pk ) ;
239+
240+ // Extract master_key from already-loaded MasterKeys
241+ let master_key = match master_keys {
242+ MasterKeys :: Open { master_key } => master_key,
243+ _ => panic ! ( "Committee mode requires Open master key configuration" ) ,
244+ } ;
245+ let pop = create_proof_of_possession ( master_key, & pop_message) ;
246+
247+ info ! (
248+ "Committee mode: KeyServer {} with party_id={} for POP with MASTER_KEY" ,
249+ key_server_oid, partial_key_server_info. party_id
250+ ) ;
251+
252+ // Use KeyServer object ID as the key since PartialKeyServer is stored inline
253+ let mut map = HashMap :: new ( ) ;
254+ map. insert ( key_server_oid, pop) ;
255+ map
256+ }
257+ ServerMode :: Permissioned { client_configs } => client_configs
258+ . iter ( )
259+ . filter ( |c| {
260+ matches ! (
261+ c. client_master_key,
262+ ClientKeyType :: Derived { .. } | ClientKeyType :: Imported { .. }
263+ )
264+ } )
265+ . map ( |c| {
266+ let key = master_keys
267+ . get_key_for_key_server ( & c. key_server_object_id )
268+ . expect ( "checked already" ) ;
269+ let pop = create_proof_of_possession ( key, & c. key_server_object_id . into_bytes ( ) ) ;
270+ ( c. key_server_object_id , pop)
271+ } )
272+ . collect ( ) ,
273+ }
274+ }
275+
178276 #[ allow( clippy:: too_many_arguments) ]
179277 async fn check_signature (
180278 & self ,
0 commit comments