feat(watch): implement has_certificate pattern matching#994
Conversation
Add certificate-based filtering to the watch module, enabling clients to monitor transactions containing specific certificate types (stake registration, delegation, pool registration, DRep, etc). Includes tests using real mainnet delegation tx CBOR data.
📝 WalkthroughWalkthroughThis pull request adds certificate-based filtering to Cardano transaction pattern matching in both v1alpha and v1beta gRPC API versions. Helper functions compare stake credentials, pool keyhashes, and DRep hashes against certificate data. A pattern matcher dispatches by certificate type and handles wildcard cases. The new ChangesCertificate-Based Transaction Pattern Matching
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/serve/grpc/v1beta/watch.rs (1)
665-691: ⚡ Quick winConsider one negative-path test for
TxPattern.has_certificate.The current tests all assert
matches_cardano_pattern(...) == trueoncehas_certificateis set. A symmetric assertion with a deliberately mismatchingCertificatePattern(e.g.StakeDelegation { pool_keyhash: vec![0xaa; 28], .. }against this tx) would lock in the "rejecting" path throughmatches_cardano_pattern, not justmatches_certificate_pattern. It would also surface thePoolRegistrationfield-collapse behavior flagged in v1alpha if a similar pool-reg fixture is ever added.♻️ Suggested additional test
#[test] fn cardano_pattern_rejects_when_certificate_does_not_match() { let tx = decoded_tx(); let tx_pattern = u5c::cardano::TxPattern { has_certificate: Some(u5c::cardano::CertificatePattern { certificate_type: Some( u5c::cardano::certificate_pattern::CertificateType::StakeDelegation( u5c::cardano::StakeDelegationPattern { stake_credential: None, pool_keyhash: vec![0xaa; 28].into(), }, ), ), }), ..Default::default() }; assert!(!matches_cardano_pattern(&tx_pattern, &tx)); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/serve/grpc/v1beta/watch.rs` around lines 665 - 691, Add a negative-path unit test that constructs a TxPattern with has_certificate = Some(CertificatePattern { certificate_type = Some(StakeDelegation(StakeDelegationPattern { stake_credential: None, pool_keyhash: vec![0xaa; 28].into() })) }) and asserts that matches_cardano_pattern(&tx_pattern, &decoded_tx()) is false; place it alongside the existing tests (e.g. name it cardano_pattern_rejects_when_certificate_does_not_match) so it exercises matches_cardano_pattern (not just matches_certificate_pattern) and verifies a mismatching pool_keyhash is rejected.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/serve/grpc/v1alpha/watch.rs`:
- Around line 254-263: In the CertificateType::PoolRegistration match arm
(matching Cert::PoolRegistration), the pool_keyhash comparison is incorrectly
checking pat.pool_keyhash against reg.operator; update the pool_match logic so
pat.pool_keyhash is compared to reg.pool_keyhash (i.e., set pool_match =
pat.pool_keyhash.is_empty() || pat.pool_keyhash == reg.pool_keyhash) while
keeping the existing operator_match check and the final operator_match &&
pool_match return.
---
Nitpick comments:
In `@src/serve/grpc/v1beta/watch.rs`:
- Around line 665-691: Add a negative-path unit test that constructs a TxPattern
with has_certificate = Some(CertificatePattern { certificate_type =
Some(StakeDelegation(StakeDelegationPattern { stake_credential: None,
pool_keyhash: vec![0xaa; 28].into() })) }) and asserts that
matches_cardano_pattern(&tx_pattern, &decoded_tx()) is false; place it alongside
the existing tests (e.g. name it
cardano_pattern_rejects_when_certificate_does_not_match) so it exercises
matches_cardano_pattern (not just matches_certificate_pattern) and verifies a
mismatching pool_keyhash is rejected.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4d9886be-da4d-4550-be23-4de599fb6747
📒 Files selected for processing (2)
src/serve/grpc/v1alpha/watch.rssrc/serve/grpc/v1beta/watch.rs
Summary
Implements
has_certificatefiltering in the watch module'sTxPattern, as defined in the UTxO RPC spec. This enables clients to subscribe to transactions containing specific certificate types via theWatchTxgRPC stream.Both
v1alphaandv1betawatch services are updated.Certificate pattern types
StakeRegistrationStakeDeregistrationStakeDelegationPoolRegistrationPoolRetirementAnyStakeCredentialAnyPoolKeyhashAnyDrepAll pattern fields use AND logic. Empty/None fields match everything (vacuous truth), consistent with existing watch predicates (
has_address,moves_asset, etc.).Example: watch delegations to a specific pool
Test plan
9f8de766...ec465), decoded through the full pallas mapper pipelineAnyPoolKeyhash,AnyStakeCredential), empty pattern, and fullTxPatternintegrationcargo test -p dolos -- watch::tests— all passcargo checkcleangrpcurlagainstWatchTxSummary by CodeRabbit