oasis_core_runtime/host/
mod.rs1use async_trait::async_trait;
3use thiserror::Error;
4
5use crate::{
6 common::{crypto::signature::PublicKey, namespace::Namespace},
7 enclave_rpc,
8 protocol::Protocol,
9 storage::mkvs::sync,
10 types::{self, Body},
11};
12
13pub mod bundle_manager;
14pub mod volume_manager;
15
16#[derive(Error, Debug)]
18pub enum Error {
19 #[error("bad response from host")]
20 BadResponse,
21
22 #[error("{0}")]
23 Host(#[from] types::Error),
24
25 #[error("{0}")]
26 Decode(#[from] cbor::DecodeError),
27}
28
29#[derive(Clone, Default, Debug)]
31pub struct SubmitTxOpts {
32 pub runtime_id: Option<Namespace>,
34 pub wait: bool,
36 pub prove: bool,
38}
39
40#[derive(Clone, Default, Debug)]
42pub struct TxResult {
43 pub output: Vec<u8>,
45 pub round: u64,
47 pub batch_order: u32,
49 pub proof: Option<sync::Proof>,
51}
52
53#[derive(Clone, Default, Debug)]
55pub struct RegisterNotifyOpts {
56 pub runtime_block: bool,
58 pub runtime_event: Vec<Vec<u8>>,
60}
61
62#[async_trait]
64pub trait Host: Send + Sync {
65 async fn identity(&self) -> Result<PublicKey, Error>;
67
68 async fn submit_tx(&self, data: Vec<u8>, opts: SubmitTxOpts)
70 -> Result<Option<TxResult>, Error>;
71
72 async fn register_notify(&self, opts: RegisterNotifyOpts) -> Result<(), Error>;
74
75 fn bundle_manager(&self) -> &dyn bundle_manager::BundleManager;
77
78 fn volume_manager(&self) -> &dyn volume_manager::VolumeManager;
80}
81
82#[async_trait]
83impl Host for Protocol {
84 async fn identity(&self) -> Result<PublicKey, Error> {
85 match self.call_host_async(Body::HostIdentityRequest {}).await? {
86 Body::HostIdentityResponse { node_id } => Ok(node_id),
87 _ => Err(Error::BadResponse),
88 }
89 }
90
91 async fn submit_tx(
92 &self,
93 data: Vec<u8>,
94 opts: SubmitTxOpts,
95 ) -> Result<Option<TxResult>, Error> {
96 match self
97 .call_host_async(Body::HostSubmitTxRequest {
98 runtime_id: opts.runtime_id.unwrap_or_else(|| self.get_runtime_id()),
99 data,
100 wait: opts.wait,
101 prove: opts.prove,
102 })
103 .await?
104 {
105 Body::HostSubmitTxResponse {
106 output,
107 round,
108 batch_order,
109 proof,
110 } => {
111 if opts.wait {
112 Ok(Some(TxResult {
113 output,
114 round,
115 batch_order,
116 proof,
117 }))
118 } else {
119 Ok(None)
121 }
122 }
123 _ => Err(Error::BadResponse),
124 }
125 }
126
127 async fn register_notify(&self, opts: RegisterNotifyOpts) -> Result<(), Error> {
128 match self
129 .call_host_async(Body::HostRegisterNotifyRequest {
130 runtime_block: opts.runtime_block,
131 runtime_event: match opts.runtime_event {
132 tags if tags.is_empty() => None,
133 tags => Some(types::RegisterNotifyRuntimeEvent { tags }),
134 },
135 })
136 .await?
137 {
138 Body::Empty {} => Ok(()),
139 _ => Err(Error::BadResponse),
140 }
141 }
142
143 fn bundle_manager(&self) -> &dyn bundle_manager::BundleManager {
144 self
145 }
146
147 fn volume_manager(&self) -> &dyn volume_manager::VolumeManager {
148 self
149 }
150}
151
152pub(super) async fn host_rpc_call<Rq: cbor::Encode, Rs: cbor::Decode>(
154 protocol: &Protocol,
155 endpoint: &str,
156 method: &str,
157 args: Rq,
158) -> Result<Rs, Error> {
159 match protocol
160 .call_host_async(Body::HostRPCCallRequest {
161 endpoint: endpoint.to_string(),
162 request_id: 0,
163 request: cbor::to_vec(enclave_rpc::types::Request {
164 method: method.to_string(),
165 args: cbor::to_value(args),
166 }),
167 kind: enclave_rpc::types::Kind::LocalQuery,
168 nodes: vec![],
169 })
170 .await?
171 {
172 Body::HostRPCCallResponse { response, .. } => Ok(cbor::from_slice(&response)?),
173 _ => Err(Error::BadResponse),
174 }
175}