1use crate::{CodeInfo, Error};
2use codec::{Compact, Decode};
3use futures::StreamExt;
4use jam_program_blob_common::{ConventionalMetadata as Metadata, CrateInfo};
5use jam_std_common::{BlockDesc, Node, NodeError, NodeExt as _, Service, SyncStatus};
6use jam_types::{HeaderHash, RefineContext, ServiceId, Slot};
7use std::future::Future;
8
9pub trait NodeExt: Node {
10 fn query_service(
11 &self,
12 head: HeaderHash,
13 id: ServiceId,
14 ) -> impl Future<Output = Result<(Service, CodeInfo<CrateInfo>), anyhow::Error>> + Send {
15 async move {
16 use CodeInfo::*;
17 let info = self.service_data(head, id).await?.ok_or(Error::ServiceNotFound)?;
18 let maybe_code = self.service_preimage(head, id, info.code_hash.0).await?;
19 let meta = match maybe_code {
20 None => CodeNotProvided(info.code_hash.0),
21 Some(code) =>
22 match <(Compact<u32>, Metadata)>::decode(&mut &code[..]).ok().map(|x| x.1) {
23 None => Undefined(info.code_hash.0),
24 Some(Metadata::Info(crate_info)) => Known(crate_info),
25 },
26 };
27 Ok((info, meta))
28 }
29 }
30
31 fn wait_for_sync(&self) -> impl Future<Output = Result<(), anyhow::Error>> + Send {
32 async move {
33 let mut sync_state = self.subscribe_sync_status().await?;
34 loop {
35 let status = sync_state.next().await;
36 match status {
37 Some(Ok(SyncStatus::Completed)) => break,
38 Some(Ok(_)) => continue,
39 Some(Err(e)) => return Err(e.into()),
40 None => break,
41 }
42 }
43 let mut final_block = self.subscribe_finalized_block().await?;
45 loop {
46 let status = final_block.next().await;
47 match status {
48 Some(Ok(block)) if block.slot > 0 => {
49 match self.parent(block.header_hash).await {
50 Ok(parent) => {
51 if parent.slot > 0 {
52 break;
55 }
56 eprintln!("Waiting for two non-genesis blocks to be finalized...");
57 },
58 Err(NodeError::BlockUnavailable(_)) => {
59 eprintln!("Waiting for two non-genesis blocks to be finalized and available...");
61 },
62 Err(err) => return Err(err.into()),
63 }
64 },
65 Some(Ok(_)) => {
66 eprintln!("Waiting for two non-genesis blocks to be finalized...");
67 },
68 Some(Err(e)) => return Err(e.into()),
69 None => break,
70 }
71 }
72 Ok(())
73 }
74 }
75
76 fn lookup_anchor_block(&self) -> impl Future<Output = Result<BlockDesc, NodeError>> + Send {
80 async move {
81 let finalized = self.finalized_block().await?;
82 let parent = self.parent(finalized.header_hash).await?;
83 Ok(parent)
84 }
85 }
86
87 fn create_refine_context(
94 &self,
95 ) -> impl Future<Output = Result<(RefineContext, Slot), NodeError>> + Send {
96 async move {
97 let BlockDesc { header_hash: lookup_anchor, slot: lookup_anchor_slot } =
100 self.lookup_anchor_block().await?;
101 let best_block = self.best_block().await?;
104 let parent = self.parent(best_block.header_hash).await?;
105 let anchor = parent.header_hash;
106 let state_root = self.state_root(anchor).await?;
107 let beefy_root = self.beefy_root(anchor).await?;
108 let context = RefineContext {
109 anchor,
110 state_root,
111 beefy_root,
112 lookup_anchor,
113 lookup_anchor_slot,
114 prerequisites: Default::default(),
115 };
116 Ok((context, parent.slot))
117 }
118 }
119}
120
121impl<T: Node + ?Sized> NodeExt for T {}