Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: skip sending pending payload if URL doesn't match #5834

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE
- Logging improvements:
- P2P logs now includes a reason for dropping a peer or neighbor
- Improvements to how a PeerAddress is logged (human readable format vs hex)
- Pending event dispatcher requests will no longer be sent to URLs that are no longer registered as event observers ([#5834](https://github.com/stacks-network/stacks-core/pull/5834))

### Fixed

Expand Down
67 changes: 61 additions & 6 deletions testnet/stacks-node/src/event_dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ impl EventObserver {
Ok(())
}

fn process_pending_payloads(conn: &Connection) {
fn process_pending_payloads(&self, conn: &Connection) {
let pending_payloads = match Self::get_pending_payloads(conn) {
Ok(payloads) => payloads,
Err(e) => {
Expand All @@ -438,6 +438,10 @@ impl EventObserver {
};

for (id, url, payload, timeout_ms) in pending_payloads {
// If the URL is not the same as the endpoint, skip it
if !url.starts_with(&self.endpoint) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is starts_with sufficient here? We should probably be more explicit so that it handles a case where the DB contains the URL "http://localhost:8000/foo" and this EventObserver has the endpoint "http://localhost:80".

continue;
}
let timeout = Duration::from_millis(timeout_ms);
Self::send_payload_directly(&payload, &url, timeout);

Expand Down Expand Up @@ -563,7 +567,7 @@ impl EventObserver {
Self::insert_payload_with_retry(&conn, &full_url, payload, self.timeout);

// Process all pending payloads
Self::process_pending_payloads(&conn);
self.process_pending_payloads(&conn);
} else {
// No database, just send the payload
Self::send_payload_directly(payload, &full_url, self.timeout);
Expand Down Expand Up @@ -2042,16 +2046,19 @@ mod test {
use mockito::Matcher;

let dir = tempdir().unwrap();
let db_path = dir.path().join("test_process_payloads.sqlite");
let db_path = dir.path().join("event_observers.sqlite");
let db_path_str = db_path.to_str().unwrap();
let mut server = mockito::Server::new();
let endpoint = server.url().to_string();
let timeout = Duration::from_secs(5);
let observer =
EventObserver::new(Some(dir.path().to_path_buf()), endpoint.clone(), timeout);

let conn = EventObserver::init_db(db_path_str).expect("Failed to initialize the database");

let payload = json!({"key": "value"});
let timeout = Duration::from_secs(5);

// Create a mock server
let mut server = mockito::Server::new();
let _m = server
.mock("POST", "/api")
.match_header("content-type", Matcher::Regex("application/json.*".into()))
Expand All @@ -2068,7 +2075,7 @@ mod test {
.expect("Failed to insert payload");

// Process pending payloads
EventObserver::process_pending_payloads(&conn);
observer.process_pending_payloads(&conn);

// Verify that the pending payloads list is empty
let pending_payloads =
Expand All @@ -2079,6 +2086,54 @@ mod test {
_m.assert();
}

#[test]
fn pending_payloads_are_skipped_if_url_does_not_match() {
let dir = tempdir().unwrap();
let db_path = dir.path().join("event_observers.sqlite");
let db_path_str = db_path.to_str().unwrap();

let mut server = mockito::Server::new();
let endpoint = server.url().to_string();
let timeout = Duration::from_secs(5);
let observer =
EventObserver::new(Some(dir.path().to_path_buf()), endpoint.clone(), timeout);

let conn = EventObserver::init_db(db_path_str).expect("Failed to initialize the database");

let payload = json!({"key": "value"});
let timeout = Duration::from_secs(5);

let mock = server
.mock("POST", "/api")
.match_header(
"content-type",
mockito::Matcher::Regex("application/json.*".into()),
)
.match_body(mockito::Matcher::Json(payload.clone()))
.with_status(200)
.expect(0) // Expect 0 calls to this endpoint
.create();

// Use a different URL than the observer's endpoint
let url = "http://different-domain.com/api";

EventObserver::insert_payload(&conn, url, &payload, timeout)
.expect("Failed to insert payload");

observer.process_pending_payloads(&conn);

let pending_payloads =
EventObserver::get_pending_payloads(&conn).expect("Failed to get pending payloads");
// Verify that the pending payload is still in the database
assert_eq!(
pending_payloads.len(),
1,
"Expected payload to remain in database since URL didn't match"
);

mock.assert();
}

#[test]
fn test_new_event_observer_with_db() {
let dir = tempdir().unwrap();
Expand Down
Loading