pocx: gate nonce submissions on actual privkey availability#3
Merged
Conversation
…pt membership The receive-path check in submit_nonce ultimately resolved to DescriptorScriptPubKeyMan::IsMine(script), which is pure script-map membership. Wallets loaded with pubkey-only descriptors (importdescriptors with an xpub, watch-only setups) passed the gate and the scheduler then built unsigned blocks that signing dropped on the floor seconds later. Replace HaveAccountKey's isSpendable probe with the same predicate the signer actually executes: iterate ScriptPubKeyMans, CanProvide as a cheap script-only pre-filter, then GetPoCXPubKey under cs_wallet to verify a private key is loadable. CWallet::SignMessage is the established Core precedent for both the loop shape and the lock placement (cs_wallet -> cs_desc_man order, see comment at wallet/wallet.cpp:2215). Return AccountKeyAvailability instead of bool so the locked-vs-absent triage in pocx/rpc/mining.cpp keeps producing RPC_WALLET_UNLOCK_NEEDED for encrypted-and-locked wallets instead of regressing them to the generic "no private key" error. SignPoCXBlock adopts the same idiom for consistency and to close the matching latent deadlock window. Misleading "failed to get public key" log line corrected to mention the actual cause. Refs PoC-Consortium/bitcoin-pocx#4
Drop the dead has_key flag from submit_nonce and replace the if/else if/else chain with two unconditional throws (Locked, then Absent); Available falls through. Same semantics, no intermediate state to track. Add a one-line note on the AccountKeyAvailability forward declaration in interfaces/wallet.h pointing at the underlying-type definition in pocx/mining/wallet_signing.h, since the two must stay in sync for the forward decl to remain valid. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
JohnnyFFM
added a commit
to PoC-Consortium/bitcoin-pocx
that referenced
this pull request
May 15, 2026
Add scripts/mining/test-regtest-submitnonce-key-gate-v2.sh covering every
branch of the receive-path probe (HaveAccountKey) plus the multi-wallet
iteration semantics:
A Absent watch-only descriptor; expect -5 + bech32 + no raw-hex regression
B Locked encrypted+locked privkey; expect -13 + walletpassphrase hint
C Available unlocked privkey; expect exit 0 + raw_quality/poc_time
D Multi Locked + Available, Locked loaded first
(probe must traverse past Locked to pick Available)
E Multi Available + Locked, Available loaded first
(later Locked must not downgrade an earlier Available)
D + E together prove the {Locked, Available} probe outcome is order-
independent, ruling out "break on first Locked" and "Locked overrides
later" regressions. Each case loads its wallets in isolation and unloads
between cases so the probe state under test is unambiguous.
Regression guards for:
#4 (PR PoC-Consortium/bitcoin#3) - Absent/Locked split
#3 (PR PoC-Consortium/bitcoin#2) - bech32 rendering
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
pocx::mining::HaveAccountKey) treatedIsMine-equivalent script membership as proof of private-key ownership. Wallets loaded with a pubkey-only descriptor (importdescriptorswith anxpub, or any watch-only setup) passed the gate; the scheduler then built unsigned blocks that signing dropped seconds later.isSpendableprobe with the predicate the signer actually executes (CanProvide+GetPoCXPubKeyundercs_wallet), mirroringCWallet::SignMessagefor both loop shape and lock-ordering (cs_wallet -> cs_desc_man, seewallet/wallet.cpp:2215).AccountKeyAvailability(Available/Locked/Absent) instead ofboolso the RPC triage atpocx/rpc/mining.cppkeeps producingRPC_WALLET_UNLOCK_NEEDEDfor encrypted+locked wallets that would be able to sign once unlocked, rather than regressing them to the generic "no private key" error.SignPoCXBlockto close the matching latent deadlock window.Refs PoC-Consortium/bitcoin-pocx#4
Test plan
wpkh(<xpub>/0/*)for a known PoCX account; point a plotter at the same account and submit a nonce. Expected:submitnoncerejects withRPC_INVALID_ADDRESS_OR_KEYbefore proof validation. Before this change: ACKs, then[Scheduler] Block signing failedat deadline.xprv, leave it locked, submit a nonce. Expected:submitnoncerejects withRPC_WALLET_UNLOCK_NEEDED("unlock with walletpassphrase first"). Confirms the tri-state path preserves the operator-friendly error.