layer_climb_core/querier/
validator.rs1use tracing::instrument;
2
3use crate::prelude::*;
4
5use super::basic::BlockHeightReq;
6
7impl QueryClient {
8 #[instrument]
9 pub async fn validator_set(
10 &self,
11 height: Option<u64>,
12 proposer_address: Option<&[u8]>,
13 ) -> Result<layer_climb_proto::tendermint::ValidatorSet> {
14 self.run_with_middleware(ValidatorSetReq {
15 height,
16 proposer_address,
17 })
18 .await
19 }
20}
21
22#[derive(Clone, Debug)]
23pub struct ValidatorSetReq<'a> {
24 pub height: Option<u64>,
25 pub proposer_address: Option<&'a [u8]>,
26}
27
28impl QueryRequest for ValidatorSetReq<'_> {
29 type QueryResponse = layer_climb_proto::tendermint::ValidatorSet;
30
31 async fn request(
32 &self,
33 client: QueryClient,
34 ) -> Result<layer_climb_proto::tendermint::ValidatorSet> {
35 let height = match self.height {
36 Some(height) => height,
37 None => BlockHeightReq {}.request(client.clone()).await?,
38 };
39
40 let mut validators = Vec::new();
41 let mut pagination = None;
42
43 let mut proposer = None;
44
45 let proposer_address = self
46 .proposer_address
47 .map(|addr| tendermint::account::Id::try_from(addr.to_vec()))
48 .transpose()?;
49
50 let mut grpc_query_client = match client.get_connection_mode() {
51 ConnectionMode::Grpc => Some(
52 layer_climb_proto::tendermint::service_client::ServiceClient::new(
53 client.clone_grpc_channel()?,
54 ),
55 ),
56 ConnectionMode::Rpc => None,
57 };
58
59 loop {
60 let req = layer_climb_proto::tendermint::GetValidatorSetByHeightRequest {
61 height: height.try_into()?,
62 pagination,
63 };
64
65 let resp = match client.get_connection_mode() {
66 ConnectionMode::Grpc => grpc_query_client
67 .as_mut()
68 .unwrap()
69 .get_validator_set_by_height(req)
70 .await
71 .map(|res| res.into_inner())
72 .context("couldn't get validator set")?,
73 ConnectionMode::Rpc => client
74 .rpc_client()?
75 .abci_protobuf_query(
76 "/cosmos.base.tendermint.v1beta1.Service/GetValidatorSetByHeight",
77 req,
78 Some(height),
79 )
80 .await
81 .context("couldn't get validator set")?,
82 };
83
84 for validator in resp.validators {
85 let pub_key = validator.pub_key.context("couldn't get public key")?;
86
87 let pub_key = match pub_key.type_url.as_str() {
88 "/cosmos.crypto.ed25519.PubKey" => {
89 let key = layer_climb_proto::crypto::ed25519::PubKey::decode(
90 pub_key.value.as_slice(),
91 )?
92 .key;
93 tendermint::public_key::PublicKey::Ed25519(key.as_slice().try_into()?)
94 }
95 _ => {
96 return Err(anyhow::anyhow!(
97 "unsupported public key type: {}",
98 pub_key.type_url
99 ))
100 }
101 };
102
103 let info = tendermint::validator::Info {
104 name: None,
105 pub_key,
106 address: tendermint::account::Id::from(pub_key),
107 power: validator.voting_power.try_into()?,
108 proposer_priority: validator.proposer_priority.into(),
109 };
110
111 if Some(info.address) == proposer_address {
112 proposer = Some(info.clone());
113 }
114
115 validators.push(info);
116 }
117
118 if let Some(resp_pagination) = resp.pagination {
119 if resp_pagination.next_key.is_empty() {
120 break;
121 } else {
122 pagination = Some(layer_climb_proto::query::PageRequest {
123 key: resp_pagination.next_key,
124 offset: 0,
125 limit: 0,
126 count_total: false,
127 reverse: false,
128 });
129 }
130 } else {
131 break;
132 }
133 }
134
135 let validator_set =
136 convert_raw_validator_set(tendermint::validator::Set::new(validators, proposer));
137
138 Ok(validator_set)
146 }
147}
148
149fn convert_raw_validator_set(
151 validators: tendermint::validator::Set,
152) -> layer_climb_proto::tendermint::ValidatorSet {
153 layer_climb_proto::tendermint::ValidatorSet {
154 validators: validators
155 .validators()
156 .iter()
157 .map(|validator| layer_climb_proto::tendermint::Validator {
158 address: validator.address.into(),
159 pub_key: Some(layer_climb_proto::tendermint::crypto::PublicKey {
160 sum: Some(
161 layer_climb_proto::tendermint::crypto::public_key::Sum::Ed25519(
162 validator.pub_key.to_bytes(),
163 ),
164 ),
165 }),
166 voting_power: validator.power.into(),
167 proposer_priority: validator.proposer_priority.into(),
168 })
169 .collect(),
170
171 proposer: validators.proposer().as_ref().map(|validator| {
172 layer_climb_proto::tendermint::Validator {
173 address: validator.address.into(),
174 pub_key: Some(layer_climb_proto::tendermint::crypto::PublicKey {
175 sum: Some(
176 layer_climb_proto::tendermint::crypto::public_key::Sum::Ed25519(
177 validator.pub_key.to_bytes(),
178 ),
179 ),
180 }),
181 voting_power: validator.power.into(),
182 proposer_priority: validator.proposer_priority.into(),
183 }
184 }),
185 total_voting_power: validators.total_voting_power().into(),
186 }
187}