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
129
130
131
132
133
use std::sync::Arc;

use anyhow::{anyhow, Error as AnyError};
use async_trait::async_trait;

use crate::{common::crypto::signature, types::Body, Protocol};

use super::types;

// Enclave's response.
pub struct EnclaveResponse {
    // Actual response data.
    pub data: Vec<u8>,
    // The public key of the node that generated the response.
    pub node: signature::PublicKey,
}

/// An EnclaveRPC transport.
#[async_trait]
pub trait Transport: Send + Sync {
    async fn write_noise_session(
        &self,
        request_id: u64,
        session_id: types::SessionID,
        data: Vec<u8>,
        untrusted_plaintext: String,
        nodes: Vec<signature::PublicKey>,
    ) -> Result<EnclaveResponse, AnyError> {
        let frame = types::Frame {
            session: session_id,
            untrusted_plaintext,
            payload: data,
        };

        self.write_message_impl(
            request_id,
            cbor::to_vec(frame),
            types::Kind::NoiseSession,
            nodes,
        )
        .await
    }

    async fn write_insecure_query(
        &self,
        request_id: u64,
        data: Vec<u8>,
        nodes: Vec<signature::PublicKey>,
    ) -> Result<EnclaveResponse, AnyError> {
        self.write_message_impl(request_id, data, types::Kind::InsecureQuery, nodes)
            .await
    }

    async fn write_message_impl(
        &self,
        request_id: u64,
        data: Vec<u8>,
        kind: types::Kind,
        nodes: Vec<signature::PublicKey>,
    ) -> Result<EnclaveResponse, AnyError>;

    async fn submit_peer_feedback(
        &self,
        request_id: u64,
        feedback: types::PeerFeedback,
    ) -> Result<(), AnyError>;
}

/// A transport implementation which can be used from inside the runtime and uses the Runtime Host
/// Protocol to transport EnclaveRPC frames.
pub struct RuntimeTransport {
    pub protocol: Arc<Protocol>,
    pub endpoint: String,
}

impl RuntimeTransport {
    pub fn new(protocol: Arc<Protocol>, endpoint: &str) -> Self {
        Self {
            protocol,
            endpoint: endpoint.to_string(),
        }
    }
}

#[async_trait]
impl Transport for RuntimeTransport {
    async fn write_message_impl(
        &self,
        request_id: u64,
        data: Vec<u8>,
        kind: types::Kind,
        nodes: Vec<signature::PublicKey>,
    ) -> Result<EnclaveResponse, AnyError> {
        let rsp = self
            .protocol
            .call_host_async(Body::HostRPCCallRequest {
                endpoint: self.endpoint.clone(),
                request_id,
                request: data,
                kind,
                nodes,
            })
            .await?;

        match rsp {
            Body::HostRPCCallResponse { response, node } => Ok(EnclaveResponse {
                data: response,
                node,
            }),
            _ => Err(anyhow!("bad response type")),
        }
    }

    async fn submit_peer_feedback(
        &self,
        request_id: u64,
        peer_feedback: types::PeerFeedback,
    ) -> Result<(), AnyError> {
        let rsp = self
            .protocol
            .call_host_async(Body::HostSubmitPeerFeedbackRequest {
                endpoint: self.endpoint.clone(),
                request_id,
                peer_feedback,
            })
            .await?;

        match rsp {
            Body::HostSubmitPeerFeedbackResponse {} => Ok(()),
            _ => Err(anyhow!("bad response type")),
        }
    }
}