-
Notifications
You must be signed in to change notification settings - Fork 677
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
Fix/observer filters #5570
base: develop
Are you sure you want to change the base?
Fix/observer filters #5570
Conversation
@@ -320,7 +322,7 @@ impl RewardSetEventPayload { | |||
} | |||
|
|||
#[cfg(test)] | |||
static TEST_EVENT_OBSERVER_SKIP_RETRY: std::sync::Mutex<Option<bool>> = std::sync::Mutex::new(None); | |||
thread_local! { static TEST_EVENT_OBSERVER_SKIP_RETRY: RefCell<bool> = RefCell::new(false); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to use Cell
here instead of RefCell
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also can you add doc comment to this variable? Skip retry of what? I'm not familiar with this code so I don't know
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, why does it have to be thread-local? If it doesn't have to be thread-local, can we just use the TestFlag
struct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hstove tests are executed in parallel so there is a race condition between the set and clear of TEST_EVENT_OBSERVER_SKIP_RETRY (this caused the 3 related tests to often fail when executed together)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah that makes sense, thanks!
.unwrap() | ||
.unwrap_or(false) | ||
{ | ||
if TEST_EVENT_OBSERVER_SKIP_RETRY.with(|v| *v.borrow()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pervasively, instead of testing a global variable container for a global that should only be compiled for test code, can you create a helper function with an informative name, and a test and non-test body? Like this:
use std::sync::LazyLock;
use crate::run_loop::neon::TestFlag;
const TEST_EVENT_OBSERVER_SKIP_RETRY : LazyLock<TestFlag> = LazyLock::new(Testflag::default);
/// Add a helpful docstring here
#[cfg(any(test, feature = "testing"))]
fn fault_injection_skip_observer_entry() -> bool {
TEST_EVENT_OBSERVER_SKIP_RETRY.get()
}
#[cfg(not(any(test, feature = "testing")))]
fn fault_injection_skip_observer_entry() -> bool {
false
}
@@ -1272,6 +1266,12 @@ impl EventDispatcher { | |||
block_timestamp: Option<u64>, | |||
coinbase_height: u64, | |||
) { | |||
let interested_observers = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this get passed into create_dispatch_matrix_and_event_vector
? and used there? Otherwise, I think this is still sending to observers that should have been filtered out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I think this new code can just be removed.
@@ -1592,7 +1592,8 @@ impl EventDispatcher { | |||
} | |||
|
|||
pub fn process_new_attachments(&self, attachments: &[(AttachmentInstance, Attachment)]) { | |||
let interested_observers: Vec<_> = self.registered_observers.iter().enumerate().collect(); | |||
let interested_observers = self.filter_observers(&self.mempool_observers_lookup, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is the correct hash set to use for attachment events. None of the others look like a better option either. Maybe we should use any_event_observers_lookup
, or maybe we should add a new one. I'm not entirely sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The specific issue (from the sbtc team that is actively using the event system) is about this /attachments/new event. Can we have a new event id dedicated to it?
let interested_observers = | ||
self.filter_observers(&self.block_proposal_observers_lookup, true); | ||
if interested_observers.is_empty() { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrong filter here - you're filtering for only the block_proposal
listeners, but this is for /new_block
. Also, there isn't a filter for /new_block
- it's sent by default (and needs to stay that way to be backwards compatible).
let interested_observers: Vec<_> = self.registered_observers.iter().enumerate().collect(); | ||
let interested_observers = self.filter_observers(&self.mempool_observers_lookup, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be another copy/paste bug. There doesn't actually appear to be an attachments event key. I think it's best to probably filter for only the *
event key here (self.any_event_observers_lookup
), but I'm actually not sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jinx
} | ||
|
||
#[test] | ||
fn test_event_dispatcher_tx_filtering_wrong() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add short comments above these tests? It takes me a bit to register exactly what's being tested in each of these. The code is good, it's just helpful to have a short explainer.
// Create a mock server | ||
let mut server = mockito::Server::new(); | ||
let _m = server | ||
.mock("POST", "/new_mempool_tx") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I mentioned above - I think we need to always send /new_block
proposals, so this test might be moot. Regardless, the path here should be /new_block
.
Assuming we do make it so that /new_block
is always sent, it would be good to modify this test such that we ensure /new_block
is called event with an empty event_keys
.
This brings up an interesting discussion about undocumented behavior here, and whether it's ok to break it. Regarding Regarding |
@hstove IMHO it seems a bit weird to expose a filtering system that cannot filter a bunch of events. What about some form of workaround that explicitely disables the new_block event (something like "!new_block")? |
Thanks for flagging @hstove. Yes it's common for API observers to use the Please do not break backward compatibility with these! |
From the sprint call: There's a case to be made for dropping support (deprecating) the current filter system and add a new opt-in filter system (this PR) where every event must be opted into. We get rid of the If both the old and new filters are configured, then the node errors out (the config file is invalid). When this PR merges, we treat the old filter system as depreciated (add this to the changelog please). One extensible option is to add the actual URL path instead of event keys. |
Description
This patch fixes the observer filtering system and adds tests for it.
Note that the patch includes a little change for fixing a race condition with 3 of the tests using the TEST_EVENT_OBSERVER_SKIP_RETRY variable (that was static and now is a thread local one)
Applicable issues
event_keys
is configured #5558Additional info (benefits, drawbacks, caveats)
Checklist
docs/rpc/openapi.yaml
andrpc-endpoints.md
for v2 endpoints,event-dispatcher.md
for new events)clarity-benchmarking
repobitcoin-tests.yml