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#[async_trait]
65impl verifier::Verifier for NopVerifier {
66 async fn sync(&self, height: u64) -> Result<(), Error> {
67 let height = self.fetch_light_block(height).await?.height; let mut inner = self.inner.lock().unwrap();
70 inner.latest_height = Some(height);
71
72 Ok(())
73 }
74
75 async fn verify(
76 &self,
77 consensus_block: LightBlock,
78 _runtime_header: Header,
79 _epoch: EpochTime,
80 ) -> Result<ConsensusState, Error> {
81 self.unverified_state(consensus_block).await
82 }
83
84 async fn verify_for_query(
85 &self,
86 consensus_block: LightBlock,
87 _runtime_header: Header,
88 _epoch: EpochTime,
89 ) -> Result<ConsensusState, Error> {
90 self.unverified_state(consensus_block).await
91 }
92
93 async fn unverified_state(&self, consensus_block: LightBlock) -> Result<ConsensusState, Error> {
94 let untrusted_block =
95 decode_light_block(consensus_block).map_err(Error::VerificationFailed)?;
96 let state_root = untrusted_block.get_state_root();
98
99 let mut inner = self.inner.lock().unwrap();
100 if state_root.version + 1 > inner.latest_height.unwrap_or_default() {
101 inner.latest_height = Some(state_root.version + 1);
102 }
103
104 Ok(ConsensusState::from_protocol(
105 self.protocol.clone(),
106 state_root.version + 1,
107 state_root,
108 ))
109 }
110
111 async fn latest_state(&self) -> Result<ConsensusState, Error> {
112 let height = self.latest_height().await?;
113
114 let result = self
116 .protocol
117 .call_host_async(Body::HostFetchBlockMetadataTxRequest { height })
118 .await
119 .map_err(|err| Error::StateRoot(err.into()))?;
120
121 let signed_tx = match result {
123 Body::HostFetchBlockMetadataTxResponse { signed_tx, .. } => signed_tx,
124 _ => return Err(Error::StateRoot(anyhow!("bad response from host"))),
125 };
126
127 let tx: Transaction = cbor::from_slice(signed_tx.blob.as_slice()).map_err(|err| {
128 Error::TransactionVerificationFailed(anyhow!("failed to decode transaction: {}", err))
129 })?;
130
131 if tx.method != METHOD_META {
132 return Err(Error::StateRoot(anyhow!("invalid method name")));
133 }
134
135 let meta: BlockMetadata = cbor::from_value(tx.body).map_err(|err| {
136 Error::StateRoot(anyhow!(
137 "failed to decode block metadata transaction: {}",
138 err
139 ))
140 })?;
141
142 let state_root = Root {
143 namespace: Namespace::default(),
144 version: height,
145 root_type: RootType::State,
146 hash: meta.state_root,
147 };
148
149 Ok(ConsensusState::from_protocol(
150 self.protocol.clone(),
151 state_root.version,
152 state_root,
153 ))
154 }
155
156 async fn state_at(&self, height: u64) -> Result<ConsensusState, Error> {
157 let block = self.fetch_light_block(height).await?;
158 self.unverified_state(block).await
159 }
160
161 async fn events_at(&self, height: u64, kind: EventKind) -> Result<Vec<Event>, Error> {
162 let result = self
163 .protocol
164 .call_host_async(Body::HostFetchConsensusEventsRequest(
165 HostFetchConsensusEventsRequest { height, kind },
166 ))
167 .await
168 .map_err(|err| Error::VerificationFailed(err.into()))?;
169
170 match result {
171 Body::HostFetchConsensusEventsResponse(HostFetchConsensusEventsResponse { events }) => {
172 Ok(events)
173 }
174 _ => Err(Error::VerificationFailed(anyhow!("bad response from host"))),
175 }
176 }
177
178 async fn latest_height(&self) -> Result<u64, Error> {
179 {
180 let inner = self.inner.lock().unwrap();
181 if let Some(latest_height) = inner.latest_height {
182 return Ok(latest_height);
183 }
184 }
185
186 let latest_height = self.fetch_light_block(HEIGHT_LATEST).await?.height;
187 self.sync(latest_height).await?;
188 Ok(latest_height)
189 }
190}