-
Notifications
You must be signed in to change notification settings - Fork 228
/
Copy pathlight_client.rs
135 lines (116 loc) · 3.97 KB
/
light_client.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use std::{path::PathBuf, time::Duration};
use futures::executor::block_on;
use gumdrop::Options;
use tendermint::Hash;
use tendermint_light_client::{
builder::{LightClientBuilder, SupervisorBuilder},
store::memory::MemoryStore,
supervisor::{Handle as _, Instance},
verifier::{
options::Options as LightClientOptions,
types::{Height, PeerId, TrustThreshold},
},
};
use tendermint_rpc as rpc;
#[derive(Debug, Options)]
struct CliOptions {
#[options(help = "print this help message")]
help: bool,
#[options(help = "enable verbose output")]
verbose: bool,
#[options(command)]
command: Option<Command>,
}
#[derive(Debug, Options)]
enum Command {
#[options(help = "run the light client and continuously sync up to the latest block")]
Sync(SyncOpts),
}
#[derive(Debug, Options)]
struct SyncOpts {
#[options(help = "show help for this command")]
help: bool,
#[options(
help = "address of the Tendermint node to connect to",
meta = "ADDR",
default = "tcp://127.0.0.1:26657"
)]
address: tendermint_rpc::Url,
#[options(
help = "height of the initial trusted state (optional if store already initialized)",
meta = "HEIGHT"
)]
trusted_height: Option<Height>,
#[options(
help = "hash of the initial trusted state (optional if store already initialized)",
meta = "HASH"
)]
trusted_hash: Option<Hash>,
#[options(
help = "path to the database folder",
meta = "PATH",
default = "./lightstore"
)]
db_path: PathBuf,
}
fn main() {
let opts = CliOptions::parse_args_default_or_exit();
match opts.command {
None => {
eprintln!("Please specify a command:");
eprintln!("{}\n", CliOptions::command_list().unwrap());
eprintln!("{}\n", CliOptions::usage());
std::process::exit(1);
},
Some(Command::Sync(sync_opts)) => sync_cmd(sync_opts).unwrap_or_else(|e| {
eprintln!("Command failed: {}", e);
std::process::exit(1);
}),
}
}
fn make_instance(
peer_id: PeerId,
addr: tendermint_rpc::Url,
opts: &SyncOpts,
) -> Result<Instance, Box<dyn std::error::Error>> {
let light_store = MemoryStore::new();
let rpc_client = rpc::HttpClient::new(addr).unwrap();
let options = LightClientOptions {
trust_threshold: TrustThreshold::default(),
trusting_period: Duration::from_secs(36000),
clock_drift: Duration::from_secs(1),
};
let builder =
LightClientBuilder::prod(peer_id, rpc_client, Box::new(light_store), options, None);
let builder = if let (Some(height), Some(hash)) = (opts.trusted_height, opts.trusted_hash) {
block_on(builder.trust_primary_at(height, hash))
} else {
builder.trust_from_store()
}?;
Ok(builder.build())
}
fn sync_cmd(opts: SyncOpts) -> Result<(), Box<dyn std::error::Error>> {
let primary: PeerId = "BADFADAD0BEFEEDC0C0ADEADBEEFC0FFEEFACADE".parse().unwrap();
let witness: PeerId = "CEFEEDBADFADAD0C0CEEFACADE0ADEADBEEFC0FF".parse().unwrap();
let primary_addr = opts.address.clone();
let witness_addr = opts.address.clone();
let primary_instance = make_instance(primary, primary_addr.clone(), &opts)?;
let witness_instance = make_instance(witness, witness_addr.clone(), &opts)?;
let supervisor = SupervisorBuilder::new()
.primary(primary, primary_addr, primary_instance)
.witness(witness, witness_addr, witness_instance)
.build_prod();
let handle = supervisor.handle();
std::thread::spawn(|| block_on(supervisor.run()));
loop {
match block_on(handle.verify_to_highest()) {
Ok(light_block) => {
println!("[info] synced to block {}", light_block.height());
},
Err(err) => {
println!("[error] sync failed: {}", err);
},
}
std::thread::sleep(Duration::from_millis(800));
}
}