Skip to content

Commit 6d21bfb

Browse files
authored
Add a faucet endpoint to return the current list of validators. (linera-io#1383)
1 parent 01f6c5f commit 6d21bfb

File tree

5 files changed

+116
-19
lines changed

5 files changed

+116
-19
lines changed

linera-core/src/node.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,20 @@ pub trait ValidatorNodeProvider {
8282
where
8383
I: FromIterator<(ValidatorName, Self::Node)>,
8484
{
85-
committee
86-
.validators()
87-
.iter()
88-
.map(|(name, validator)| {
89-
let node = self.make_node(&validator.network_address)?;
90-
Ok((*name, node))
91-
})
85+
self.make_nodes_from_list(committee.validator_addresses())
86+
}
87+
88+
fn make_nodes_from_list<I, A>(
89+
&self,
90+
validators: impl IntoIterator<Item = (ValidatorName, A)>,
91+
) -> Result<I, NodeError>
92+
where
93+
I: FromIterator<(ValidatorName, Self::Node)>,
94+
A: AsRef<str>,
95+
{
96+
validators
97+
.into_iter()
98+
.map(|(name, address)| Ok((name, self.make_node(address.as_ref())?)))
9299
.collect()
93100
}
94101
}

linera-execution/src/committee.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,12 @@ impl Committee {
350350
&self.validators
351351
}
352352

353+
pub fn validator_addresses(&self) -> impl Iterator<Item = (ValidatorName, &str)> {
354+
self.validators
355+
.iter()
356+
.map(|(name, validator)| (*name, &*validator.network_address))
357+
}
358+
353359
pub fn total_votes(&self) -> u64 {
354360
self.total_votes
355361
}

linera-service/src/cli_wrappers/wallet.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use linera_base::{
1616
data_types::Amount,
1717
identifiers::{ApplicationId, BytecodeId, ChainId, MessageId, Owner},
1818
};
19-
use linera_execution::Bytecode;
19+
use linera_execution::{committee::ValidatorName, Bytecode};
2020
use serde::{de::DeserializeOwned, ser::Serialize};
2121
use serde_json::{json, Value};
2222
use std::{
@@ -888,6 +888,46 @@ impl Faucet {
888888
};
889889
Ok(outcome)
890890
}
891+
892+
pub async fn current_validators(url: &str) -> Result<Vec<(ValidatorName, String)>> {
893+
let query = "query { currentValidators { name networkAddress } }";
894+
let client = reqwest_client();
895+
let response = client
896+
.post(url)
897+
.json(&json!({ "query": query }))
898+
.send()
899+
.await
900+
.context("failed to post query")?;
901+
anyhow::ensure!(
902+
response.status().is_success(),
903+
"Query \"{}\" failed: {}",
904+
query,
905+
response
906+
.text()
907+
.await
908+
.unwrap_or_else(|error| format!("Could not get response text: {error}"))
909+
);
910+
let mut value: Value = response.json().await.context("invalid JSON")?;
911+
if let Some(errors) = value.get("errors") {
912+
bail!("Query \"{}\" failed: {}", query, errors);
913+
}
914+
let validators = match value["data"]["currentValidators"].take() {
915+
serde_json::Value::Array(validators) => validators,
916+
validators => bail!("{validators} is not an array"),
917+
};
918+
validators
919+
.into_iter()
920+
.map(|mut validator| {
921+
let name = serde_json::from_value::<ValidatorName>(validator["name"].take())
922+
.context("could not parse current validators: invalid name")?;
923+
let addr = validator["networkAddress"]
924+
.as_str()
925+
.context("could not parse current validators: invalid address")?
926+
.to_string();
927+
Ok((name, addr))
928+
})
929+
.collect()
930+
}
891931
}
892932

893933
/// A running `Application` to be queried in GraphQL.

linera-service/src/faucet.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ use linera_core::{
1414
client::{ChainClient, ChainClientError},
1515
node::ValidatorNodeProvider,
1616
};
17-
use linera_execution::ChainOwnership;
17+
use linera_execution::{committee::ValidatorName, ChainOwnership};
1818
use linera_storage::Storage;
1919
use linera_views::views::ViewError;
20+
use serde::Deserialize;
2021
use serde_json::json;
2122
use std::{net::SocketAddr, num::NonZeroU16, sync::Arc};
2223
use thiserror::Error as ThisError;
@@ -30,8 +31,9 @@ use crate::{config::GenesisConfig, util};
3031
mod tests;
3132

3233
/// The root GraphQL query type.
33-
pub struct QueryRoot {
34+
pub struct QueryRoot<P, S> {
3435
genesis_config: Arc<GenesisConfig>,
36+
client: Arc<Mutex<ChainClient<P, S>>>,
3537
}
3638

3739
/// The root GraphQL mutation type.
@@ -66,12 +68,37 @@ pub struct ClaimOutcome {
6668
pub certificate_hash: CryptoHash,
6769
}
6870

71+
#[derive(Debug, Deserialize, SimpleObject)]
72+
pub struct Validator {
73+
pub name: ValidatorName,
74+
pub network_address: String,
75+
}
76+
6977
#[Object]
70-
impl QueryRoot {
78+
impl<P, S> QueryRoot<P, S>
79+
where
80+
P: ValidatorNodeProvider + Send + Sync + 'static,
81+
S: Storage + Clone + Send + Sync + 'static,
82+
ViewError: From<S::ContextError>,
83+
{
7184
/// Returns the genesis config.
7285
async fn genesis_config(&self) -> Result<serde_json::Value, Error> {
7386
Ok(serde_json::to_value(&*self.genesis_config)?)
7487
}
88+
89+
/// Returns the current committee's validators.
90+
async fn current_validators(&self) -> Result<Vec<Validator>, Error> {
91+
let mut client = self.client.lock().await;
92+
let committee = client.local_committee().await?;
93+
Ok(committee
94+
.validators()
95+
.iter()
96+
.map(|(name, validator)| Validator {
97+
name: *name,
98+
network_address: validator.network_address.clone(),
99+
})
100+
.collect())
101+
}
75102
}
76103

77104
#[Object]
@@ -181,7 +208,7 @@ where
181208
})
182209
}
183210

184-
pub fn schema(&self) -> Schema<QueryRoot, MutationRoot<P, S>, EmptySubscription> {
211+
pub fn schema(&self) -> Schema<QueryRoot<P, S>, MutationRoot<P, S>, EmptySubscription> {
185212
let mutation_root = MutationRoot {
186213
client: self.client.clone(),
187214
amount: self.amount,
@@ -191,6 +218,7 @@ where
191218
};
192219
let query_root = QueryRoot {
193220
genesis_config: self.genesis_config.clone(),
221+
client: self.client.clone(),
194222
};
195223
Schema::build(query_root, mutation_root, EmptySubscription).finish()
196224
}

linera-service/src/linera.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1811,8 +1811,15 @@ impl Runnable for Job {
18111811

18121812
Assign { key, message_id } => {
18131813
let chain_id = ChainId::child(message_id);
1814-
Self::assign_new_chain_to_key(chain_id, message_id, storage, key, &mut context)
1815-
.await?;
1814+
Self::assign_new_chain_to_key(
1815+
chain_id,
1816+
message_id,
1817+
storage,
1818+
key,
1819+
None,
1820+
&mut context,
1821+
)
1822+
.await?;
18161823
println!("{}", chain_id);
18171824
context.save_wallet();
18181825
}
@@ -1885,6 +1892,7 @@ impl Runnable for Job {
18851892
let public_key = key_pair.public();
18861893
context.wallet_state.add_unassigned_key_pair(key_pair);
18871894
let outcome = cli_wrappers::Faucet::claim_url(&public_key, &faucet_url).await?;
1895+
let validators = cli_wrappers::Faucet::current_validators(&faucet_url).await?;
18881896
println!("{}", outcome.chain_id);
18891897
println!("{}", outcome.message_id);
18901898
println!("{}", outcome.certificate_hash);
@@ -1893,6 +1901,7 @@ impl Runnable for Job {
18931901
outcome.message_id,
18941902
storage.clone(),
18951903
public_key,
1904+
Some(validators),
18961905
&mut context,
18971906
)
18981907
.await?;
@@ -1919,6 +1928,7 @@ impl Job {
19191928
message_id: MessageId,
19201929
storage: S,
19211930
public_key: PublicKey,
1931+
validators: Option<Vec<(ValidatorName, String)>>,
19221932
context: &mut ClientContext,
19231933
) -> anyhow::Result<()>
19241934
where
@@ -1933,11 +1943,17 @@ impl Job {
19331943
// Take the latest committee we know of.
19341944
let admin_chain_id = context.wallet_state.genesis_admin_chain();
19351945
let query = ChainInfoQuery::new(admin_chain_id).with_committees();
1936-
let info = node_client.handle_chain_info_query(query).await?;
1937-
let committee = info
1938-
.latest_committee()
1939-
.context("Invalid chain info response; missing latest committee")?;
1940-
let nodes = context.make_node_provider().make_nodes(committee)?;
1946+
let nodes = if let Some(validators) = validators {
1947+
context
1948+
.make_node_provider()
1949+
.make_nodes_from_list(validators)?
1950+
} else {
1951+
let info = node_client.handle_chain_info_query(query).await?;
1952+
let committee = info
1953+
.latest_committee()
1954+
.context("Invalid chain info response; missing latest committee")?;
1955+
context.make_node_provider().make_nodes(committee)?
1956+
};
19411957

19421958
// Download the parent chain.
19431959
let target_height = message_id.height.try_add_one()?;

0 commit comments

Comments
 (0)