From e3189395671c9552626d99e821f9244a55af84e7 Mon Sep 17 00:00:00 2001 From: Matteo Almanza Date: Thu, 9 Jan 2025 19:27:23 +0100 Subject: [PATCH 1/3] fix: increase the event observer max body size --- signer/src/api/new_block.rs | 63 +++++++++++++++++++++++++++++++++++++ signer/src/api/router.rs | 7 ++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/signer/src/api/new_block.rs b/signer/src/api/new_block.rs index 8c43c242a..abe8a4018 100644 --- a/signer/src/api/new_block.rs +++ b/signer/src/api/new_block.rs @@ -51,6 +51,15 @@ use super::SBTC_REGISTRY_CONTRACT_NAME; /// See https://github.com/stacks-network/sbtc/issues/501. static SBTC_REGISTRY_IDENTIFIER: OnceLock = OnceLock::new(); +/// Maximum request body size for the event observer endpoint. +/// +/// Stacks blocks have a limit of 2 MB, which is enforced at the p2p level, but +/// event observer events can be larger than that since they contain the +/// subscribed sbtc events. Luckily, the size of the sbtc events themselves are +/// bounded by the size of the transactions that create them, so a limit of 8 MB +/// will be fine since it is twice as high as required. +pub const EVENT_OBSERVER_BODY_LIMIT: usize = 8 * 1024 * 1024; + /// An enum representing the result of the event processing. /// This is used to send the results of the events to Emily. enum UpdateResult { @@ -401,6 +410,9 @@ async fn handle_key_rotation( mod tests { use super::*; + use axum::body::Body; + use axum::http::Method; + use axum::http::Request; use bitcoin::OutPoint; use bitvec::array::BitArray; use clarity::vm::types::PrincipalData; @@ -411,7 +423,9 @@ mod tests { use rand::SeedableRng as _; use secp256k1::SECP256K1; use test_case::test_case; + use tower::ServiceExt; + use crate::api::get_router; use crate::storage::in_memory::Store; use crate::storage::model::DepositRequest; use crate::storage::model::ScriptPubKey; @@ -914,4 +928,53 @@ mod tests { assert_eq!(db.rotate_keys_transactions.len(), 1); assert!(db.rotate_keys_transactions.get(&txid).is_some()); } + + #[test_case(EVENT_OBSERVER_BODY_LIMIT, true; "event within limit")] + #[test_case(EVENT_OBSERVER_BODY_LIMIT+1, false; "event over limit")] + #[tokio::test] + async fn test_big_event(event_size: usize, success: bool) { + let mut ctx = TestContext::builder() + .with_in_memory_storage() + .with_mocked_clients() + .build(); + + ctx.with_emily_client(|client| { + client.expect_update_deposits().returning(move |_| { + Box::pin(async { Ok(UpdateDepositsResponse { deposits: vec![] }) }) + }); + client.expect_update_withdrawals().returning(move |_| { + Box::pin(async { Ok(UpdateWithdrawalsResponse { withdrawals: vec![] }) }) + }); + client + .expect_create_withdrawals() + .returning(move |_| Box::pin(async { vec![] })); + }) + .await; + + let state = ApiState { ctx: ctx.clone() }; + let app = get_router().with_state(state); + + let db = ctx.inner_storage(); + // We don't have anything here yet + assert!(db.lock().await.rotate_keys_transactions.is_empty()); + + let mut event: String = " ".repeat(event_size - ROTATE_KEYS_WEBHOOK.len()); + event.push_str(ROTATE_KEYS_WEBHOOK); + + let request = Request::builder() + .uri("/new_block") + .method(Method::POST) + .body(Body::from(event)) + .unwrap(); + + let response = app.oneshot(request).await.unwrap(); + + if success { + assert_eq!(response.status(), StatusCode::OK); + assert!(!db.lock().await.rotate_keys_transactions.is_empty()); + } else { + assert_eq!(response.status(), StatusCode::PAYLOAD_TOO_LARGE); + assert!(db.lock().await.rotate_keys_transactions.is_empty()); + } + } } diff --git a/signer/src/api/router.rs b/signer/src/api/router.rs index bfb37b8b6..57d74bc4f 100644 --- a/signer/src/api/router.rs +++ b/signer/src/api/router.rs @@ -2,6 +2,7 @@ //! use axum::{ + extract::DefaultBodyLimit, routing::{get, post}, Router, }; @@ -20,7 +21,11 @@ async fn new_attachment_handler() -> StatusCode { pub fn get_router() -> Router> { Router::new() .route("/", get(status::status_handler)) - .route("/new_block", post(new_block::new_block_handler)) + .route( + "/new_block", + post(new_block::new_block_handler) + .layer(DefaultBodyLimit::max(new_block::EVENT_OBSERVER_BODY_LIMIT)), + ) // TODO: remove this once https://github.com/stacks-network/stacks-core/issues/5558 // is addressed .route("/attachments/new", post(new_attachment_handler)) From ee6aefd28390bc75be20b1d95b9ca63ebcdd7d1e Mon Sep 17 00:00:00 2001 From: Matteo Almanza Date: Thu, 9 Jan 2025 19:44:45 +0100 Subject: [PATCH 2/3] chore: add missing codegen(?) --- .../emily/client/rust/private/src/apis/deposit_api.rs | 1 + .../emily/client/rust/public/src/apis/deposit_api.rs | 1 + .../emily/client/rust/testing/src/apis/deposit_api.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/.generated-sources/emily/client/rust/private/src/apis/deposit_api.rs b/.generated-sources/emily/client/rust/private/src/apis/deposit_api.rs index ed7f027a9..439a89209 100644 --- a/.generated-sources/emily/client/rust/private/src/apis/deposit_api.rs +++ b/.generated-sources/emily/client/rust/private/src/apis/deposit_api.rs @@ -20,6 +20,7 @@ pub enum CreateDepositError { Status400(models::ErrorResponse), Status404(models::ErrorResponse), Status405(models::ErrorResponse), + Status409(models::ErrorResponse), Status500(models::ErrorResponse), UnknownValue(serde_json::Value), } diff --git a/.generated-sources/emily/client/rust/public/src/apis/deposit_api.rs b/.generated-sources/emily/client/rust/public/src/apis/deposit_api.rs index ed7f027a9..439a89209 100644 --- a/.generated-sources/emily/client/rust/public/src/apis/deposit_api.rs +++ b/.generated-sources/emily/client/rust/public/src/apis/deposit_api.rs @@ -20,6 +20,7 @@ pub enum CreateDepositError { Status400(models::ErrorResponse), Status404(models::ErrorResponse), Status405(models::ErrorResponse), + Status409(models::ErrorResponse), Status500(models::ErrorResponse), UnknownValue(serde_json::Value), } diff --git a/.generated-sources/emily/client/rust/testing/src/apis/deposit_api.rs b/.generated-sources/emily/client/rust/testing/src/apis/deposit_api.rs index ed7f027a9..439a89209 100644 --- a/.generated-sources/emily/client/rust/testing/src/apis/deposit_api.rs +++ b/.generated-sources/emily/client/rust/testing/src/apis/deposit_api.rs @@ -20,6 +20,7 @@ pub enum CreateDepositError { Status400(models::ErrorResponse), Status404(models::ErrorResponse), Status405(models::ErrorResponse), + Status409(models::ErrorResponse), Status500(models::ErrorResponse), UnknownValue(serde_json::Value), } From 399a4b33671d292c6c528b35d5195dd87f8fbc58 Mon Sep 17 00:00:00 2001 From: Matteo Almanza Date: Thu, 9 Jan 2025 21:20:18 +0100 Subject: [PATCH 3/3] chore: fmt --- signer/src/api/new_block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/src/api/new_block.rs b/signer/src/api/new_block.rs index abe8a4018..a8e834ccb 100644 --- a/signer/src/api/new_block.rs +++ b/signer/src/api/new_block.rs @@ -930,7 +930,7 @@ mod tests { } #[test_case(EVENT_OBSERVER_BODY_LIMIT, true; "event within limit")] - #[test_case(EVENT_OBSERVER_BODY_LIMIT+1, false; "event over limit")] + #[test_case(EVENT_OBSERVER_BODY_LIMIT + 1, false; "event over limit")] #[tokio::test] async fn test_big_event(event_size: usize, success: bool) { let mut ctx = TestContext::builder()