oasis_core_runtime/consensus/tendermint/verifier/
io.rs1use std::sync::Arc;
2
3use tendermint_light_client::{
4 components::{
5 self,
6 io::{AtHeight, IoError},
7 },
8 types::{LightBlock as TMLightBlock, PeerId},
9};
10use tendermint_rpc::error::Error as RpcError;
11
12use crate::{
13 consensus::{
14 tendermint::{decode_light_block, LightBlockMeta},
15 transaction::SignedTransactionWithProof,
16 HEIGHT_LATEST,
17 },
18 protocol::Protocol,
19 types::Body,
20};
21
22use super::types::Nonce;
23
24pub struct Io {
25 protocol: Arc<Protocol>,
26}
27
28impl Io {
29 pub fn new(protocol: &Arc<Protocol>) -> Self {
30 Self {
31 protocol: protocol.clone(),
32 }
33 }
34
35 fn fetch_light_block(&self, height: u64) -> Result<LightBlockMeta, IoError> {
36 let result = self
37 .protocol
38 .call_host(Body::HostFetchConsensusBlockRequest { height })
39 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
40
41 let block = match result {
43 Body::HostFetchConsensusBlockResponse { block } => block,
44 _ => return Err(IoError::rpc(RpcError::server("bad response".to_string()))),
45 };
46
47 let block = decode_light_block(block)
49 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
50
51 Ok(block)
52 }
53
54 pub fn fetch_genesis_height(&self) -> Result<u64, IoError> {
55 let result = self
56 .protocol
57 .call_host(Body::HostFetchGenesisHeightRequest {})
58 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
59
60 let height = match result {
62 Body::HostFetchGenesisHeightResponse { height } => height,
63 _ => return Err(IoError::rpc(RpcError::server("bad response".to_string()))),
64 };
65
66 Ok(height)
67 }
68
69 pub fn fetch_freshness_proof(
70 &self,
71 nonce: &Nonce,
72 ) -> Result<SignedTransactionWithProof, IoError> {
73 let result = self
74 .protocol
75 .call_host(Body::HostProveFreshnessRequest {
76 blob: nonce.to_vec(),
77 })
78 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
79
80 let (signed_tx, proof) = match result {
82 Body::HostProveFreshnessResponse { signed_tx, proof } => (signed_tx, proof),
83 _ => return Err(IoError::rpc(RpcError::server("bad response".to_string()))),
84 };
85
86 Ok(SignedTransactionWithProof { signed_tx, proof })
87 }
88
89 pub fn fetch_block_metadata(&self, height: u64) -> Result<SignedTransactionWithProof, IoError> {
90 let result = self
91 .protocol
92 .call_host(Body::HostFetchBlockMetadataTxRequest { height })
93 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
94
95 let (signed_tx, proof) = match result {
97 Body::HostFetchBlockMetadataTxResponse { signed_tx, proof } => (signed_tx, proof),
98 _ => return Err(IoError::rpc(RpcError::server("bad response".to_string()))),
99 };
100
101 Ok(SignedTransactionWithProof { signed_tx, proof })
102 }
103}
104
105impl components::io::Io for Io {
106 fn fetch_light_block(&self, height: AtHeight) -> Result<TMLightBlock, IoError> {
107 let height = match height {
108 AtHeight::At(height) => height.into(),
109 AtHeight::Highest => HEIGHT_LATEST,
110 };
111
112 let block = Io::fetch_light_block(self, height)?;
114 let height: u64 = block
115 .signed_header
116 .as_ref()
117 .ok_or_else(|| IoError::rpc(RpcError::server("missing signed header".to_string())))?
118 .header()
119 .height
120 .into();
121 let next_block = Io::fetch_light_block(self, height + 1)?;
124
125 Ok(TMLightBlock {
126 signed_header: block.signed_header.unwrap(), validators: block.validators,
128 next_validators: next_block.validators,
129 provider: PeerId::new([0; 20]),
130 })
131 }
132}