Skip to content

Commit 3da12bf

Browse files
apollo_http_server: use allow new tx flag
1 parent 4a7a609 commit 3da12bf

File tree

5 files changed

+60
-12
lines changed

5 files changed

+60
-12
lines changed

crates/apollo_http_server/src/errors.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub enum HttpServerError {
2929
DecompressionError(#[from] CompressionError),
3030
#[error(transparent)]
3131
DeserializationError(#[from] serde_json::Error),
32+
#[error("Server is rejecting new transactions.")]
33+
DisabledError(),
3234
#[error(transparent)]
3335
GatewayClientError(#[from] Box<GatewayClientError>),
3436
}
@@ -41,6 +43,7 @@ impl IntoResponse for HttpServerError {
4143
}
4244
HttpServerError::DecompressionError(e) => compression_error_into_response(e),
4345
HttpServerError::DeserializationError(e) => serde_error_into_response(e),
46+
HttpServerError::DisabledError() => disabled_error_into_response(),
4447
HttpServerError::GatewayClientError(e) => gw_client_err_into_response(*e),
4548
}
4649
}
@@ -74,6 +77,19 @@ fn serde_error_into_response(err: serde_json::Error) -> Response {
7477
(response_code, response_body).into_response()
7578
}
7679

80+
fn disabled_error_into_response() -> Response {
81+
debug!("Server is configured to reject transactions.");
82+
let (response_code, starknet_error) = (
83+
StatusCode::SERVICE_UNAVAILABLE,
84+
StarknetError {
85+
code: StarknetErrorCode::UnknownErrorCode("Server unavailable.".to_string()),
86+
message: "Server unavailable.".to_string(),
87+
},
88+
);
89+
let response_body = serialize_error(&starknet_error);
90+
(response_code, response_body).into_response()
91+
}
92+
7793
fn gw_client_err_into_response(err: GatewayClientError) -> Response {
7894
let (response_code, deprecated_gateway_error) = match err {
7995
GatewayClientError::ClientError(e) => (

crates/apollo_http_server/src/http_server.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ async fn add_rpc_tx(
117117
Json(tx): Json<RpcTransaction>,
118118
) -> HttpServerResult<Json<GatewayOutput>> {
119119
debug!("ADD_TX_START: Http server received a new transaction.");
120+
121+
let dynamic_config = app_state.config_manager_client.get_http_server_dynamic_config().await?;
122+
check_new_transactions_are_allowed(dynamic_config.accept_new_txs)?;
123+
120124
ADDED_TRANSACTIONS_TOTAL.increment(1);
121125
add_tx_inner(app_state, headers, tx).await
122126
}
@@ -128,11 +132,12 @@ async fn add_tx(
128132
headers: HeaderMap,
129133
tx: String,
130134
) -> HttpServerResult<Json<GatewayOutput>> {
131-
ADDED_TRANSACTIONS_TOTAL.increment(1);
132135
debug!("ADD_TX_START: Http server received a new transaction.");
133136

134137
let dynamic_config = app_state.config_manager_client.get_http_server_dynamic_config().await?;
138+
check_new_transactions_are_allowed(dynamic_config.accept_new_txs)?;
135139

140+
ADDED_TRANSACTIONS_TOTAL.increment(1);
136141
let tx: DeprecatedGatewayTransactionV3 = match serde_json::from_str(&tx) {
137142
Ok(value) => value,
138143
Err(e) => {
@@ -154,6 +159,13 @@ async fn add_tx(
154159
add_tx_inner(app_state, headers, rpc_tx).await
155160
}
156161

162+
fn check_new_transactions_are_allowed(accept_new_txs: bool) -> HttpServerResult<()> {
163+
match accept_new_txs {
164+
true => Ok(()),
165+
false => Err(HttpServerError::DisabledError()),
166+
}
167+
}
168+
157169
#[allow(clippy::result_large_err)]
158170
fn validate_supported_tx_version_str(tx: &str) -> HttpServerResult<()> {
159171
// 1. Remove all whitespace

crates/apollo_http_server/src/http_server_test.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ async fn to_bytes(res: Response) -> Bytes {
8888
res.into_body().collect().await.unwrap().to_bytes()
8989
}
9090

91+
/// Test that an HTTP server with a `allow_new_txs = false` config rejects new transactions.
92+
#[rstest]
93+
#[tokio::test]
94+
async fn allow_new_txs() {
95+
let index = 10;
96+
let tx = rpc_invoke_tx();
97+
98+
let mock_gateway_client = MockGatewayClient::new();
99+
let mock_config_manager_client = get_mock_config_manager_client(false);
100+
101+
// TODO(Yael): avoid the hardcoded node offset index, consider dynamic allocation.
102+
let http_client =
103+
add_tx_http_client(mock_config_manager_client, mock_gateway_client, 1 + index).await;
104+
105+
// Send a transaction to the server.
106+
let response = http_client.add_tx(tx.clone()).await;
107+
let status = response.status();
108+
assert!(!status.is_success(), "{status:?}");
109+
}
110+
91111
#[tokio::test]
92112
async fn error_into_response() {
93113
let error = HttpServerError::DeserializationError(
@@ -127,7 +147,7 @@ async fn record_region_test(#[case] index: u16, #[case] tx: impl GatewayTransact
127147
.times(1)
128148
.return_const(Ok(GatewayOutput::Invoke(InvokeGatewayOutput::new(tx_hash_2))));
129149

130-
let mock_config_manager_client = get_mock_config_manager_client();
150+
let mock_config_manager_client = get_mock_config_manager_client(true);
131151
// TODO(Yael): avoid the hardcoded node offset index, consider dynamic allocation.
132152
let http_client =
133153
add_tx_http_client(mock_config_manager_client, mock_gateway_client, 1 + index).await;
@@ -162,7 +182,7 @@ async fn record_region_gateway_failing_tx(#[case] index: u16, #[case] tx: impl G
162182
)),
163183
));
164184

165-
let mock_config_manager_client = get_mock_config_manager_client();
185+
let mock_config_manager_client = get_mock_config_manager_client(true);
166186
let http_client =
167187
add_tx_http_client(mock_config_manager_client, mock_gateway_client, 3 + index).await;
168188

@@ -212,7 +232,7 @@ async fn test_response(#[case] index: u16, #[case] tx: impl GatewayTransaction)
212232
expected_internal_err,
213233
));
214234

215-
let mock_config_manager_client = get_mock_config_manager_client();
235+
let mock_config_manager_client = get_mock_config_manager_client(true);
216236
let http_client =
217237
add_tx_http_client(mock_config_manager_client, mock_gateway_client, 5 + index).await;
218238

@@ -281,7 +301,7 @@ async fn test_unsupported_tx_version(
281301
}
282302

283303
let mock_gateway_client = MockGatewayClient::new();
284-
let mock_config_manager_client = get_mock_config_manager_client();
304+
let mock_config_manager_client = get_mock_config_manager_client(true);
285305
let http_client =
286306
add_tx_http_client(mock_config_manager_client, mock_gateway_client, 9 + index).await;
287307

@@ -302,7 +322,7 @@ async fn sanitizing_error_message() {
302322
tx_object.insert("version".to_string(), Value::String(malicious_version.to_string())).unwrap();
303323

304324
let mock_gateway_client = MockGatewayClient::new();
305-
let mock_config_manager_client = get_mock_config_manager_client();
325+
let mock_config_manager_client = get_mock_config_manager_client(true);
306326
let http_client = add_tx_http_client(mock_config_manager_client, mock_gateway_client, 13).await;
307327

308328
let serialized_err =

crates/apollo_http_server/src/metrics_test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async fn add_tx_metrics_test(#[case] index: u16, #[case] tx: impl GatewayTransac
5555
)))
5656
});
5757

58-
let mock_config_manager_client = get_mock_config_manager_client();
58+
let mock_config_manager_client = get_mock_config_manager_client(true);
5959

6060
// Initialize the metrics directly instead of spawning a monitoring endpoint task.
6161
let recorder = PrometheusBuilder::new().build_recorder();
@@ -89,7 +89,7 @@ async fn add_tx_serde_failure_metrics_test() {
8989
.times(1)
9090
.return_once(move |_| Ok(success_gateway_client_output()));
9191

92-
let mock_config_manager_client = get_mock_config_manager_client();
92+
let mock_config_manager_client = get_mock_config_manager_client(true);
9393

9494
// Initialize the metrics directly instead of spawning a monitoring endpoint task.
9595
let recorder = PrometheusBuilder::new().build_recorder();

crates/apollo_http_server/src/test_utils.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,12 @@ pub fn deprecated_gateway_declare_tx() -> DeprecatedGatewayTransactionV3 {
183183
DeprecatedGatewayTransactionV3::from(declare_tx())
184184
}
185185

186-
// A mock config manager client returning the default http server dynamic config for an unlimited
187-
// number of requests.
188-
pub fn get_mock_config_manager_client() -> MockConfigManagerClient {
186+
// A mock config manager client returning the an http server dynamic config that accepts/rejects
187+
// transactions for an unlimited number of requests.
188+
pub fn get_mock_config_manager_client(accept_new_txs: bool) -> MockConfigManagerClient {
189189
let mut mock_config_manager_client = MockConfigManagerClient::new();
190190
mock_config_manager_client
191191
.expect_get_http_server_dynamic_config()
192-
.returning(move || Ok(HttpServerDynamicConfig::default()));
192+
.returning(move || Ok(HttpServerDynamicConfig { accept_new_txs, ..Default::default() }));
193193
mock_config_manager_client
194194
}

0 commit comments

Comments
 (0)