Skip to content

Commit 2eda9d8

Browse files
committed
Enable building the light-client crate for WASM on Rust nightly
1 parent 0dcfa1c commit 2eda9d8

File tree

3 files changed

+165
-143
lines changed

3 files changed

+165
-143
lines changed

light-client/Cargo.toml

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ description = """
1818
Implementation of the Tendermint Light Client Verification Protocol.
1919
"""
2020

21+
[lib]
22+
crate-type = ["cdylib", "rlib"]
23+
2124
[dependencies]
2225
tendermint = { version = "0.15.0", path = "../tendermint" }
23-
tendermint-rpc = { version = "0.15.0", path = "../rpc", features = ["client"] }
26+
tendermint-rpc = { version = "0.15.0", path = "../rpc" }
2427

2528
anomaly = { version = "0.2.0", features = ["serializer"] }
2629
contracts = "0.4.0"
@@ -41,4 +44,5 @@ serde_json = "1.0.51"
4144
gumdrop = "0.8.0"
4245

4346
[features]
47+
rpc = ["tendermint-rpc/client"]
4448
secp256k1 = ["tendermint/secp256k1", "tendermint-rpc/secp256k1"]

light-client/src/components/io.rs

+114-105
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
11
//! Provides an interface and a default implementation of the `Io` component
22
3-
use std::collections::HashMap;
4-
use std::time::Duration;
5-
6-
use contracts::{contract_trait, post, pre};
3+
use contracts::{contract_trait, post};
74
use serde::{Deserialize, Serialize};
85
use thiserror::Error;
96

10-
use tendermint::{
11-
block::signed_header::SignedHeader as TMSignedHeader, validator::Set as TMValidatorSet,
12-
};
13-
147
use tendermint_rpc as rpc;
158

16-
use crate::{
17-
bail,
18-
types::{Height, LightBlock, PeerId},
19-
};
9+
use crate::types::{Height, LightBlock, PeerId};
2010

2111
/// Type for selecting either a specific height or the latest one
2212
pub enum AtHeight {
@@ -81,113 +71,132 @@ where
8171
}
8272
}
8373

84-
/// Production implementation of the Io component, which fetches
85-
/// light blocks from full nodes via RPC.
86-
#[derive(Clone, Debug)]
87-
pub struct ProdIo {
88-
peer_map: HashMap<PeerId, tendermint::net::Address>,
89-
timeout: Option<Duration>,
90-
}
74+
#[cfg(feature = "rpc")]
75+
pub use self::prod::ProdIo;
9176

92-
#[contract_trait]
93-
impl Io for ProdIo {
94-
fn fetch_light_block(&self, peer: PeerId, height: AtHeight) -> Result<LightBlock, IoError> {
95-
let signed_header = self.fetch_signed_header(peer, height)?;
96-
let height = signed_header.header.height;
77+
#[cfg(feature = "rpc")]
78+
mod prod {
79+
use super::*;
9780

98-
let validator_set = self.fetch_validator_set(peer, height.into())?;
99-
let next_validator_set = self.fetch_validator_set(peer, height.increment().into())?;
81+
use std::collections::HashMap;
82+
use std::time::Duration;
10083

101-
let light_block = LightBlock::new(signed_header, validator_set, next_validator_set, peer);
84+
use crate::bail;
85+
use contracts::{contract_trait, post, pre};
86+
use tendermint::{
87+
block::signed_header::SignedHeader as TMSignedHeader, validator::Set as TMValidatorSet,
88+
};
10289

103-
Ok(light_block)
104-
}
105-
}
106-
107-
impl ProdIo {
108-
/// Constructs a new ProdIo component.
109-
///
110-
/// A peer map which maps peer IDS to their network address must be supplied.
111-
pub fn new(
90+
/// Production implementation of the Io component, which fetches
91+
/// light blocks from full nodes via RPC.
92+
#[derive(Clone, Debug)]
93+
pub struct ProdIo {
11294
peer_map: HashMap<PeerId, tendermint::net::Address>,
11395
timeout: Option<Duration>,
114-
) -> Self {
115-
Self { peer_map, timeout }
11696
}
11797

118-
#[pre(self.peer_map.contains_key(&peer))]
119-
fn fetch_signed_header(
120-
&self,
121-
peer: PeerId,
122-
height: AtHeight,
123-
) -> Result<TMSignedHeader, IoError> {
124-
let rpc_client = self.rpc_client_for(peer);
125-
126-
let res = block_on(
127-
async {
128-
match height {
129-
AtHeight::Highest => rpc_client.latest_commit().await,
130-
AtHeight::At(height) => rpc_client.commit(height).await,
131-
}
132-
},
133-
peer,
134-
self.timeout,
135-
)?;
136-
137-
match res {
138-
Ok(response) => Ok(response.signed_header),
139-
Err(err) => Err(IoError::IoError(err)),
98+
#[contract_trait]
99+
impl Io for ProdIo {
100+
fn fetch_light_block(&self, peer: PeerId, height: AtHeight) -> Result<LightBlock, IoError> {
101+
let signed_header = self.fetch_signed_header(peer, height)?;
102+
let height = signed_header.header.height;
103+
104+
let validator_set = self.fetch_validator_set(peer, height.into())?;
105+
let next_validator_set = self.fetch_validator_set(peer, height.increment().into())?;
106+
107+
let light_block =
108+
LightBlock::new(signed_header, validator_set, next_validator_set, peer);
109+
110+
Ok(light_block)
140111
}
141112
}
142113

143-
#[pre(self.peer_map.contains_key(&peer))]
144-
fn fetch_validator_set(
145-
&self,
146-
peer: PeerId,
147-
height: AtHeight,
148-
) -> Result<TMValidatorSet, IoError> {
149-
let height = match height {
150-
AtHeight::Highest => bail!(IoError::InvalidHeight(
151-
"given height must be greater than 0".to_string()
152-
)),
153-
AtHeight::At(height) => height,
154-
};
155-
156-
let res = block_on(
157-
self.rpc_client_for(peer).validators(height),
158-
peer,
159-
self.timeout,
160-
)?;
161-
162-
match res {
163-
Ok(response) => Ok(TMValidatorSet::new(response.validators)),
164-
Err(err) => Err(IoError::IoError(err)),
114+
impl ProdIo {
115+
/// Constructs a new ProdIo component.
116+
///
117+
/// A peer map which maps peer IDS to their network address must be supplied.
118+
pub fn new(
119+
peer_map: HashMap<PeerId, tendermint::net::Address>,
120+
timeout: Option<Duration>,
121+
) -> Self {
122+
Self { peer_map, timeout }
123+
}
124+
125+
#[pre(self.peer_map.contains_key(&peer))]
126+
fn fetch_signed_header(
127+
&self,
128+
peer: PeerId,
129+
height: AtHeight,
130+
) -> Result<TMSignedHeader, IoError> {
131+
let rpc_client = self.rpc_client_for(peer);
132+
133+
let res = block_on(
134+
async {
135+
match height {
136+
AtHeight::Highest => rpc_client.latest_commit().await,
137+
AtHeight::At(height) => rpc_client.commit(height).await,
138+
}
139+
},
140+
peer,
141+
self.timeout,
142+
)?;
143+
144+
match res {
145+
Ok(response) => Ok(response.signed_header),
146+
Err(err) => Err(IoError::IoError(err)),
147+
}
165148
}
166-
}
167149

168-
// FIXME: Cannot enable precondition because of "autoref lifetime" issue
169-
// #[pre(self.peer_map.contains_key(&peer))]
170-
fn rpc_client_for(&self, peer: PeerId) -> rpc::Client {
171-
let peer_addr = self.peer_map.get(&peer).unwrap().to_owned();
172-
rpc::Client::new(peer_addr)
150+
#[pre(self.peer_map.contains_key(&peer))]
151+
fn fetch_validator_set(
152+
&self,
153+
peer: PeerId,
154+
height: AtHeight,
155+
) -> Result<TMValidatorSet, IoError> {
156+
let height = match height {
157+
AtHeight::Highest => bail!(IoError::InvalidHeight(
158+
"given height must be greater than 0".to_string()
159+
)),
160+
AtHeight::At(height) => height,
161+
};
162+
163+
let res = block_on(
164+
self.rpc_client_for(peer).validators(height),
165+
peer,
166+
self.timeout,
167+
)?;
168+
169+
match res {
170+
Ok(response) => Ok(TMValidatorSet::new(response.validators)),
171+
Err(err) => Err(IoError::IoError(err)),
172+
}
173+
}
174+
175+
// FIXME: Cannot enable precondition because of "autoref lifetime" issue
176+
// #[pre(self.peer_map.contains_key(&peer))]
177+
fn rpc_client_for(&self, peer: PeerId) -> rpc::Client {
178+
let peer_addr = self.peer_map.get(&peer).unwrap().to_owned();
179+
rpc::Client::new(peer_addr)
180+
}
173181
}
174-
}
175182

176-
fn block_on<F: std::future::Future>(
177-
f: F,
178-
peer: PeerId,
179-
timeout: Option<Duration>,
180-
) -> Result<F::Output, IoError> {
181-
let mut rt = tokio::runtime::Builder::new()
182-
.basic_scheduler()
183-
.enable_all()
184-
.build()
185-
.unwrap();
186-
187-
if let Some(timeout) = timeout {
188-
rt.block_on(async { tokio::time::timeout(timeout, f).await })
189-
.map_err(|_| IoError::Timeout(peer))
190-
} else {
191-
Ok(rt.block_on(f))
183+
fn block_on<F: std::future::Future>(
184+
f: F,
185+
peer: PeerId,
186+
timeout: Option<Duration>,
187+
) -> Result<F::Output, IoError> {
188+
let mut rt = tokio::runtime::Builder::new()
189+
.basic_scheduler()
190+
.enable_all()
191+
.build()
192+
.unwrap();
193+
194+
if let Some(timeout) = timeout {
195+
rt.block_on(async { tokio::time::timeout(timeout, f).await })
196+
.map_err(|_| IoError::Timeout(peer))
197+
} else {
198+
Ok(rt.block_on(f))
199+
}
192200
}
193201
}
202+

light-client/src/evidence.rs

+46-37
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@
33
use crate::{components::io::IoError, types::PeerId};
44

55
use tendermint::abci::transaction::Hash;
6-
use tendermint_rpc as rpc;
76

8-
use contracts::{contract_trait, pre};
9-
use std::collections::HashMap;
7+
use contracts::contract_trait;
108

119
pub use tendermint::evidence::Evidence;
1210

@@ -18,47 +16,58 @@ pub trait EvidenceReporter: Send {
1816
fn report(&self, e: Evidence, peer: PeerId) -> Result<Hash, IoError>;
1917
}
2018

21-
/// Production implementation of the EvidenceReporter component, which reports evidence to full
22-
/// nodes via RPC.
23-
#[derive(Clone, Debug)]
24-
pub struct ProdEvidenceReporter {
25-
peer_map: HashMap<PeerId, tendermint::net::Address>,
26-
}
19+
#[cfg(feature = "rpc")]
20+
pub use self::prod::ProdEvidenceReporter;
2721

28-
#[contract_trait]
29-
impl EvidenceReporter for ProdEvidenceReporter {
30-
#[pre(self.peer_map.contains_key(&peer))]
31-
fn report(&self, e: Evidence, peer: PeerId) -> Result<Hash, IoError> {
32-
let res = block_on(self.rpc_client_for(peer).broadcast_evidence(e));
22+
#[cfg(feature = "rpc")]
23+
mod prod {
24+
use contracts::pre;
25+
use std::collections::HashMap;
26+
use tendermint_rpc as rpc;
27+
28+
/// Production implementation of the EvidenceReporter component, which reports evidence to full
29+
/// nodes via RPC.
30+
#[derive(Clone, Debug)]
31+
pub struct ProdEvidenceReporter {
32+
peer_map: HashMap<PeerId, tendermint::net::Address>,
33+
}
34+
35+
#[contract_trait]
36+
impl EvidenceReporter for ProdEvidenceReporter {
37+
#[pre(self.peer_map.contains_key(&peer))]
38+
fn report(&self, e: Evidence, peer: PeerId) -> Result<Hash, IoError> {
39+
let res = block_on(self.rpc_client_for(peer).broadcast_evidence(e));
3340

34-
match res {
35-
Ok(response) => Ok(response.hash),
36-
Err(err) => Err(IoError::IoError(err)),
41+
match res {
42+
Ok(response) => Ok(response.hash),
43+
Err(err) => Err(IoError::IoError(err)),
44+
}
3745
}
3846
}
39-
}
4047

41-
impl ProdEvidenceReporter {
42-
/// Constructs a new ProdEvidenceReporter component.
43-
///
44-
/// A peer map which maps peer IDS to their network address must be supplied.
45-
pub fn new(peer_map: HashMap<PeerId, tendermint::net::Address>) -> Self {
46-
Self { peer_map }
48+
impl ProdEvidenceReporter {
49+
/// Constructs a new ProdEvidenceReporter component.
50+
///
51+
/// A peer map which maps peer IDS to their network address must be supplied.
52+
pub fn new(peer_map: HashMap<PeerId, tendermint::net::Address>) -> Self {
53+
Self { peer_map }
54+
}
55+
56+
// FIXME: Cannot enable precondition because of "autoref lifetime" issue
57+
// #[pre(self.peer_map.contains_key(&peer))]
58+
fn rpc_client_for(&self, peer: PeerId) -> rpc::Client {
59+
let peer_addr = self.peer_map.get(&peer).unwrap().to_owned();
60+
rpc::Client::new(peer_addr)
61+
}
4762
}
4863

49-
// FIXME: Cannot enable precondition because of "autoref lifetime" issue
50-
// #[pre(self.peer_map.contains_key(&peer))]
51-
fn rpc_client_for(&self, peer: PeerId) -> rpc::Client {
52-
let peer_addr = self.peer_map.get(&peer).unwrap().to_owned();
53-
rpc::Client::new(peer_addr)
64+
fn block_on<F: std::future::Future>(f: F) -> F::Output {
65+
tokio::runtime::Builder::new()
66+
.basic_scheduler()
67+
.enable_all()
68+
.build()
69+
.unwrap()
70+
.block_on(f)
5471
}
5572
}
5673

57-
fn block_on<F: std::future::Future>(f: F) -> F::Output {
58-
tokio::runtime::Builder::new()
59-
.basic_scheduler()
60-
.enable_all()
61-
.build()
62-
.unwrap()
63-
.block_on(f)
64-
}

0 commit comments

Comments
 (0)