Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ You can configure the proxy server via an optional `config.toml` file or command

```toml
bind_address = "0.0.0.0:8080"
upstream_url = "http://validium-sequencer:8545"
validium_url = "http://validium-sequencer:8545"
```

### Override with CLI

```sh
cargo run -- --bind-address 127.0.0.1:9000 --upstream-url http://localhost:8545
cargo run -- --bind-address 127.0.0.1:9000 --validium-url http://localhost:8545
```

### Config file path
Expand All @@ -38,7 +38,7 @@ By default, the server uses `config.toml` in the current directory. You can use

### Defaults

If not specified, `bind_address` defaults to `0.0.0.0:8080`, `upstream_url` defaults to `http://validium-sequencer:8545`.
If not specified, `bind_address` defaults to `0.0.0.0:8080`, `validium_url` defaults to `http://validium-sequencer:8545`.

### Precedence

Expand Down
7 changes: 5 additions & 2 deletions config.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# The address for the server to bind to
bind_address = "0.0.0.0:1234"

# The upstream HTTP endpoint (e.g. for forwarding requests)
upstream_url = "https://rpc.scroll.io"
# The validium RPC endpoint
validium_url = "https://rpc.scroll.io"

# The withdraw-proofs RPC endpoint
withdraw_proofs_url = "http://withdraw-proofs-service:3000"

# List of admin API tokens. Only users with these tokens can access admin functions.
admin_keys = [
Expand Down
48 changes: 34 additions & 14 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,23 @@ struct CliArgs {
#[arg(long)]
bind_address: Option<String>,

/// Upstream RPC endpoint to relay proxy requests to, e.g. http://validium-sequencer:8545
/// Validium RPC endpoint to relay proxy requests to, e.g. http://validium-sequencer:8545
#[arg(long)]
upstream_url: Option<String>,
validium_url: Option<String>,

/// Withdraw-proofs RPC endpoint to relay proxy requests to, e.g. http://cloak-withdraw-proofs:8545
#[arg(long)]
withdraw_proofs_url: Option<String>,
}

/// Structure of the config file
#[derive(Debug, serde::Deserialize)]
pub struct AppConfig {
#[serde(default = "default_bind_address")]
pub bind_address: String,
#[serde(default = "default_upstream_url")]
pub upstream_url: String,
#[serde(default = "default_validium_url")]
pub validium_url: String,
pub withdraw_proofs_url: String,
pub admin_keys: Vec<String>,
pub jwt_expiry_secs: usize,
pub default_kid: String,
Expand All @@ -35,8 +40,8 @@ fn default_bind_address() -> String {
"0.0.0.0:8080".to_owned()
}

/// Default upstream URL if not specified anywhere
fn default_upstream_url() -> String {
/// Default validium URL if not specified anywhere
fn default_validium_url() -> String {
"http://validium-sequencer:8545".to_owned()
}

Expand All @@ -53,8 +58,11 @@ pub fn load_config() -> anyhow::Result<AppConfig> {
if let Some(val) = args.bind_address {
cfg.bind_address = val;
}
if let Some(val) = args.upstream_url {
cfg.upstream_url = val;
if let Some(val) = args.validium_url {
cfg.validium_url = val;
}
if let Some(val) = args.withdraw_proofs_url {
cfg.withdraw_proofs_url = val;
}

// Validate bind_address format
Expand All @@ -67,11 +75,21 @@ pub fn load_config() -> anyhow::Result<AppConfig> {
)
})?;

// Validate upstream_url format
if !cfg.upstream_url.starts_with("http://") && !cfg.upstream_url.starts_with("https://") {
// Validate validium_url format
if !cfg.validium_url.starts_with("http://") && !cfg.validium_url.starts_with("https://") {
anyhow::bail!(
"Invalid validium_url: {}. Must start with http:// or https://",
cfg.validium_url
);
}

// Validate withdraw_proofs_url format
if !cfg.withdraw_proofs_url.starts_with("http://")
&& !cfg.withdraw_proofs_url.starts_with("https://")
{
anyhow::bail!(
"Invalid upstream_url: {}. Must start with http:// or https://",
cfg.upstream_url
"Invalid withdraw_proofs_url: {}. Must start with http:// or https://",
cfg.withdraw_proofs_url
);
}

Expand All @@ -88,7 +106,8 @@ mod tests {
// Example TOML configuration string
let toml = r#"
bind_address = "127.0.0.1:12345"
upstream_url = "http://example.com:8545"
validium_url = "http://example.com:8545"
withdraw_proofs_url = "http://example.com:8546"
admin_keys = [
"admin-token-1-abcdefg",
"admin-token-2-hijklmn"
Expand All @@ -112,7 +131,8 @@ mod tests {

// Check values
assert_eq!(cfg.bind_address, "127.0.0.1:12345");
assert_eq!(cfg.upstream_url, "http://example.com:8545");
assert_eq!(cfg.validium_url, "http://example.com:8545");
assert_eq!(cfg.withdraw_proofs_url, "http://example.com:8546");
assert_eq!(
cfg.admin_keys,
vec![
Expand Down
17 changes: 12 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ use service::{RpcLoggerMiddleware, log_request};
fn all_apis(
jwt: JwtSigner,
jwt_expiry_secs: usize,
upstream_url: &str,
validium_url: &str,
withdraw_proofs_url: &str,
) -> anyhow::Result<impl Into<Methods>> {
let auth_server = SiweAuthRpcImpl::new(jwt, jwt_expiry_secs);
let eth_proxy_server = RpcProxyImpl::new(upstream_url)?;
let scroll_proxy_server = RpcProxyImpl::new(upstream_url)?;
let eth_proxy_server = RpcProxyImpl::new(validium_url, withdraw_proofs_url)?;
let scroll_proxy_server = RpcProxyImpl::new(validium_url, withdraw_proofs_url)?;

let mut module = RpcModule::new(());
module.merge(SiweAuthRpcServer::into_rpc(auth_server))?;
Expand Down Expand Up @@ -70,9 +71,15 @@ pub async fn run_server() -> anyhow::Result<SocketAddr> {

let addr = server.local_addr()?;
info!("Server is listening on {addr}");
info!("Upstream endpoint is {}", cfg.upstream_url);
info!("Validium endpoint is {}", cfg.validium_url);
info!("Withdraw proofs endpoint is {}", cfg.withdraw_proofs_url);

let handle = server.start(all_apis(jwt, cfg.jwt_expiry_secs, &cfg.upstream_url)?);
let handle = server.start(all_apis(
jwt,
cfg.jwt_expiry_secs,
&cfg.validium_url,
&cfg.withdraw_proofs_url,
)?);
handle.stopped().await;
Ok(addr)
}
Expand Down
8 changes: 6 additions & 2 deletions src/proxy/error.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use jsonrpsee::core::ClientError;
use jsonrpsee::types::ErrorObjectOwned;
use jsonrpsee::types::error::{INTERNAL_ERROR_CODE, INTERNAL_ERROR_MSG};
use jsonrpsee::types::error::{INTERNAL_ERROR_CODE, INTERNAL_ERROR_MSG, INVALID_REQUEST_CODE};

pub fn unauthorized() -> ErrorObjectOwned {
ErrorObjectOwned::owned(INTERNAL_ERROR_CODE, "unauthorized", Some("unauthorized"))
ErrorObjectOwned::owned(INVALID_REQUEST_CODE, "unauthorized", Some("unauthorized"))
}

pub fn internal_error(msg: impl AsRef<str>) -> ErrorObjectOwned {
ErrorObjectOwned::owned(INTERNAL_ERROR_CODE, "internal_error", Some(msg.as_ref()))
}

pub fn proxy_call_failed(e: ClientError) -> ErrorObjectOwned {
Expand Down
21 changes: 21 additions & 0 deletions src/proxy/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,23 @@ use alloy_rpc_types::{
};
use jsonrpsee::core::RpcResult;
use scroll_alloy_rpc_types::{ScrollTransactionReceipt as Receipt, Transaction};
use serde::{Deserialize, Serialize};

pub type Block = EthBlock<Transaction>;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Withdrawal {
pub tx_hash: B256,
pub message_hash: B256,
pub from: Address,
pub to: Address,
pub value: U256,
pub nonce: u64,
pub message: Bytes,
pub batch_index: u64,
pub proof: Bytes,
}

#[rpc(server, client, namespace = "scroll")]
pub trait ScrollRpcProxy {
#[method(name = "getL1MessagesInBlock", with_extensions)]
Expand All @@ -19,6 +33,13 @@ pub trait ScrollRpcProxy {
block_id: String,
mode: String,
) -> RpcResult<Option<Vec<Transaction>>>;

#[method(name = "withdrawalsByTransaction", with_extensions)]
async fn withdrawals_by_transaction(&self, tx_hash: B256) -> RpcResult<Vec<Withdrawal>>;

#[method(name = "withdrawalByMessageHash", with_extensions)]
async fn withdrawal_by_message_hash(&self, message_hash: B256)
-> RpcResult<Option<Withdrawal>>;
}

// see https://github.com/paradigmxyz/reth/blob/main/crates/rpc/rpc-eth-api/src/core.rs
Expand Down
Loading
Loading