Skip to content

Commit 7f6bb22

Browse files
committed
Fetch remote forkpoint and validators
1 parent 33d321a commit 7f6bb22

File tree

5 files changed

+106
-19
lines changed

5 files changed

+106
-19
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

monad-node-config/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,7 @@ pub type ForkpointConfig = monad_consensus_types::checkpoint::Checkpoint<
8989
ExecutionProtocolType,
9090
>;
9191
#[cfg(feature = "crypto")]
92+
pub type ValidatorsConfigType =
93+
monad_consensus_types::validator_data::ValidatorsConfig<SignatureCollectionType>;
94+
#[cfg(feature = "crypto")]
9295
pub type MonadNodeConfig = NodeConfig<SignatureType>;

monad-node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ opentelemetry-otlp = { workspace = true, features = ["metrics", "grpc-tonic"] }
5151
opentelemetry-semantic-conventions = { workspace = true }
5252
rand_chacha = { workspace = true }
5353
rayon = { workspace = true }
54+
reqwest = { workspace = true, features = ["blocking"] }
5455
thiserror = { workspace = true }
5556
tokio = { workspace = true, features = ["rt-multi-thread", "signal"] }
5657
toml = { workspace = true }

monad-node/src/main.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,7 @@ use clap::CommandFactory;
2929
use futures_util::{FutureExt, StreamExt};
3030
use monad_chain_config::ChainConfig;
3131
use monad_consensus_state::ConsensusConfig;
32-
use monad_consensus_types::{
33-
metrics::Metrics,
34-
validator_data::{ValidatorSetDataWithEpoch, ValidatorsConfig},
35-
};
32+
use monad_consensus_types::{metrics::Metrics, validator_data::ValidatorSetDataWithEpoch};
3633
use monad_control_panel::{ipc::ControlPanelIpcReceiver, TracingReload};
3734
use monad_crypto::{
3835
certificate_signature::{
@@ -206,13 +203,8 @@ fn setup_tracing(
206203
}
207204

208205
async fn run(node_state: NodeState, reload_handle: Box<dyn TracingReload>) -> Result<(), ()> {
209-
let locked_epoch_validators = ValidatorsConfig::read_from_path(&node_state.validators_path)
210-
.unwrap_or_else(|err| {
211-
panic!(
212-
"failed to read/parse validators_path={:?}, err={:?}",
213-
&node_state.validators_path, err
214-
)
215-
})
206+
let locked_epoch_validators = node_state
207+
.validators_config
216208
.get_locked_validator_sets(&node_state.forkpoint_config);
217209

218210
let current_epoch = node_state
@@ -397,8 +389,8 @@ async fn run(node_state: NodeState, reload_handle: Box<dyn TracingReload>) -> Re
397389
key: node_state.secp256k1_identity,
398390
certkey: node_state.bls12_381_identity,
399391
beneficiary: node_state.node_config.beneficiary.into(),
400-
locked_epoch_validators,
401392
forkpoint: node_state.forkpoint_config.into(),
393+
locked_epoch_validators,
402394
block_sync_override_peers,
403395
consensus_config: ConsensusConfig {
404396
execution_delay: SeqNum(EXECUTION_DELAY),

monad-node/src/state.rs

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,32 +14,40 @@
1414
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

1616
use std::{
17+
env,
1718
path::{Path, PathBuf},
19+
str::FromStr,
1820
time::Duration,
1921
};
2022

2123
use clap::{error::ErrorKind, FromArgMatches};
2224
use monad_bls::BlsKeyPair;
2325
use monad_chain_config::MonadChainConfig;
2426
use monad_keystore::keystore::Keystore;
25-
use monad_node_config::{ForkpointConfig, MonadNodeConfig};
27+
use monad_node_config::{ForkpointConfig, MonadNodeConfig, ValidatorsConfigType};
2628
use monad_secp::KeyPair;
27-
use tracing::info;
29+
use monad_types::Round;
30+
use reqwest::{blocking::Client, Url};
31+
use tracing::{info, warn};
2832

2933
use crate::{cli::Cli, error::NodeSetupError};
3034

35+
const REMOTE_FORKPOINT_URL_ENV: &str = "REMOTE_FORKPOINT_URL";
36+
const REMOTE_VALIDATORS_URL_ENV: &str = "REMOTE_VALIDATORS_URL";
37+
3138
pub struct NodeState {
3239
pub node_config: MonadNodeConfig,
3340
pub node_config_path: PathBuf,
3441
pub forkpoint_config: ForkpointConfig,
35-
pub validators_path: PathBuf,
42+
pub validators_config: ValidatorsConfigType,
3643
pub chain_config: MonadChainConfig,
3744

3845
pub secp256k1_identity: KeyPair,
3946
pub router_identity: KeyPair,
4047
pub bls12_381_identity: BlsKeyPair,
4148

4249
pub forkpoint_path: PathBuf,
50+
pub validators_path: PathBuf,
4351
pub wal_path: PathBuf,
4452
pub ledger_path: PathBuf,
4553
pub mempool_ipc_path: PathBuf,
@@ -60,7 +68,7 @@ impl NodeState {
6068
secp_identity,
6169
node_config: node_config_path,
6270
forkpoint_config: forkpoint_config_path,
63-
validators_path,
71+
validators_path: validators_config_path,
6472
devnet_chain_config_override: maybe_devnet_chain_config_override_path,
6573
wal_path,
6674
ledger_path,
@@ -101,8 +109,10 @@ impl NodeState {
101109

102110
let node_config: MonadNodeConfig =
103111
toml::from_str(&std::fs::read_to_string(&node_config_path)?)?;
104-
let forkpoint_config: ForkpointConfig =
105-
toml::from_str(&std::fs::read_to_string(&forkpoint_config_path)?)?;
112+
113+
let (forkpoint_config, validators_config) =
114+
get_latest_configs(&forkpoint_config_path, &validators_config_path)?;
115+
106116
let devnet_chain_config_override =
107117
if let Some(devnet_override_path) = maybe_devnet_chain_config_override_path {
108118
Some(toml::from_str(&std::fs::read_to_string(
@@ -141,14 +151,15 @@ impl NodeState {
141151
node_config,
142152
node_config_path,
143153
forkpoint_config,
144-
validators_path,
154+
validators_config,
145155
chain_config,
146156

147157
secp256k1_identity: secp_key,
148158
router_identity: router_key,
149159
bls12_381_identity: bls_key,
150160

151161
forkpoint_path: forkpoint_config_path,
162+
validators_path: validators_config_path,
152163
wal_path,
153164
ledger_path,
154165
triedb_path,
@@ -164,6 +175,85 @@ impl NodeState {
164175
}
165176
}
166177

178+
fn fetch_remote_configs() -> Result<(ForkpointConfig, ValidatorsConfigType), String> {
179+
let forkpoint_url_str = env::var(REMOTE_FORKPOINT_URL_ENV)
180+
.map_err(|_| format!("{REMOTE_FORKPOINT_URL_ENV} env variable unset"))?;
181+
let remote_forkpoint_url = Url::from_str(&forkpoint_url_str)
182+
.map_err(|err| format!("failed to parse remote forkpoint url: {err}"))?;
183+
184+
let validators_url_str = env::var(REMOTE_VALIDATORS_URL_ENV)
185+
.map_err(|_| format!("{REMOTE_VALIDATORS_URL_ENV} env variable unset"))?;
186+
let remote_validators_url = Url::from_str(&validators_url_str)
187+
.map_err(|err| format!("failed to parse remote validators url: {err}"))?;
188+
189+
let client = Client::new();
190+
191+
let forkpoint_config_str = client
192+
.get(remote_forkpoint_url)
193+
.send()
194+
.and_then(|forkpoint_response| forkpoint_response.error_for_status())
195+
.and_then(|valid_forkpoint_response| valid_forkpoint_response.text())
196+
.map_err(|err| format!("error fetching remote forkpoint config: {err}"))?;
197+
let forkpoint_config = toml::from_str(&forkpoint_config_str)
198+
.map_err(|err| format!("failed to parse remote forkpoint config: {err}"))?;
199+
200+
let validators_config_str = client
201+
.get(remote_validators_url)
202+
.send()
203+
.and_then(|validators_response| validators_response.error_for_status())
204+
.and_then(|valid_validators_response| valid_validators_response.text())
205+
.map_err(|err| format!("error fetching remote validators config: {err}"))?;
206+
let validators_config = ValidatorsConfigType::read_from_str(&validators_config_str)
207+
.map_err(|err| format!("failed to parse remote validators config: {err}"))?;
208+
209+
Ok((forkpoint_config, validators_config))
210+
}
211+
212+
fn get_latest_configs(
213+
forkpoint_config_path: &Path,
214+
validators_config_path: &Path,
215+
) -> Result<(ForkpointConfig, ValidatorsConfigType), NodeSetupError> {
216+
let local_forkpoint_config: ForkpointConfig =
217+
toml::from_str(&std::fs::read_to_string(forkpoint_config_path)?)?;
218+
let local_validators_config = ValidatorsConfigType::read_from_path(validators_config_path)
219+
.map_err(|_| NodeSetupError::Custom {
220+
kind: ErrorKind::Io,
221+
msg: "failed to read validators.toml file".to_owned(),
222+
})?;
223+
224+
match fetch_remote_configs() {
225+
Ok((remote_forkpoint_config, remote_validators_config)) => {
226+
let local_forkpoint_round = local_forkpoint_config.high_certificate.round();
227+
let remote_forkpoint_round = remote_forkpoint_config.high_certificate.round();
228+
229+
// if remote config is more recent, use that over local config
230+
if remote_forkpoint_round > local_forkpoint_round {
231+
info!(
232+
?remote_forkpoint_round,
233+
?local_forkpoint_round,
234+
"fetched more recent forkpoint from remote source"
235+
);
236+
return Ok((remote_forkpoint_config, remote_validators_config));
237+
} else if remote_forkpoint_round < local_forkpoint_round - Round(200) {
238+
// warn user if remote configs are stale
239+
warn!(
240+
?remote_forkpoint_round,
241+
?local_forkpoint_round,
242+
"remote forkpoint 200 rounds older than local forkpoint"
243+
);
244+
}
245+
}
246+
Err(err) => {
247+
info!(
248+
err,
249+
"failed to fetch remote configs, using local forkpoint and validators config"
250+
);
251+
}
252+
}
253+
254+
Ok((local_forkpoint_config, local_validators_config))
255+
}
256+
167257
fn load_secp256k1_keypair(path: &Path, keystore_password: &str) -> Result<KeyPair, NodeSetupError> {
168258
Keystore::load_secp_key(path, keystore_password).map_err(|_| NodeSetupError::Custom {
169259
kind: ErrorKind::ValueValidation,

0 commit comments

Comments
 (0)