Conversation
…-broadcast-outcome
There was a problem hiding this comment.
detekt found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
Regtest APKDownload bitkit-dev-debug universal APK (expires in 30 days). |
This comment has been minimized.
This comment has been minimized.
|
I pushed 6966111 with the scoped review fixes: original-send follow-up, exact-observation acknowledgement, running-process Accepted persistence repair, verified Shop proof delivery after guard replacement, and original transfer accounting. The visibility component test now states its actual coverage. The source batch passed 71 focused tests. Process loss before Accepted is durable still leaves the attempt guarded. This PR remains draft while corrected node artifacts, consumer validation and current native journeys are pending. |
|
I pushed ae0be37 with the hardware Shop proof correction. A Core txid is retained only as the original lookup candidate; proof and Success require fresh observation of that exact outgoing transaction in the original wallet. Identity/request/wallet context is captured, preparation failures block dispatch, and pending proof work cannot start another payment. The frozen batch passed 58 focused tests, including the guard, wrong-identity, inbound/mismatched lookup and original-context regressions. The hardware journey spec is parsed but unrun; physical hardware and native fault fixtures remain explicit QA gaps. This remains draft while both apps validate the published rc68 dependency and current native fixed/Max journeys. Prior rc67 media is labelled historical. |
|
I pushed 9de645a with the final hardware Shop guards and the production rc68 dependency pin. A candidate-save failure or a Core exception with no returned txid keeps the started request protected after dismissal/reopening. Shop Sent activity now requires fresh exact outgoing observation and durable local follow-up in the original wallet. The affected run passed 95 tests and app/test APK builds. The actual installed APK embeds the published rc68 native bytes; funded fixed 1,000-sat and Max 98,749-sat native sends passed, and both exact UI transaction IDs were independently observed on the backend. Current Preview replaces the historical accepted-send media. Controlled native refusal/response-loss and hardware Shop execution remain unrun; their QA entries remain explicit. No recovery scope was added. |
jvsena42
left a comment
There was a problem hiding this comment.
Two HIGH, one MEDIUM and two LOW inline. I reviewed this as a funds change. The refusal lockout and the legacy-proof gap are shared with synonymdev/bitkit-ios#844.
Checked and clean:
- No failure is reported for a tx that broadcast:
NodeException/NodeNotSetuprelease the guard only before dispatch in rc.68, and everything else keeps the guard. - Success is shown only on
Accepted. The replays at :4018/:4172 are for the same request with its original txid. HW Shop needs a fresh exact observation. admitblocks the samerequestId/orderId, and Lightning proof association is refused while an on-chain attempt exists.- Pending is persisted before dispatch.
- Old backups decode with the new field defaulting to false, and newer backups decode on older builds via
ignoreUnknownKeys. - The Keychain change is storage-only, with no seed material.
- The rc.66 → rc.68 bump carries the broadcast-result API.
Pre-existing: RBF/CPFP remain fire-and-forget.
Also LOW: the new toasts at TransferViewModel.kt:394/436 are hardcoded English.
| get() = evidence == OnchainSendEvidence.Accepted || evidence == OnchainSendEvidence.Observed | ||
|
|
||
| val blocksNextSend: Boolean | ||
| get() = isUnresolved || (hasPositiveEvidence && !localFollowupComplete) |
There was a problem hiding this comment.
A refused broadcast locks on-chain sends for good.
Unknown and Rejected both block the next send, and the only exit is observing that exact txid on chain. There is no release on sync and no user action; only a wallet reset or reinstall clears the stored attempt. Ordinary sends, Shop payments and Blocktank funding all go through the same guard.
In ldk-node rc.68, classify_electrum_broadcast (src/chain/electrum.rs) returns Rejected only for -26 non-final. Every other daemon refusal becomes Unknown, including mempool min fee not met, min relay fee not met, txn-mempool-conflict and bad-txns-inputs-missingorspent. Those mean the backend did not take the transaction, and nothing rebroadcasts a user send, so no Received/Confirmed event ever arrives. A Slow or Custom fee during a mempool purge, or a send built on stale UTXO state, leaves the wallet unable to send on-chain while its funds stay in BDK.
Out of Scope accepts indefinite blocking for a lost result. This is a definite, common refusal that lands in the same state.
Fix: allow a release once a post-refusal sync shows the txid unknown to the backend and the attempt's inputs still unspent. If it could surface later, require the next send to spend at least one of those inputs so it conflicts rather than double-pays.
Same in synonymdev/bitkit-ios#844.
There was a problem hiding this comment.
The lockout is real when a refused transaction never surfaces. It is an explicit limitation of this bounded change, including refusal as well as a lost response.
rc.68 Rejected reports a recognized refusal and explicitly allows earlier delivery: outcome contract. The pinned electrum-client 0.24.1 retries transport failures up to three times after the original call. A later protocol refusal returns without the earlier transport-error history; a request may already have been written before a receive failure. The final refusal therefore does not prove that earlier delivery or acceptance never occurred. See the retry wrapper. This is a possibility supported by the transport contract, not a claim that it happened in the tested journeys.
Only a proven pre-dispatch failure releases this guard. Relabelling fee/conflict/missing-input responses as Rejected would preserve diagnostics but would not prove retry safety. One backend reporting absence and unspent inputs cannot retract previously delivered bytes or an in-flight request.
Requiring a later send to conflict with the original adds a replacement/recovery policy, which the agreed scope excludes. I’m keeping the guard and clarifying the refusal limitation. Does this remain a blocker for the bounded acceptance-reporting change, or can the recovery policy be considered separately?
|
Two independent reviews. needs changing before merge
worth doing, does not block
nits
|
|
Pushed 0ef4613 with the current master conflict resolved. Accepted/observed funding now resumes from its saved original order/balance context at startup and node events, persists transfer/paid-order/local activity idempotently, and completes without another native send. Proven pre-admission errors use existing error handling; post-dispatch uncertainty remains guarded. Pending shows the candidate transaction ID/refusal and exact original-wallet local Details without treating that row as acceptance. Local verification: compile, 3,079 unit tests and two emulator component tests passed against the published rc68 AAR; app/test APK builds passed. Detekt exited successfully under ignoreFailures with 570 existing findings, none on changed feedback lines. Two semantic regressions failed before their fixes. The installed native bytes match rc68. Current Preview is explicitly synthetic component UI; prior funded fixed/Max media predates this batch. Native refusal/response-loss, storage-fault and hardware Shop journeys remain unrun. Refusal lockout and pre-upgrade software-proof migration remain open review discussions; no release, new schema or payment recovery was added. |
jvsena42
left a comment
There was a problem hiding this comment.
Re-checked the fixes in merge 0ef4613. The transfer-resume HIGH, the pre-admission MEDIUM and the Pending LOW are resolved (replied on each). One new LOW inline, introduced with the auto-resume.
Checked and clean:
- The resume never broadcasts, and needs positive evidence plus an exact order/txid match.
persistAcceptedFundingis serialized and idempotent.- Observation promotion happens before the
nodeEventsemit, so there is no race.
Still open, waiting on my decision: the refusal lockout thread and the legacy-proof migration thread.
|
Pushed 6c75463 to preserve paid-success navigation when local activity follow-up fails after funding and the paid order are durably saved. Both fresh Accepted and resumed Accepted/Observed paths keep the original transaction; existing resumption retries the local work. Funding-persistence failures remain guarded. Three duplicate-funding regressions failed on the old source; compilation and 169 focused tests now pass against unchanged published rc68. Actual storage-fault device QA remains unrun. The description retains that limit, earlier validation provenance and the single-row image table. |
Closes #1211
Twin: synonymdev/bitkit-ios#844
Refs: synonymdev/ldk-node#119
Description
The published rc68 dependency matches the canonical artifact. The latest accepted-funding fix passed 169 focused unit tests and compilation. The earlier feedback batch at 0ef4613 passed 3,079 unit tests and two emulator component tests after resolving the master conflict. Native send and component Preview evidence below predates the latest fix.
0.7.0-rc.68; independent remote and resolved AAR hashes match, with Maven local excluded from validation.Out of Scope
Transaction recovery: journals, raw transaction storage, automatic rebroadcast, replacement, RBF recovery and abandonment.
Chain handling: reorg and event-delivery redesign.
Unresolved sends: no timeout/reset escape. A refused or unknown result can block further on-chain sends indefinitely when the transaction never becomes positively observed; backend acceptance does not guarantee confirmation.
Legacy software proofs: queued-era transaction IDs without positive acceptance and original wallet provenance are not promoted or delivered. Opted-in released users can have these records; migration is excluded from this PR, with the documented limitation accepted in review.
Design
N/A — no design available for the new unresolved-send state.
Preview
Historical rc68 candidate before the current feedback batch: fixed 1,000-sat and Max 98,749-sat regtest sends using the actual published and resolved LDK package. Both exact transaction IDs matched native Accepted logs and independent backend observation.
Current Pending preview: synthetic component UI only, with dummy transaction IDs/refusal text and mocked fiat value. It shows refusal copy, a selectable candidate ID and local Details without success; it does not reproduce backend refusal or persistent reopening.
QA Notes
Journeys
shop-onchain-proof.xml— linked issuer and funded Bridge hardware wallet: exact original transaction and delivered proof, with no new signing/payment while observation is pending. Spec parsed; native hardware journey unrun.onchain-accepted-result.xml— accepted fixed-amount and send-all finish local activity and expose distinct exact transaction IDs in Details.Manual Tests
Automated Checks
OnchainSendAttemptStoreTest.kt— serialized admission, durable guards, outcome persistence and exact transaction observation.SendPendingScreenTest.kt— refusal/candidate visibility and enabled local Details callback while remaining Pending; component checks do not reload durable state.LightningRepoTest.kt,LightningServiceTest.kt— explicit accepted/rejected/unknown mapping and pre-dispatch boundaries.AppViewModelSendFlowTest.kt,PaykitPaymentProofRepoTest.kt,TransferViewModelTest.kt— proven pre-admission errors, accepted follow-up failures, request protection and original hardware proof identity.TransferViewModelTest.kt— fresh Accepted and resumed Accepted/Observed funding retain one order/send and paid-success navigation after local activity failure; failed funding persistence retains the original order without success.TransferRepoTest.kt,SendPendingViewModelTest.kt— startup/event funding resumption, partial storage idempotency and original-wallet Details without acceptance inference.HwWalletRepoTest.kt,HwSendViewModelTest.kt,ActivityRepoTest.kt— exact outgoing original-account observation, Sent activity durability and one native broadcast while proof completion is pending.PaykitOnchainPaymentProofLookupTest.kt— address/amount matching no longer establishes that an interrupted attempt was accepted.0.7.0-rc.68resolved AAR SHA-2560cee2079291260aea12bf60ac9c8af8f459d9f24c3327d4cb021e5686035aa2f, identical to the published canonical artifact.Local verification at 6c75463: compilation and 169 focused tests passed (0 failures/errors). All three new duplicate-funding regressions failed on the preceding production source by funding a second order; the persistence-failure regression remained fail closed. Maven local was excluded and the resolved AAR hash matches unchanged published rc68. No device or storage-fault journey was run for this fix.
Earlier verification at 0ef4613: compile, 3,079 unit tests (0 failures/errors/skips), app/test APK builds and two emulator component tests passed. Startup funding and pre-admission regressions failed before their fixes. Detekt exited successfully with
ignoreFailures: 570 findings remained, none on added or changed feedback lines. The installed APK’s native library matched rc68. Full-suite, Detekt and device checks were not repeated for 6c75463.Prior rc68 validation: 95 affected tests and funded fixed-amount/Max native journeys passed with independently verified exact backend transactions. Those native journeys were not repeated for this batch. Controlled native refusal, response-loss, storage-fault and hardware Shop journeys remain unrun; the new Preview is synthetic component coverage only.