oasis_core_runtime/host/
mod.rs

1//! Host interface.
2use 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 attestation;
14pub mod bundle_manager;
15pub mod log_manager;
16pub mod volume_manager;
17
18/// Errors.
19#[derive(Error, Debug)]
20pub enum Error {
21    #[error("bad response from host")]
22    BadResponse,
23
24    #[error("{0}")]
25    Host(#[from] types::Error),
26
27    #[error("{0}")]
28    Decode(#[from] cbor::DecodeError),
29}
30
31/// Transaction submission options.
32#[derive(Clone, Default, Debug)]
33pub struct SubmitTxOpts {
34    /// Target runtime identifier. If not specified, own runtime identifier is used.
35    pub runtime_id: Option<Namespace>,
36    /// Whether the call should wait until the transaction is included in a block.
37    pub wait: bool,
38    /// Whether the response should include a proof of transaction being included in a block.
39    pub prove: bool,
40}
41
42/// Transaction submission result.
43#[derive(Clone, Default, Debug)]
44pub struct TxResult {
45    /// Transaction output.
46    pub output: Vec<u8>,
47    /// Round in which the transaction was executed.
48    pub round: u64,
49    /// Order of the transaction in the execution batch.
50    pub batch_order: u32,
51    /// Optional inclusion proof.
52    pub proof: Option<sync::Proof>,
53}
54
55/// Interface to the (untrusted) host node.
56#[async_trait]
57pub trait Host: Send + Sync {
58    /// Returns the identity of the host node.
59    async fn identity(&self) -> Result<PublicKey, Error>;
60
61    /// Submit a transaction.
62    async fn submit_tx(&self, data: Vec<u8>, opts: SubmitTxOpts)
63        -> Result<Option<TxResult>, Error>;
64
65    /// Bundle manager interface.
66    fn bundle_manager(&self) -> &dyn bundle_manager::BundleManager;
67
68    /// Volume manager interface.
69    fn volume_manager(&self) -> &dyn volume_manager::VolumeManager;
70
71    /// Log manager interface.
72    fn log_manager(&self) -> &dyn log_manager::LogManager;
73
74    /// Attestation interface.
75    fn attestation(&self) -> &dyn attestation::Attestation;
76}
77
78#[async_trait]
79impl Host for Protocol {
80    async fn identity(&self) -> Result<PublicKey, Error> {
81        match self.call_host_async(Body::HostIdentityRequest {}).await? {
82            Body::HostIdentityResponse { node_id } => Ok(node_id),
83            _ => Err(Error::BadResponse),
84        }
85    }
86
87    async fn submit_tx(
88        &self,
89        data: Vec<u8>,
90        opts: SubmitTxOpts,
91    ) -> Result<Option<TxResult>, Error> {
92        match self
93            .call_host_async(Body::HostSubmitTxRequest {
94                runtime_id: opts.runtime_id.unwrap_or_else(|| self.get_runtime_id()),
95                data,
96                wait: opts.wait,
97                prove: opts.prove,
98            })
99            .await?
100        {
101            Body::HostSubmitTxResponse {
102                output,
103                round,
104                batch_order,
105                proof,
106            } => {
107                if opts.wait {
108                    Ok(Some(TxResult {
109                        output,
110                        round,
111                        batch_order,
112                        proof,
113                    }))
114                } else {
115                    // If we didn't wait for inclusion then there is no result.
116                    Ok(None)
117                }
118            }
119            _ => Err(Error::BadResponse),
120        }
121    }
122
123    fn bundle_manager(&self) -> &dyn bundle_manager::BundleManager {
124        self
125    }
126
127    fn volume_manager(&self) -> &dyn volume_manager::VolumeManager {
128        self
129    }
130
131    fn log_manager(&self) -> &dyn log_manager::LogManager {
132        self
133    }
134
135    fn attestation(&self) -> &dyn attestation::Attestation {
136        self
137    }
138}
139
140/// Wrapper to call the host via local RPC.
141pub(super) async fn host_rpc_call<Rq: cbor::Encode, Rs: cbor::Decode>(
142    protocol: &Protocol,
143    endpoint: &str,
144    method: &str,
145    args: Rq,
146) -> Result<Rs, Error> {
147    match protocol
148        .call_host_async(Body::HostRPCCallRequest {
149            endpoint: endpoint.to_string(),
150            request_id: 0,
151            request: cbor::to_vec(enclave_rpc::types::Request {
152                method: method.to_string(),
153                args: cbor::to_value(args),
154            }),
155            kind: enclave_rpc::types::Kind::LocalQuery,
156            nodes: vec![],
157        })
158        .await?
159    {
160        Body::HostRPCCallResponse { response, .. } => Ok(cbor::from_slice(&response)?),
161        _ => Err(Error::BadResponse),
162    }
163}