1use crate::{CodeInfo, Error};
2use codec::{Compact, Decode, Encode};
3use corevm_host::StorageKey;
4use jam_program_blob::{read_metadata, ConventionalMetadata as Metadata, CrateInfo};
5use jam_std_common::{RpcClient, Service, SyncStatus};
6use jam_types::{CodeHash, Hash, HeaderHash, ServiceId};
7use jsonrpsee::ws_client::WsClient;
8
9pub async fn query_service(
10 rpc: &WsClient,
11 head: HeaderHash,
12 id: ServiceId,
13) -> Result<(Service, CodeInfo<CrateInfo>, Option<CodeInfo<CrateInfo>>), anyhow::Error> {
14 use CodeInfo::*;
15 let req = rpc.service_data(head, id).await?.ok_or(Error::ServiceNotFound)?;
16 let info = Service::decode(&mut &req[..]).map_err(Error::InvalidServiceEncoding)?;
17 let maybe_code = rpc.service_preimage(head, id, info.code_hash.0).await?;
18 let meta = match maybe_code {
19 None => CodeNotProvided(info.code_hash),
20 Some(code) => match <(Compact<u32>, Metadata)>::decode(&mut &code[..]).ok().map(|x| x.1) {
21 None => Undefined(info.code_hash),
22 Some(Metadata::Info(crate_info)) => Known(crate_info),
23 },
24 };
25 let inner_meta = match &meta {
26 Known(info) if info.name == "corevm" => {
27 if let Some(inner_code) =
28 rpc.service_value(head, id, StorageKey::GuestCode.encode()).await?
29 {
30 let (file_hash, code_host) = <(CodeHash, ServiceId)>::decode(&mut &inner_code[..])
31 .map_err(Error::InvalidServiceEncoding)?;
32 log::info!("inner file hash: {file_hash}, service id: {code_host}");
33 let maybe_file_chunk = rpc.service_preimage(head, code_host, file_hash.0).await?;
34 Some(match maybe_file_chunk {
35 None => CodeNotProvided(file_hash),
36 Some(data) => {
37 let _next_hash = Hash::try_from(&data[..32]).expect("fixed length");
38 let code = &data[32..];
39 match read_metadata(&mut &code[..]) {
40 Err(_) => Undefined(file_hash),
41 Ok(Metadata::Info(crate_info)) => Known(crate_info),
42 }
43 },
44 })
45 } else {
46 None
47 }
48 },
49 _ => None,
50 };
51 Ok((info, meta, inner_meta))
52}
53
54pub async fn wait_for_sync(rpc: &WsClient) -> Result<(), anyhow::Error> {
55 let mut sync_state = rpc.subscribe_sync_status().await?;
56 loop {
57 let status = sync_state.next().await;
58 match status {
59 Some(Ok(SyncStatus::Completed)) => break,
60 Some(Ok(_)) => continue,
61 Some(Err(e)) => return Err(e)?,
62 None => break,
63 }
64 }
65 let mut final_block = rpc.subscribe_finalized_block().await?;
67 loop {
68 let status = final_block.next().await;
69 match status {
70 Some(Ok(block)) if block.slot > 0 => break,
71 Some(Ok(_)) => continue,
72 Some(Err(e)) => return Err(e)?,
73 None => break,
74 }
75 }
76 Ok(())
77}