Skip to content

Commit d5d036a

Browse files
committed
fix: allow specification of multiple rpc endpoints
This fix introduces a breaking change to configuration, where instead of a single remote, it's now possible to specify multiple. Only the first one will be used for HTTP requests, but all of them will be used to load balance websocket subscriptions.
1 parent 5da3bf9 commit d5d036a

23 files changed

+56
-50
lines changed

magicblock-accounts/src/accounts_manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl AccountsManager {
3636
validator_keypair: Keypair,
3737
config: AccountsConfig,
3838
) -> AccountsResult<Self> {
39-
let remote_cluster = config.remote_cluster;
39+
let remote_cluster = config.remote_clusters[0].clone();
4040
let internal_account_provider = BankAccountProvider::new(bank.clone());
4141
let rpc_cluster = try_rpc_cluster_from_cluster(&remote_cluster)?;
4242
let rpc_client = RpcClient::new_with_commitment(

magicblock-accounts/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use solana_sdk::pubkey::Pubkey;
66

77
#[derive(Debug, PartialEq, Eq)]
88
pub struct AccountsConfig {
9-
pub remote_cluster: Cluster,
9+
pub remote_clusters: Vec<Cluster>,
1010
pub lifecycle: LifecycleMode,
1111
pub commit_compute_unit_price: u64,
1212
pub payer_init_lamports: Option<u64>,

magicblock-api/src/external_config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub(crate) fn try_convert_accounts_config(
88
conf: &magicblock_config::AccountsConfig,
99
) -> ConfigResult<AccountsConfig> {
1010
Ok(AccountsConfig {
11-
remote_cluster: cluster_from_remote(&conf.remote),
11+
remote_clusters: conf.remotes.iter().map(cluster_from_remote).collect(),
1212
lifecycle: lifecycle_mode_from_lifecycle_mode(&conf.lifecycle),
1313
commit_compute_unit_price: conf.commit.compute_unit_price,
1414
payer_init_lamports: conf.payer.try_init_lamports()?,

magicblock-api/src/magic_validator.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use magicblock_account_updates::{
2424
RemoteAccountUpdatesClient, RemoteAccountUpdatesWorker,
2525
};
2626
use magicblock_accounts::{
27-
utils::try_rpc_cluster_from_cluster, AccountsManager,
27+
errors::AccountsError, utils::try_rpc_cluster_from_cluster, AccountsManager,
2828
};
2929
use magicblock_accounts_api::BankAccountProvider;
3030
use magicblock_accounts_db::{
@@ -262,21 +262,22 @@ impl MagicValidator {
262262
try_convert_accounts_config(&config.validator_config.accounts)
263263
.map_err(ApiError::ConfigError)?;
264264

265-
let remote_rpc_config = RpcProviderConfig::new(
266-
try_rpc_cluster_from_cluster(&accounts_config.remote_cluster)?,
267-
Some(CommitmentLevel::Confirmed),
268-
);
265+
let remote_rpc_configs = accounts_config
266+
.remote_clusters
267+
.iter()
268+
.map(|c| {
269+
Ok(RpcProviderConfig::new(
270+
try_rpc_cluster_from_cluster(c)?,
271+
Some(CommitmentLevel::Confirmed),
272+
))
273+
})
274+
.collect::<Result<Vec<_>, AccountsError>>()?;
269275

270276
let remote_account_fetcher_worker =
271-
RemoteAccountFetcherWorker::new(remote_rpc_config.clone());
277+
RemoteAccountFetcherWorker::new(remote_rpc_configs[0].clone());
272278

273279
let remote_account_updates_worker = RemoteAccountUpdatesWorker::new(
274-
// We'll maintain 3 connections constantly (those could be on different nodes if we wanted to)
275-
vec![
276-
remote_rpc_config.clone(),
277-
remote_rpc_config.clone(),
278-
remote_rpc_config.clone(),
279-
],
280+
remote_rpc_configs,
280281
// We'll kill/refresh one connection every 50 minutes
281282
Duration::from_secs(60 * 50),
282283
);
@@ -583,7 +584,7 @@ impl MagicValidator {
583584
&self,
584585
fdqn: impl ToString,
585586
) -> ApiResult<()> {
586-
let url = cluster_from_remote(&self.config.accounts.remote);
587+
let url = cluster_from_remote(&self.config.accounts.remotes[0]);
587588
let country_code =
588589
CountryCode::from(self.config.validator.country_code.alpha3());
589590
let validator_keypair = validator_authority();
@@ -609,7 +610,7 @@ impl MagicValidator {
609610
}
610611

611612
fn unregister_validator_on_chain(&self) -> ApiResult<()> {
612-
let url = cluster_from_remote(&self.config.accounts.remote);
613+
let url = cluster_from_remote(&self.config.accounts.remotes[0]);
613614
let validator_keypair = validator_authority();
614615

615616
DomainRegistryManager::handle_unregistration_static(

magicblock-config/src/accounts.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::errors::{ConfigError, ConfigResult};
1818
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
1919
pub struct AccountsConfig {
2020
#[serde(default)]
21-
pub remote: RemoteConfig,
21+
pub remotes: Vec<RemoteConfig>,
2222
#[serde(default)]
2323
pub lifecycle: LifecycleMode,
2424
#[serde(default)]
@@ -38,7 +38,7 @@ pub struct AccountsConfig {
3838
impl Default for AccountsConfig {
3939
fn default() -> Self {
4040
Self {
41-
remote: Default::default(),
41+
remotes: vec![Default::default()],
4242
lifecycle: Default::default(),
4343
commit: Default::default(),
4444
payer: Default::default(),

magicblock-config/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl EphemeralConfig {
9595
// -----------------
9696
if let Ok(http) = env::var("ACCOUNTS_REMOTE") {
9797
if let Ok(ws) = env::var("ACCOUNTS_REMOTE_WS") {
98-
config.accounts.remote = RemoteConfig::CustomWithWs(
98+
config.accounts.remotes = vec![RemoteConfig::CustomWithWs(
9999
Url::parse(&http)
100100
.map_err(|err| {
101101
panic!(
@@ -112,9 +112,9 @@ impl EphemeralConfig {
112112
)
113113
})
114114
.unwrap(),
115-
);
115+
)];
116116
} else {
117-
config.accounts.remote = RemoteConfig::Custom(
117+
config.accounts.remotes = vec![RemoteConfig::Custom(
118118
Url::parse(&http)
119119
.map_err(|err| {
120120
panic!(
@@ -123,7 +123,7 @@ impl EphemeralConfig {
123123
)
124124
})
125125
.unwrap(),
126-
);
126+
)];
127127
}
128128
}
129129

magicblock-config/tests/parse_config.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,9 @@ fn test_custom_remote_toml() {
131131
config,
132132
EphemeralConfig {
133133
accounts: AccountsConfig {
134-
remote: RemoteConfig::Custom(
134+
remotes: vec![RemoteConfig::Custom(
135135
Url::parse("http://localhost:8899").unwrap()
136-
),
136+
)],
137137
..Default::default()
138138
},
139139
..Default::default()
@@ -150,10 +150,10 @@ fn test_custom_ws_remote_toml() {
150150
config,
151151
EphemeralConfig {
152152
accounts: AccountsConfig {
153-
remote: RemoteConfig::CustomWithWs(
153+
remotes: vec![RemoteConfig::CustomWithWs(
154154
Url::parse("http://localhost:8899").unwrap(),
155155
Url::parse("ws://localhost:9001").unwrap()
156-
),
156+
)],
157157
..Default::default()
158158
},
159159
..Default::default()

magicblock-config/tests/read_config.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,9 @@ fn test_load_local_dev_with_programs_toml_envs_override() {
115115
frequency_millis: 123,
116116
compute_unit_price: 1,
117117
},
118-
remote: RemoteConfig::Custom(Url::parse(base_cluster).unwrap()),
118+
remotes: vec![RemoteConfig::Custom(
119+
Url::parse(base_cluster).unwrap()
120+
)],
119121
..Default::default()
120122
},
121123
programs: vec![ProgramConfig {
@@ -158,10 +160,10 @@ fn test_load_local_dev_with_programs_toml_envs_override() {
158160
let config = config.override_from_envs();
159161

160162
assert_eq!(
161-
config.accounts.remote,
162-
RemoteConfig::CustomWithWs(
163+
config.accounts.remotes,
164+
vec![RemoteConfig::CustomWithWs(
163165
base_cluster.parse().unwrap(),
164166
base_cluster_ws.parse().unwrap()
165-
)
167+
)]
166168
);
167169
}

test-integration/configs/cloning-conf.devnet.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[accounts]
2-
remote = "devnet"
2+
remotes = ["devnet"]
33
lifecycle = "offline"
44
commit = { frequency_millis = 9_000_000_000_000, compute_unit_price = 1_000_000 }
55

test-integration/configs/cloning-conf.ephem.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[accounts]
2-
remote = "http://0.0.0.0:7799"
2+
remotes = ["http://0.0.0.0:7799"]
33
lifecycle = "ephemeral"
44
commit = { frequency_millis = 500_000, compute_unit_price = 1_000_000 }
55
max-monitored-accounts = 3

test-integration/configs/luzid-devtool.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "Devtool:8899"
33

44
[node.accounts]
5-
remote = "devnet"
5+
remotes = ["devnet"]
66
lifecycle = "offline"
77
commit = { frequency_millis = 9_000_000_000_000, compute_unit_price = 1_000_000 }
88

test-integration/configs/luzid-offline.devnet.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "Devnet:7799"
33

44
[node.accounts]
5-
remote = "devnet"
5+
remotes = ["devnet"]
66
lifecycle = "offline"
77
commit = { frequency_millis = 9_000_000_000_000, compute_unit_price = 1_000_000 }
88

test-integration/configs/luzid-schedulecommit-conf.devnet.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "Devnet:7799"
33

44
[node.accounts]
5-
remote = "devnet"
5+
remotes = ["devnet"]
66
lifecycle = "offline"
77
commit = { frequency_millis = 9_000_000_000_000, compute_unit_price = 1_000_000 }
88

test-integration/configs/luzid-schedulecommit-conf.ephem.frequent-commits.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "Ephem:8899"
33

44
[node.accounts]
5-
remote = "http://0.0.0.0:7799"
5+
remotes = ["http://0.0.0.0:7799"]
66
lifecycle = "ephemeral"
77
commit = { frequency_millis = 60, compute_unit_price = 1_000_000 }
88

test-integration/configs/luzid-schedulecommit-conf.ephem.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "Ephem:8899"
33

44
[node.accounts]
5-
remote = "http://0.0.0.0:7799"
5+
remotes = ["http://0.0.0.0:7799"]
66
lifecycle = "ephemeral"
77
commit = { frequency_millis = 500_000, compute_unit_price = 1_000_000 }
88

test-integration/configs/restore-ledger-conf.devnet.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[accounts]
2-
remote = "devnet"
2+
remotes = ["devnet"]
33
lifecycle = "offline"
44
commit = { frequency_millis = 9_000_000_000_000, compute_unit_price = 1_000_000 }
55

test-integration/configs/schedulecommit-conf-fees.ephem.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[accounts]
2-
remote = "http://0.0.0.0:7799"
2+
remotes = ["http://0.0.0.0:7799"]
33
lifecycle = "ephemeral"
44
commit = { frequency_millis = 500_000, compute_unit_price = 1_000_000 }
55

test-integration/configs/schedulecommit-conf.devnet.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[accounts]
2-
remote = "devnet"
2+
remotes = ["devnet"]
33
lifecycle = "offline"
44
commit = { frequency_millis = 9_000_000_000_000, compute_unit_price = 1_000_000 }
55

test-integration/configs/schedulecommit-conf.ephem.frequent-commits.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[accounts]
2-
remote = "http://0.0.0.0:7799"
2+
remotes = ["http://0.0.0.0:7799"]
33
lifecycle = "ephemeral"
44
# NOTE: we'd be committing almost every slot here if we didn't detect when
55
# a commit is not needed

test-integration/configs/schedulecommit-conf.ephem.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[accounts]
2-
remote = "http://0.0.0.0:7799"
2+
remotes = ["http://0.0.0.0:7799"]
33
lifecycle = "ephemeral"
44
commit = { frequency_millis = 500_000, compute_unit_price = 1_000_000 }
55

test-integration/configs/validator-offline.devnet.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[accounts]
2-
remote = "devnet"
2+
remotes = ["devnet"]
33
lifecycle = "offline"
44
commit = { frequency_millis = 9_000_000_000_000, compute_unit_price = 1_000_000 }
55

test-integration/test-ledger-restore/src/lib.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use integration_test_tools::{
1111
workspace_paths::path_relative_to_workspace,
1212
IntegrationTestContext,
1313
};
14-
use magicblock_config::{AccountsConfig, EphemeralConfig, LedgerConfig, LifecycleMode, ProgramConfig, RemoteConfig, ValidatorConfig, DEFAULT_LEDGER_SIZE_BYTES};
14+
use magicblock_config::{
15+
AccountsConfig, EphemeralConfig, LedgerConfig, LifecycleMode,
16+
ProgramConfig, RemoteConfig, ValidatorConfig, DEFAULT_LEDGER_SIZE_BYTES,
17+
};
1518
use program_flexi_counter::state::FlexiCounter;
1619
use solana_sdk::{
1720
clock::Slot,
@@ -104,7 +107,7 @@ pub fn setup_offline_validator(
104107
ledger: LedgerConfig {
105108
reset,
106109
path: Some(ledger_path.display().to_string()),
107-
size: DEFAULT_LEDGER_SIZE_BYTES
110+
size: DEFAULT_LEDGER_SIZE_BYTES,
108111
},
109112
accounts: accounts_config.clone(),
110113
programs,
@@ -132,9 +135,9 @@ pub fn setup_validator_with_local_remote(
132135
) -> (TempDir, Child, IntegrationTestContext) {
133136
let mut accounts_config = AccountsConfig {
134137
lifecycle: LifecycleMode::Ephemeral,
135-
remote: RemoteConfig::Custom(
138+
remotes: vec![RemoteConfig::Custom(
136139
IntegrationTestContext::url_chain().try_into().unwrap(),
137-
),
140+
)],
138141
..Default::default()
139142
};
140143
accounts_config.db.snapshot_frequency = 2;

test-integration/test-tools/src/toml_to_args.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct Config {
1616

1717
#[derive(Deserialize)]
1818
struct RemoteConfig {
19-
remote: String,
19+
remotes: Vec<String>,
2020
}
2121

2222
#[derive(Deserialize)]
@@ -97,7 +97,7 @@ pub fn config_to_args(
9797
}
9898
}
9999
args.push("--url".into());
100-
args.push(config.accounts.remote);
100+
args.push(config.accounts.remotes[0].clone());
101101

102102
args
103103
}

0 commit comments

Comments
 (0)