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