1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Host interface.
use async_trait::async_trait;
use thiserror::Error;

use crate::{
    common::{crypto::signature::PublicKey, namespace::Namespace},
    protocol::Protocol,
    storage::mkvs::sync,
    types::{self, Body},
};

/// Errors.
#[derive(Error, Debug)]
pub enum Error {
    #[error("bad response from host")]
    BadResponse,
    #[error("{0}")]
    Other(#[from] types::Error),
}

/// Transaction submission options.
#[derive(Clone, Default, Debug)]
pub struct SubmitTxOpts {
    /// Target runtime identifier. If not specified, own runtime identifier is used.
    pub runtime_id: Option<Namespace>,
    /// Whether the call should wait until the transaction is included in a block.
    pub wait: bool,
    /// Whether the response should include a proof of transaction being included in a block.
    pub prove: bool,
}

/// Transaction submission result.
#[derive(Clone, Default, Debug)]
pub struct TxResult {
    /// Transaction output.
    pub output: Vec<u8>,
    /// Round in which the transaction was executed.
    pub round: u64,
    /// Order of the transaction in the execution batch.
    pub batch_order: u32,
    /// Optional inclusion proof.
    pub proof: Option<sync::Proof>,
}

/// Notification registration options.
#[derive(Clone, Default, Debug)]
pub struct RegisterNotifyOpts {
    /// Subscribe to runtime block notifications.
    pub runtime_block: bool,
    /// Subscribe to runtime event notifications.
    pub runtime_event: Vec<Vec<u8>>,
}

/// Interface to the (untrusted) host node.
#[async_trait]
pub trait Host: Send + Sync {
    /// Returns the identity of the host node.
    async fn identity(&self) -> Result<PublicKey, Error>;

    /// Submit a transaction.
    async fn submit_tx(&self, data: Vec<u8>, opts: SubmitTxOpts)
        -> Result<Option<TxResult>, Error>;

    /// Register for receiving notifications.
    async fn register_notify(&self, opts: RegisterNotifyOpts) -> Result<(), Error>;
}

#[async_trait]
impl Host for Protocol {
    async fn identity(&self) -> Result<PublicKey, Error> {
        match self.call_host_async(Body::HostIdentityRequest {}).await? {
            Body::HostIdentityResponse { node_id } => Ok(node_id),
            _ => Err(Error::BadResponse),
        }
    }

    async fn submit_tx(
        &self,
        data: Vec<u8>,
        opts: SubmitTxOpts,
    ) -> Result<Option<TxResult>, Error> {
        match self
            .call_host_async(Body::HostSubmitTxRequest {
                runtime_id: opts.runtime_id.unwrap_or_else(|| self.get_runtime_id()),
                data,
                wait: opts.wait,
                prove: opts.prove,
            })
            .await?
        {
            Body::HostSubmitTxResponse {
                output,
                round,
                batch_order,
                proof,
            } => {
                if opts.wait {
                    Ok(Some(TxResult {
                        output,
                        round,
                        batch_order,
                        proof,
                    }))
                } else {
                    // If we didn't wait for inclusion then there is no result.
                    Ok(None)
                }
            }
            _ => Err(Error::BadResponse),
        }
    }

    async fn register_notify(&self, opts: RegisterNotifyOpts) -> Result<(), Error> {
        match self
            .call_host_async(Body::HostRegisterNotifyRequest {
                runtime_block: opts.runtime_block,
                runtime_event: match opts.runtime_event {
                    tags if tags.is_empty() => None,
                    tags => Some(types::RegisterNotifyRuntimeEvent { tags }),
                },
            })
            .await?
        {
            Body::Empty {} => Ok(()),
            _ => Err(Error::BadResponse),
        }
    }
}