oasis_core_runtime/consensus/tendermint/verifier/
noop.rs1use std::sync::{Arc, Mutex};
2
3use anyhow::anyhow;
4use async_trait::async_trait;
5use slog::info;
6
7use crate::{
8 common::{logger::get_logger, namespace::Namespace},
9 consensus::{
10 beacon::EpochTime,
11 roothash::Header,
12 state::ConsensusState,
13 tendermint::decode_light_block,
14 transaction::Transaction,
15 verifier::{self, Error},
16 BlockMetadata, Event, LightBlock, HEIGHT_LATEST, METHOD_META,
17 },
18 protocol::Protocol,
19 storage::mkvs::{Root, RootType},
20 types::{Body, EventKind, HostFetchConsensusEventsRequest, HostFetchConsensusEventsResponse},
21};
22
23struct Inner {
24 latest_height: Option<u64>,
25}
26
27pub struct NopVerifier {
29 protocol: Arc<Protocol>,
30 inner: Arc<Mutex<Inner>>,
31}
32
33impl NopVerifier {
34 pub fn new(protocol: Arc<Protocol>) -> Self {
36 Self {
37 protocol,
38 inner: Arc::new(Mutex::new(Inner {
39 latest_height: None,
40 })),
41 }
42 }
43
44 pub fn start(&self) {
46 let logger = get_logger("consensus/cometbft/verifier");
47 info!(logger, "Starting consensus noop verifier");
48 }
49
50 async fn fetch_light_block(&self, height: u64) -> Result<LightBlock, Error> {
51 let result = self
52 .protocol
53 .call_host_async(Body::HostFetchConsensusBlockRequest { height })
54 .await
55 .map_err(|err| Error::VerificationFailed(err.into()))?;
56
57 match result {
58 Body::HostFetchConsensusBlockResponse { block } => Ok(block),
59 _ => Err(Error::VerificationFailed(anyhow!("bad response from host"))),
60 }
61 }
62}
63
64#[allow(clippy::double_must_use)]
65#[async_trait]
66impl verifier::Verifier for NopVerifier {
67 async fn sync(&self, height: u64) -> Result<(), Error> {
68 let height = self.fetch_light_block(height).await?.height; let mut inner = self.inner.lock().unwrap();
71 inner.latest_height = Some(height);
72
73 Ok(())
74 }
75
76 async fn verify(
77 &self,
78 consensus_block: LightBlock,
79 _runtime_header: Header,
80 _epoch: EpochTime,
81 ) -> Result<ConsensusState, Error> {
82 self.unverified_state(consensus_block).await
83 }
84
85 async fn verify_for_query(
86 &self,
87 consensus_block: LightBlock,
88 _runtime_header: Header,
89 _epoch: EpochTime,
90 ) -> Result<ConsensusState, Error> {
91 self.unverified_state(consensus_block).await
92 }
93
94 async fn unverified_state(&self, consensus_block: LightBlock) -> Result<ConsensusState, Error> {
95 let untrusted_block =
96 decode_light_block(consensus_block).map_err(Error::VerificationFailed)?;
97 let state_root = untrusted_block.get_state_root();
99
100 let mut inner = self.inner.lock().unwrap();
101 if state_root.version + 1 > inner.latest_height.unwrap_or_default() {
102 inner.latest_height = Some(state_root.version + 1);
103 }
104
105 Ok(ConsensusState::from_protocol(
106 self.protocol.clone(),
107 state_root.version + 1,
108 state_root,
109 ))
110 }
111
112 async fn latest_state(&self) -> Result<ConsensusState, Error> {
113 let height = self.latest_height().await?;
114
115 let result = self
117 .protocol
118 .call_host_async(Body::HostFetchBlockMetadataTxRequest { height })
119 .await
120 .map_err(|err| Error::StateRoot(err.into()))?;
121
122 let signed_tx = match result {
124 Body::HostFetchBlockMetadataTxResponse { signed_tx, .. } => signed_tx,
125 _ => return Err(Error::StateRoot(anyhow!("bad response from host"))),
126 };
127
128 let tx: Transaction = cbor::from_slice(signed_tx.blob.as_slice()).map_err(|err| {
129 Error::TransactionVerificationFailed(anyhow!("failed to decode transaction: {}", err))
130 })?;
131
132 if tx.method != METHOD_META {
133 return Err(Error::StateRoot(anyhow!("invalid method name")));
134 }
135
136 let meta: BlockMetadata = cbor::from_value(tx.body).map_err(|err| {
137 Error::StateRoot(anyhow!(
138 "failed to decode block metadata transaction: {}",
139 err
140 ))
141 })?;
142
143 let state_root = Root {
144 namespace: Namespace::default(),
145 version: height,
146 root_type: RootType::State,
147 hash: meta.state_root,
148 };
149
150 Ok(ConsensusState::from_protocol(
151 self.protocol.clone(),
152 state_root.version,
153 state_root,
154 ))
155 }
156
157 async fn state_at(&self, height: u64) -> Result<ConsensusState, Error> {
158 let block = self.fetch_light_block(height).await?;
159 self.unverified_state(block).await
160 }
161
162 async fn events_at(&self, height: u64, kind: EventKind) -> Result<Vec<Event>, Error> {
163 let result = self
164 .protocol
165 .call_host_async(Body::HostFetchConsensusEventsRequest(
166 HostFetchConsensusEventsRequest { height, kind },
167 ))
168 .await
169 .map_err(|err| Error::VerificationFailed(err.into()))?;
170
171 match result {
172 Body::HostFetchConsensusEventsResponse(HostFetchConsensusEventsResponse { events }) => {
173 Ok(events)
174 }
175 _ => Err(Error::VerificationFailed(anyhow!("bad response from host"))),
176 }
177 }
178
179 async fn latest_height(&self) -> Result<u64, Error> {
180 {
181 let inner = self.inner.lock().unwrap();
182 if let Some(latest_height) = inner.latest_height {
183 return Ok(latest_height);
184 }
185 }
186
187 let latest_height = self.fetch_light_block(HEIGHT_LATEST).await?.height;
188 self.sync(latest_height).await?;
189 Ok(latest_height)
190 }
191}