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, ValidatorSet as TMValidatorSet},
9};
10use tendermint_rpc::error::Error as RpcError;
11
12use crate::{
13 consensus::{
14 tendermint::{decode_light_block, decode_validators, 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 fn fetch_validators(&self, height: u64) -> Result<TMValidatorSet, IoError> {
55 let result = self
56 .protocol
57 .call_host(Body::HostFetchConsensusValidatorsRequest { height })
58 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
59
60 let validators = match result {
62 Body::HostFetchConsensusValidatorsResponse { validators } => validators,
63 _ => return Err(IoError::rpc(RpcError::server("bad response".to_string()))),
64 };
65
66 let validators = decode_validators(validators)
68 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
69
70 Ok(validators)
71 }
72
73 pub fn fetch_genesis_height(&self) -> Result<u64, IoError> {
74 let result = self
75 .protocol
76 .call_host(Body::HostFetchGenesisHeightRequest {})
77 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
78
79 let height = match result {
81 Body::HostFetchGenesisHeightResponse { height } => height,
82 _ => return Err(IoError::rpc(RpcError::server("bad response".to_string()))),
83 };
84
85 Ok(height)
86 }
87
88 pub fn fetch_freshness_proof(
89 &self,
90 nonce: &Nonce,
91 ) -> Result<SignedTransactionWithProof, IoError> {
92 let result = self
93 .protocol
94 .call_host(Body::HostProveFreshnessRequest {
95 blob: nonce.to_vec(),
96 })
97 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
98
99 let (signed_tx, proof) = match result {
101 Body::HostProveFreshnessResponse { signed_tx, proof } => (signed_tx, proof),
102 _ => return Err(IoError::rpc(RpcError::server("bad response".to_string()))),
103 };
104
105 Ok(SignedTransactionWithProof { signed_tx, proof })
106 }
107
108 pub fn fetch_block_metadata(&self, height: u64) -> Result<SignedTransactionWithProof, IoError> {
109 let result = self
110 .protocol
111 .call_host(Body::HostFetchBlockMetadataTxRequest { height })
112 .map_err(|err| IoError::rpc(RpcError::server(err.to_string())))?;
113
114 let (signed_tx, proof) = match result {
116 Body::HostFetchBlockMetadataTxResponse { signed_tx, proof } => (signed_tx, proof),
117 _ => return Err(IoError::rpc(RpcError::server("bad response".to_string()))),
118 };
119
120 Ok(SignedTransactionWithProof { signed_tx, proof })
121 }
122}
123
124impl components::io::Io for Io {
125 fn fetch_light_block(&self, height: AtHeight) -> Result<TMLightBlock, IoError> {
126 let height = match height {
127 AtHeight::At(height) => height.into(),
128 AtHeight::Highest => HEIGHT_LATEST,
129 };
130
131 let block = Io::fetch_light_block(self, height)?;
132 let height: u64 = block
133 .signed_header
134 .as_ref()
135 .ok_or_else(|| IoError::rpc(RpcError::server("missing signed header".to_string())))?
136 .header()
137 .height
138 .into();
139
140 let next_validators = Io::fetch_validators(self, height + 1)?;
141
142 Ok(TMLightBlock {
143 signed_header: block.signed_header.unwrap(), validators: block.validators,
145 next_validators,
146 provider: PeerId::new([0; 20]),
147 })
148 }
149}