Skip to content

Commit 5b74f8f

Browse files
committed
papyrus_base_layer: add the option to cycle the URL directly into the base layer
1 parent 0f1ffb3 commit 5b74f8f

File tree

5 files changed

+60
-12
lines changed

5 files changed

+60
-12
lines changed

crates/apollo_base_layer_tests/src/anvil_base_layer.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use alloy::sol_types::SolValue;
1010
use async_trait::async_trait;
1111
use colored::*;
1212
use papyrus_base_layer::ethereum_base_layer_contract::{
13+
CircularUrlIterator,
1314
EthereumBaseLayerConfig,
1415
EthereumBaseLayerContract,
1516
EthereumBaseLayerError,
@@ -96,14 +97,13 @@ curl -L \
9697
Starknet::deploy(anvil_client.clone()).await.unwrap();
9798

9899
let config = Self::config();
99-
let url =
100-
config.ordered_l1_endpoint_urls.first().expect("No endpoint URLs provided").clone();
100+
let url_iterator = CircularUrlIterator::new(config.ordered_l1_endpoint_urls.clone());
101101
let root_client = anvil_client.root().clone();
102102
let contract = Starknet::new(config.starknet_contract_address, root_client);
103103

104104
let anvil_base_layer = Self {
105105
anvil_provider: anvil_client.erased(),
106-
ethereum_base_layer: EthereumBaseLayerContract { config, contract, url },
106+
ethereum_base_layer: EthereumBaseLayerContract { config, contract, url_iterator },
107107
};
108108
anvil_base_layer.initialize_mocked_starknet_contract().await;
109109

@@ -229,12 +229,16 @@ impl BaseLayerContract for AnvilBaseLayer {
229229

230230
// TODO(Arni): Consider deleting this function from the trait.
231231
async fn get_url(&self) -> Result<Url, Self::Error> {
232-
Ok(self.ethereum_base_layer.url.clone())
232+
Ok(self.ethereum_base_layer.url_iterator.get_current_url())
233233
}
234234

235235
async fn set_provider_url(&mut self, _url: Url) -> Result<(), Self::Error> {
236236
unimplemented!("Anvil base layer is tied to a an Anvil server, url is fixed.")
237237
}
238+
239+
async fn cycle_provider_url(&mut self) -> Result<(), Self::Error> {
240+
unimplemented!("Anvil base layer is tied to a an Anvil server, url is fixed.")
241+
}
238242
}
239243

240244
/// Converts a given [L1 handler transaction](starknet_api::transaction::L1HandlerTransaction)

crates/papyrus_base_layer/src/base_layer_test.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use alloy::rpc::types::{Block, BlockTransactions, Header as AlloyRpcHeader};
66
use pretty_assertions::assert_eq;
77

88
use crate::ethereum_base_layer_contract::{
9+
CircularUrlIterator,
910
EthereumBaseLayerConfig,
1011
EthereumBaseLayerContract,
1112
Starknet,
@@ -25,8 +26,8 @@ fn base_layer_with_mocked_provider() -> (EthereumBaseLayerContract, Asserter) {
2526
let provider = ProviderBuilder::new().connect_mocked_client(asserter.clone()).root().clone();
2627
let contract = Starknet::new(Default::default(), provider);
2728
let config = EthereumBaseLayerConfig::default();
28-
let url = config.ordered_l1_endpoint_urls.first().expect("No endpoint URLs provided").clone();
29-
let base_layer = EthereumBaseLayerContract { contract, config, url };
29+
let url_iterator = CircularUrlIterator::new(config.ordered_l1_endpoint_urls.clone());
30+
let base_layer = EthereumBaseLayerContract { contract, config, url_iterator };
3031

3132
(base_layer, asserter)
3233
}

crates/papyrus_base_layer/src/ethereum_base_layer_contract.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,46 @@ sol!(
6565
/// L2 from this contract, which appear on the corresponding base layer.
6666
pub type StarknetL1Contract = Starknet::StarknetInstance<RootProvider, Ethereum>;
6767

68+
#[derive(Clone, Debug)]
69+
pub struct CircularUrlIterator {
70+
urls: Vec<Url>,
71+
index: usize,
72+
}
73+
74+
impl CircularUrlIterator {
75+
pub fn new(urls: Vec<Url>) -> Self {
76+
Self { urls, index: 0 }
77+
}
78+
79+
pub fn get_current_url(&self) -> Url {
80+
self.urls.get(self.index).cloned().expect("No endpoint URLs provided")
81+
}
82+
}
83+
84+
impl Iterator for CircularUrlIterator {
85+
type Item = Url;
86+
87+
fn next(&mut self) -> Option<Self::Item> {
88+
self.index = (self.index + 1) % self.urls.len();
89+
self.urls.get(self.index).cloned()
90+
}
91+
}
92+
6893
#[derive(Clone, Debug)]
6994
pub struct EthereumBaseLayerContract {
70-
pub url: Url,
95+
pub url_iterator: CircularUrlIterator,
7196
pub config: EthereumBaseLayerConfig,
7297
pub contract: StarknetL1Contract,
7398
}
7499

75100
impl EthereumBaseLayerContract {
76101
pub fn new(config: EthereumBaseLayerConfig) -> Self {
77-
let url =
78-
config.ordered_l1_endpoint_urls.first().expect("No endpoint URLs provided").clone();
79-
let contract = build_contract_instance(config.starknet_contract_address, url.clone());
80-
Self { url, contract, config }
102+
let url_iterator = CircularUrlIterator::new(config.ordered_l1_endpoint_urls.clone());
103+
let contract = build_contract_instance(
104+
config.starknet_contract_address,
105+
url_iterator.get_current_url(),
106+
);
107+
Self { url_iterator, contract, config }
81108
}
82109
}
83110

@@ -207,14 +234,19 @@ impl BaseLayerContract for EthereumBaseLayerContract {
207234
}
208235

209236
async fn get_url(&self) -> Result<Url, Self::Error> {
210-
Ok(self.url.clone())
237+
Ok(self.url_iterator.get_current_url())
211238
}
212239

213240
/// Rebuilds the provider on the new url.
214241
async fn set_provider_url(&mut self, url: Url) -> Result<(), Self::Error> {
215242
self.contract = build_contract_instance(self.config.starknet_contract_address, url.clone());
216243
Ok(())
217244
}
245+
246+
async fn cycle_provider_url(&mut self) -> Result<(), Self::Error> {
247+
self.url_iterator.next().ok_or(EthereumBaseLayerError::OrdererL1EndpointUrlsListIsEmpty)?;
248+
Ok(())
249+
}
218250
}
219251

220252
#[derive(thiserror::Error, Debug)]
@@ -233,6 +265,8 @@ pub enum EthereumBaseLayerError {
233265
TypeError(#[from] alloy::sol_types::Error),
234266
#[error("{0:?}")]
235267
UnhandledL1Event(alloy::primitives::Log),
268+
#[error("The orderer_l1_endpoint_urls list is empty")]
269+
OrdererL1EndpointUrlsListIsEmpty,
236270
}
237271

238272
impl PartialEq for EthereumBaseLayerError {

crates/papyrus_base_layer/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ pub trait BaseLayerContract {
8080

8181
async fn get_url(&self) -> Result<Url, Self::Error>;
8282
async fn set_provider_url(&mut self, url: Url) -> Result<(), Self::Error>;
83+
async fn cycle_provider_url(&mut self) -> Result<(), Self::Error>;
8384
}
8485

8586
/// Reference to an L1 block, extend as needed.

crates/papyrus_base_layer/src/monitored_base_layer.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ impl<B: BaseLayerContract + Send + Sync> BaseLayerContract for MonitoredBaseLaye
153153
.await
154154
.map_err(|err| MonitoredBaseLayerError::BaseLayerContractError(err))
155155
}
156+
157+
async fn cycle_provider_url(&mut self) -> Result<(), Self::Error> {
158+
self.get()
159+
.await?
160+
.cycle_provider_url()
161+
.await
162+
.map_err(|err| MonitoredBaseLayerError::BaseLayerContractError(err))
163+
}
156164
}
157165

158166
impl<B: BaseLayerContract + Send + Sync + std::fmt::Debug> std::fmt::Debug

0 commit comments

Comments
 (0)