oasis_core_runtime/consensus/
verifier.rs

1//! Trait for consensus layer verification.
2use std::sync::Arc;
3
4use anyhow::anyhow;
5use async_trait::async_trait;
6use thiserror::Error;
7
8use super::{
9    beacon::EpochTime,
10    roothash::Header,
11    state::{registry::ImmutableState as RegistryState, ConsensusState},
12    Event, LightBlock,
13};
14use crate::{
15    common::{crypto::signature::PublicKey, namespace::Namespace, version::Version},
16    identity::Identity,
17    types::{self, EventKind},
18};
19
20#[derive(Debug, Error)]
21pub enum Error {
22    #[error("builder: {0}")]
23    Builder(#[source] anyhow::Error),
24
25    #[error("verification: {0}")]
26    VerificationFailed(#[source] anyhow::Error),
27
28    #[error("trusted state loading failed")]
29    TrustedStateLoadingFailed,
30
31    #[error("consensus chain context transition failed: {0}")]
32    ChainContextTransitionFailed(#[source] anyhow::Error),
33
34    #[error("freshness verification: {0}")]
35    FreshnessVerificationFailed(#[source] anyhow::Error),
36
37    #[error("transaction verification: {0}")]
38    TransactionVerificationFailed(#[source] anyhow::Error),
39
40    #[error("state root: {0}")]
41    StateRoot(#[source] anyhow::Error),
42
43    #[error("internal consensus verifier error")]
44    Internal,
45}
46
47impl Error {
48    fn code(&self) -> u32 {
49        match self {
50            Error::Builder(_) => 1,
51            Error::VerificationFailed(_) => 2,
52            Error::TrustedStateLoadingFailed => 3,
53            Error::ChainContextTransitionFailed(_) => 4,
54            Error::FreshnessVerificationFailed(_) => 5,
55            Error::TransactionVerificationFailed(_) => 6,
56            Error::StateRoot(_) => 7,
57            Error::Internal => 8,
58        }
59    }
60}
61
62impl From<Error> for types::Error {
63    fn from(e: Error) -> Self {
64        Self {
65            module: "verifier".to_string(),
66            code: e.code(),
67            message: e.to_string(),
68        }
69    }
70}
71
72/// Verifier is the consensus layer state verifier trait.
73#[async_trait]
74pub trait Verifier: Send + Sync {
75    /// Synchronize the verifier state up to including the passed consensus height.
76    async fn sync(&self, height: u64) -> Result<(), Error>;
77
78    /// Verify that the given runtime header is valid at the given consensus layer block and return
79    /// the consensus layer state accessor for that block.
80    ///
81    /// This also verifies that the state is fresh.
82    async fn verify(
83        &self,
84        consensus_block: LightBlock,
85        runtime_header: Header,
86        epoch: EpochTime,
87    ) -> Result<ConsensusState, Error>;
88
89    /// Verify that the given runtime header is valid at the given consensus layer block and return
90    /// the consensus layer state accessor for that block.
91    ///
92    /// This is a relaxed version of the `verify` function that should be used for verifying state
93    /// in queries.
94    async fn verify_for_query(
95        &self,
96        consensus_block: LightBlock,
97        runtime_header: Header,
98        epoch: EpochTime,
99    ) -> Result<ConsensusState, Error>;
100
101    /// Return the consensus layer state accessor for the given consensus layer block WITHOUT
102    /// performing any verification. This method should only be used for operations that do not
103    /// require integrity guarantees.
104    async fn unverified_state(&self, consensus_block: LightBlock) -> Result<ConsensusState, Error>;
105
106    /// Return the latest verified consensus layer state.
107    ///
108    /// # Warning
109    ///
110    /// The state is not verified to be fresh. Use `verify_state_freshness` to perform this
111    /// verification manually if needed.
112    async fn latest_state(&self) -> Result<ConsensusState, Error>;
113
114    /// Return the verified consensus layer state for a given height.
115    ///
116    /// # Warning
117    ///
118    /// The state is not verified to be fresh. Use `verify_state_freshness` to perform this
119    /// verification manually if needed.
120    async fn state_at(&self, height: u64) -> Result<ConsensusState, Error>;
121
122    /// Return the consensus layer events at the given height.
123    ///
124    /// # Warning
125    ///
126    /// Event integrity is currently not verified and it thus relies on replicated computation even
127    /// when using a TEE-enabled runtime.
128    async fn events_at(&self, height: u64, kind: EventKind) -> Result<Vec<Event>, Error>;
129
130    /// Return the latest known consensus layer height.
131    async fn latest_height(&self) -> Result<u64, Error>;
132}
133
134#[async_trait]
135impl<T: ?Sized + Verifier> Verifier for Arc<T> {
136    async fn sync(&self, height: u64) -> Result<(), Error> {
137        Verifier::sync(&**self, height).await
138    }
139
140    async fn verify(
141        &self,
142        consensus_block: LightBlock,
143        runtime_header: Header,
144        epoch: EpochTime,
145    ) -> Result<ConsensusState, Error> {
146        Verifier::verify(&**self, consensus_block, runtime_header, epoch).await
147    }
148
149    async fn verify_for_query(
150        &self,
151        consensus_block: LightBlock,
152        runtime_header: Header,
153        epoch: EpochTime,
154    ) -> Result<ConsensusState, Error> {
155        Verifier::verify_for_query(&**self, consensus_block, runtime_header, epoch).await
156    }
157
158    async fn unverified_state(&self, consensus_block: LightBlock) -> Result<ConsensusState, Error> {
159        Verifier::unverified_state(&**self, consensus_block).await
160    }
161
162    async fn latest_state(&self) -> Result<ConsensusState, Error> {
163        Verifier::latest_state(&**self).await
164    }
165
166    async fn state_at(&self, height: u64) -> Result<ConsensusState, Error> {
167        Verifier::state_at(&**self, height).await
168    }
169
170    async fn events_at(&self, height: u64, kind: EventKind) -> Result<Vec<Event>, Error> {
171        Verifier::events_at(&**self, height, kind).await
172    }
173
174    async fn latest_height(&self) -> Result<u64, Error> {
175        Verifier::latest_height(&**self).await
176    }
177}
178
179/// Consensus layer trust root.
180#[derive(Debug, Clone, Default, PartialEq, Eq, cbor::Encode, cbor::Decode)]
181pub struct TrustRoot {
182    /// Known trusted height.
183    pub height: u64,
184    /// Known hex-encoded trusted consensus layer header hash.
185    pub hash: String,
186    /// Known runtime identifier.
187    pub runtime_id: Namespace,
188    /// Known consensus chain context.
189    pub chain_context: String,
190}
191
192/// Verify consensus layer state freshness based on our internal state.
193pub fn verify_state_freshness(
194    state: &ConsensusState,
195    identity: &Identity,
196    runtime_id: &Namespace,
197    version: &Version,
198    host_node_id: &PublicKey,
199) -> Result<(), Error> {
200    let registry_state = RegistryState::new(&state);
201
202    let node = registry_state.node(host_node_id).map_err(|err| {
203        Error::VerificationFailed(anyhow!(
204            "failed to retrieve node from the registry: {}",
205            err
206        ))
207    })?;
208    let node = node.ok_or_else(|| {
209        Error::VerificationFailed(anyhow!(
210            "own node ID '{}' not found in registry state",
211            host_node_id,
212        ))
213    })?;
214
215    if !node.has_tee(identity, runtime_id, version) {
216        return Err(Error::VerificationFailed(anyhow!(
217            "own identity not found in registry state"
218        )));
219    }
220
221    Ok(())
222}