Repository navigation
Conversation
rs-dapi dedupes the raw transactions it streams to a subscription by txid. From protocol version 15 Platform emits asset unlocks with payload version 2, whose txid leaves out the request height, quorum hash and signature, so every instance Platform re-signs after an expiry shares one txid. Core relays each instance, but a subscriber that received an earlier one never received the refreshed one, nor the one that was mined, and kept a stale signature (review of #5634, finding 5). A transaction is now marked delivered by txid, still used by instant locks and merkle blocks, and, when its instance hash (rust-dashcore's Transaction::instance_hash, the hash of the full serialization) differs from its txid, also by that instance hash. Raw transactions are deduped by instance on the live, mempool and history paths. The instance set fills only for stable-txid asset unlocks, so per-stream memory for other transactions is unchanged. Tests: - should_stream_every_instance_of_a_re_signed_asset_unlock: two instances of one version 2 asset unlock, then the first again, through flush_transaction_pending. Before the fix only the first instance reached the subscriber; after it both do, once each, and the txid is still found as delivered. - should_not_stream_again_the_asset_unlock_instances_a_replay_delivered: instances a history replay delivered are skipped live; a new instance is not. Test would have caught this in CI: ✖ before fix, ✔ after. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
|
Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post |
|
✅ Final review complete — no blockers (commit 45e4c9d) · triage: normal |
thepastaclaw
left a comment
There was a problem hiding this comment.
Final validation — Phase 1 + Phase 2
At head 393aa1c, the instance-aware deduplication correctly preserves txid-based proof correlation across live delivery, mempool snapshots, and history replay. Two non-blocking improvements remain: avoid retaining decoded history transactions solely for identifier bookkeeping, and clarify the deserialization-failure log label. This was a static review; current CI reports successful Rust workspace tests with no failed code checks, while review and hygiene checks remain pending.
🟡 1 suggestion(s) | 💬 1 nitpick(s)
Approved: nothing here blocks the merge. The non-blocking findings are optional: fix them forward, in this PR or a follow-up, without waiting for another review round.
Review provenance
Source: reviewer 1: glm-5.3-flash (agent: phase1-reviewer, role: general); reviewer 2: glm-5.3-flash (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
lowbygpt-6.1-sol(effort low) — This is a contained, single-file deduplication fix with focused regression tests across delivery paths, and it does not change consensus, signature verification, or network deserialization rules. - Phase 1 reviewers:
glm-5.3-flash— general (completed, effort high); agentphase1-reviewer,glm-5.3-flash— rust-quality (completed, effort high); agentphase1-reviewer - Phase 1 model:
glm-5.3-flash— zai quota: 5h 100% left, weekly 93% left; passed overgemini-3.8-flash-high(antigravity quota lookup failed) - Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort medium); agentphase2-reviewer,gpt-6.1-sol— architecture-layering (completed, effort medium); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort medium); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review (PastaClaw). How to work through them:
- Verify each finding against the code; fix only what is real, as narrowly as the finding.
- If a finding is wrong, decline it on its thread in one or two sentences; the bot answers once and stops.
- To defer one, link a tracking issue on its thread (or reply asking the bot to file one).
- Suggestions are optional: fix them forward in a later PR rather than pushing another round just for them.
- Address every current finding in one push: self-review the full diff first, and don't push piecemeal.
- Keep the PR's scope; don't grow it to satisfy hardening suggestions.
- Carried items were raised in an earlier round: read the thread first, and don't re-fix what you already fixed, declined or deferred there. Disputed and deferred items are already handled and are not listed.
In `packages/rs-dapi/src/services/streaming_service/transaction_stream.rs`:
- [SUGGESTION] packages/rs-dapi/src/services/streaming_service/transaction_stream.rs:1296-1300: Retain delivery identifiers rather than decoded history transactions
The new `matching_transactions` collection retains every matching decoded transaction alongside its serialized bytes until the block iteration ends, including across response sends. Previously, this bookkeeping retained only txid bytes. The decoded inputs, outputs, scripts, and payloads are needed only to derive delivery identifiers, so this adds avoidable per-block memory and allocation overhead. Successfully decoded bloom matches are also parsed again here after their earlier decode at line 1266. Reuse a single decode per transaction and collect only txid/instance-hash pairs for a batched marking API, preserving the existing raw-bytes bloom fallback when decoding fails.
- [NITPICK] packages/rs-dapi/src/services/streaming_service/transaction_stream.rs:561: Name the log event after the deserialization failure
The rewritten guard skips the event because transaction deserialization failed, but the retained `transaction_no_txid` label suggests a transaction-identity problem instead. The old helpers also deserialized internally, so the failure condition has not changed; this is a diagnostic naming cleanup on the guard being rewritten. Use a deserialization-specific label so malformed or unsupported payloads are identifiable in production logs.
|
Bots are done — your move: post |
The history replay kept every matching decoded transaction until the block was sent, only to derive the ids it marks delivered. It now decodes each transaction once and keeps its txid and, for a stable-txid asset unlock, its instance hash. The unused txid_bytes_from_bytes helper is removed, and the live path's deserialization failure is logged as transaction_deserialize_failed. Addresses the PastaClaw review of #5832. No behaviour change; the existing tests, including both asset unlock instance tests, pass. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
Waiting for bot review — thepastaclaw not yet. Wait for the missing reviews, or a writer can post |
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
The reviewed head correctly distinguishes re-signed asset-unlock instances while preserving txid-based InstantSend and Merkle bookkeeping. The two prior findings are fixed, and no new actionable issues were identified; the supplied Rust workspace CI check passed, with only review/hygiene checks still pending.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
normalbygpt-6.1-sol(effort low) — This is a contained but nontrivial Rust streaming-state change affecting transaction deduplication across live, mempool, and replay paths, without modifying consensus, cryptography, or funds movement. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— architecture-layering (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort high); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
|
Bots are done — your move: post |
Issue being fixed or feature implemented
rs-dapi dedupes the raw transactions it streams to each
subscribeToTransactionsWithProofssubscription by txid.From protocol version 15, Platform emits asset unlocks with payload version 2. Their txid leaves out the request height, quorum hash and signature, so every instance Platform re-signs after an expiry has the same txid. Core 24 relays each instance (
TransactionAddedToMempoolfires for the refreshed one). A subscriber that already received an earlier instance was never sent the refreshed instance, or the one that was mined, so it kept a stale requested height, quorum hash and signature.Found in the review of #5634 (finding 5). The problem is outside that PR's diff, but its switch to version 2 unlocks is what triggers it. It does not affect consensus.
What was done?
TransactionStreamState::mark_transaction_deliverednow takes the transaction. It marks:Transaction::instance_hash, the hash of the full serialization, and it is what tells re-signed instances apart. It only ever differs for an asset unlock with payload version 2 or higher, and those instances go into a new bounded per-stream set,delivered_tx_instances.So a stream dedupes raw transactions by instance. For every other transaction, behaviour and per-stream memory are unchanged.
All three paths use it:
mark_transactions_deliverednow takes the decoded matching transactions)An instance the replay delivered is therefore not streamed again when Core reports it live.
The live path decodes the transaction once. It used to decode it twice, once for the txid bytes and once for the hex.
How Has This Been Tested?
TDD:
should_stream_every_instance_of_a_re_signed_asset_unlockfeeds two instances of one version 2 asset unlock (same txid, different instance hashes), then the first instance again, throughflush_transaction_pending.left: [0x808a…b8dd](only the first instance was streamed),right: [0x808a…b8dd, 0xc45c…6c98].should_not_stream_again_the_asset_unlock_instances_a_replay_deliveredcovers the history path: instances a replay delivered are skipped live, and a new instance is not.should_dedupe_transactions_blocks_and_instant_locksnow passes a transaction instead of raw txid bytes.Commands:
cargo test -p rs-dapi: 346 passed, 0 failed, 0 ignored.cargo clippy -p rs-dapi --all-features --all-targets: no warnings in rs-dapi. Under rs-dapi's feature set, clippy reports three doc lints indpp, indata_contract_create_transition/v0/mod.rs:31andshield_from_asset_lock_transition/v0/mod.rs:62-63. Those files are not touched here and give the same warnings onv5.1-dev.cargo fmt --all -- --check: clean.Breaking Changes
None. Subscribers now receive each instance of a version 2 asset unlock once, where before they received only the first. Every other transaction is streamed exactly as before.
In-place changes to shipped generations
None. rs-dapi is not versioned consensus code.
Checklist:
structure.rs, regeneratedgrovedb-structure.json, and checked the structure viewer link posted on this pull requestFor repository code-owners and collaborators only
🤖 Generated with Claude Code
PR Hygiene ·
45e4c9d/self-reviewedrust-dapi(packages/rs-dapi/src/services/streaming_service/mod.rs,packages/rs-dapi/src/services/streaming_service/transaction_stream.rs) — QuantumExplorer or lklimekWhen every merge requirement is met, the
PR Hygienecheck passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.Summary by CodeRabbit