Repository navigation
fix(tx): honest broadcast result, and no name transaction hsd would reject - #81
Merged
Merged
Conversation
… is never final hsd 8.0.0 answers sendrawtransaction with the txid whatever its mempool does with the transaction, so a send whose coins were already spent, or one hsd refused for any other reason, read as sent. This implements docs/specs/2026-10-07-honest-broadcast-result.md: - R1-R3: after sendrawtransaction the wallet looks the transaction up up to five times, 400 ms apart; the first find ends the window. hsd's not-found on every check, with no output of the transaction mined, is "not taken": the broadcast errors "The node did not take the transaction", the draft is broadcast_pending with its coins held. An output already mined (a node without a transaction index) confirms it; a check without hsd's answer is no verdict. - R5: a Shakedex purchase goes through the same check, and so does its one automatic rebroadcast: not taken loses it with nothing paid, unless the chain traces to it. - R6: a broadcasted, confirmed, dropped or failed draft is not signed or broadcast again. Signing flipped any draft back to "signed", so a confirmed one could be turned back and a dropped one's released coins spent again. - R7: dropped and failed are no longer final. For 72 hours (hsd's mempool expiry) the confirmation poll keeps looking for such a transaction and confirms it once mined, so a payment that went through never keeps reading "not sent". The look-up and the chain evidence move to noncustodial::tx_evidence, which the purchase job may use (CODING_STANDARDS layering). Tests: unit and mock tests pin R1-R7 (each checked to fail with its rule removed); live regtest tests cover the double spend, the revived send on both nodes, a purchase and finalize paying their fee rate on vsize at 20 doos/byte, and a purchase rebroadcast refused after a price drop. Seven older live tests now fail because hsd refuses a transaction they build (bad-redeem-owner, bad-renewal-premature, bad-finalize-maturity, an orphan): they passed only because the broadcast never said so. They are fixed next.
…reject
The name builders built transactions hsd refuses: a RENEW within tree_interval of the name's last renewal (bad-renewal-premature), a FINALIZE before the transfer lockup is over (bad-finalize-maturity; the Finalize button was gated, the builders were not, and the gate allowed it when the transfer height was unknown), and a REDEEM of the winning reveal, which is the name's owner coin until REGISTER (bad-redeem-owner; the old filter read the wallet's database and missed a name the wallet never tracked). Each now asks the node (getnameinfo and the tip, judged at tip + 1 as hsd does) and refuses before a draft is persisted, saying how many blocks are left; single and batch renew, finalize, finalize-with-payment and redeem all go through the same checks (commands/draft_ctx.rs). The UI withholds Renew the same way ("can be renewed in N blocks").
Seven live regtest tests built exactly these transactions and passed only because the broadcast never said hsd refused them. They now run valid scenarios and assert the effect on chain: a rival bidder outbids for redeem, renew and finalize mine the required blocks first and check info.renewal / the new owner, and the batch transfer test syncs between its two finalizes (both had spent one funding coin, which hsd held as an orphan). New live test: live_redeem_of_the_winning_reveal_is_refused.
Tests: unit 2959 passed, each guard and wrapper call checked to fail its tests when removed; full live suite on a fresh regtest chain, Shakedex and the node without a transaction index included, 80 passed. clippy -D warnings, fmt and prettier clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements
docs/specs/2026-10-07-honest-broadcast-result.md(R1–R7) and fixes the name builders that the honest broadcast showed were building transactions hsd rejects.1. A send is sent only once the node has it (
4f33104)hsd 8.0.0's
sendrawtransactionreturns the txid whatever its mempool does with the transaction.broadcast_pendingwith its coins held. An output already mined (a node without a transaction index) confirms it. A check without hsd's answer gives no verdict.broadcasted,confirmed,droppedorfaileddraft is not signed or broadcast again. Signing used to flip any draft back tosigned.droppedandfailedare no longer final. For 72 hours (hsd's mempool expiry) the confirmation poll keeps looking and confirms a transaction mined after the verdict.noncustodial::tx_evidence, so the purchase job can use them under the layering rule.2. The builders refuse what hsd's consensus rejects (
8c44af0)Seven live tests built transactions hsd refuses and passed only because the broadcast never said so (
bad-renewal-premature,bad-finalize-maturity,bad-redeem-owner, an orphan). Before persisting a draft, renew, finalize (single, batch, with payment) and redeem now ask the node (getnameinfoand the tip, judged attip + 1) and refuse, saying how many blocks are left. The UI withholds Renew the same way. The seven tests now run valid scenarios (a rival outbids for redeem; renew and finalize mine the required blocks first) and assert the effect on chain.Tests
--index-txincluded: 80 passed. New: double spend not sent, a dropped send revived on both nodes, purchase and finalize fee rate on vsize at 20 doos/byte, purchase rebroadcast refused after a price drop, redeem of the winning reveal refused.cargo clippy --all-targets -D warnings, fmt andnpx prettier --check .clean.Known leftovers
docs/REGTEST_TESTING.mdScenario 4 reads as if an unrevealed bid could be redeemed (REDEEM spends a REVEAL output). Not checked live; left as is.