1414// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
1616use std:: {
17+ env,
1718 path:: { Path , PathBuf } ,
19+ str:: FromStr ,
1820 time:: Duration ,
1921} ;
2022
2123use clap:: { error:: ErrorKind , FromArgMatches } ;
2224use monad_bls:: BlsKeyPair ;
2325use monad_chain_config:: MonadChainConfig ;
2426use monad_keystore:: keystore:: Keystore ;
25- use monad_node_config:: { ForkpointConfig , MonadNodeConfig } ;
27+ use monad_node_config:: { ForkpointConfig , MonadNodeConfig , ValidatorsConfigType } ;
2628use monad_secp:: KeyPair ;
27- use tracing:: info;
29+ use monad_types:: Round ;
30+ use reqwest:: { blocking:: Client , Url } ;
31+ use tracing:: { info, warn} ;
2832
2933use 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+
3138pub 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+
167257fn 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