-
Notifications
You must be signed in to change notification settings - Fork 42
SignCommitmentTx improvements #803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughReplaces per-input PSBT tapscript verification with vtxo-aware verification and boarding-input checks, adds combine-by-index API, delegates prevout fetching to txutils, updates service call sites and mocks, and tweaks two tests/config timings. Changes
Sequence Diagram(s)sequenceDiagram
participant S as Service
participant B as TxBuilder
participant U as txutils
rect rgb(250,250,255)
Note over S: SignCommitmentTx (read-only commitmentTx)
S->>B: VerifyBoardingTapscriptSigs(partialTx, commitmentTx)
B->>U: GetPrevOutputFetcher(commitmentTx)
B->>U: VerifyTapscriptSigs(partialPSBT, prevoutFetcher)
U-->>B: []int (signed input indices)
alt no signed inputs
B-->>S: error INVALID_BOARDING_INPUT_SIG
else
S->>B: CombineTapscriptSigs(dest, src, indexes)
B-->>S: combinedTx
end
end
rect rgb(245,255,245)
Note over S: Offchain verification (ark/checkpoint)
S->>B: VerifyVtxoTapscriptSigs(tx, mustIncludeSignerSig)
B->>U: GetPrevOutputFetcher(...) / VerifyTapscriptSigs(...)
U-->>B: ([]int, *psbt.Packet)
B-->>S: verification result
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pkg/ark-lib/txutils/utils.go (1)
31-36: Fix the witness loop to keep the build green
for i := range witCountdoesn’t compile becauserangecan’t iterate over a scalar (witCountis auint64). Use an indexed loop so the code builds.- for i := range witCount { - witness[i], err = wire.ReadVarBytes(r, 0, txscript.MaxScriptSize, "witness") + for i := uint64(0); i < witCount; i++ { + witness[i], err = wire.ReadVarBytes(r, 0, txscript.MaxScriptSize, "witness")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
internal/core/application/service.go(4 hunks)internal/core/ports/tx_builder.go(1 hunks)internal/infrastructure/live-store/live_store_test.go(2 hunks)internal/infrastructure/tx-builder/covenantless/builder.go(3 hunks)internal/test/e2e/e2e_test.go(1 hunks)internal/test/e2e/utils_test.go(1 hunks)pkg/ark-lib/txutils/utils.go(3 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: louisinger
Repo: arkade-os/arkd PR: 691
File: internal/core/application/service.go:557-562
Timestamp: 2025-08-19T10:58:41.042Z
Learning: In the arkd SubmitOffchainTx method, using the checkpoint PSBT input's tapscript (forfeit path) for the VtxoInput.Tapscript field is the correct behavior, not a bug as initially thought. The system correctly handles the relationship between checkpoint inputs and Ark transaction inputs.
📚 Learning: 2025-08-19T10:58:41.042Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 691
File: internal/core/application/service.go:557-562
Timestamp: 2025-08-19T10:58:41.042Z
Learning: In the arkd SubmitOffchainTx method, using the checkpoint PSBT input's tapscript (forfeit path) for the VtxoInput.Tapscript field is the correct behavior, not a bug as initially thought. The system correctly handles the relationship between checkpoint inputs and Ark transaction inputs.
Applied to files:
internal/core/ports/tx_builder.gopkg/ark-lib/txutils/utils.gointernal/core/application/service.gointernal/infrastructure/tx-builder/covenantless/builder.gointernal/infrastructure/live-store/live_store_test.go
📚 Learning: 2025-09-29T14:33:52.871Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 722
File: pkg/ark-lib/intent/proof.go:52-58
Timestamp: 2025-09-29T14:33:52.871Z
Learning: In btcsuite/btcd's psbt package, the NewFromRawBytes function's boolean parameter (b64) automatically handles base64 decoding when set to true, so passing a base64 string via strings.NewReader with b64=true is the correct usage pattern.
Applied to files:
pkg/ark-lib/txutils/utils.go
📚 Learning: 2025-09-29T14:33:52.871Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 722
File: pkg/ark-lib/intent/proof.go:52-58
Timestamp: 2025-09-29T14:33:52.871Z
Learning: In btcsuite/btcd's psbt package, the NewFromRawBytes function's boolean parameter (b64) automatically handles base64 decoding when set to true, so passing a base64 string via strings.NewReader with b64=true is the correct usage pattern. A common bug is manually base64-decoding the string and then passing b64=true, which causes a double-decode error.
Applied to files:
pkg/ark-lib/txutils/utils.go
🧬 Code graph analysis (3)
pkg/ark-lib/txutils/utils.go (1)
pkg/ark-lib/intent/proof.go (1)
Verify(53-128)
internal/core/application/service.go (2)
pkg/errors/errors.go (2)
INVALID_BOARDING_INPUT_SIG(316-320)InvalidBoardingInputSigMetadata(186-188)pkg/ark-lib/intent/proof.go (1)
New(136-160)
internal/infrastructure/tx-builder/covenantless/builder.go (1)
pkg/ark-lib/txutils/utils.go (2)
GetPrevOutputFetcher(148-161)VerifyTapscriptSigs(43-145)
🔇 Additional comments (4)
internal/test/e2e/e2e_test.go (1)
264-264: Verify the timeout increase is necessary and not masking a performance regression.The timeout increase from 5 to 10 seconds in commit 6934426 ("Improve SignCommitmentTx") corresponds to a significant refactoring that split signature verification and combination into separate steps. While this change may require additional processing time, confirm whether:
- This 2x timeout increase was measured and validated as necessary for the refactored verification logic
- The separate verification step (
VerifyBoardingTapscriptSigsfollowed byCombineTapscriptSigs) adds proportional overhead or indicates a performance regression- A polling mechanism (checking balance state until complete or timeout) would be more reliable than a fixed sleep
internal/infrastructure/tx-builder/covenantless/builder.go (3)
52-61: LGTM! Clear rename improves API semantics.The rename from
VerifyTapscriptPartialSigstoVerifyVtxoTapscriptSigsbetter communicates that this method specifically verifies VTXO tapscript signatures, aligning with the PR's goal to distinguish between different verification contexts.
72-75: LGTM! Good consolidation to shared utility.Moving to
txutils.GetPrevOutputFetchercentralizes prevout fetching logic, improving code reuse and consistency across the codebase.
1017-1039: LGTM! Strong security approach using commitment tx for prevouts.This method correctly uses the
commitmentTx(built by the builder) to derive prevouts for signature verification, preventing attackers from manipulating prevouts intxToVerifyto produce valid-looking but fraudulent signatures. The explicit comment at lines 1031-1032 documents this important security property.
Co-authored-by: Pietralberto Mazza <[email protected]> Signed-off-by: louisinger <[email protected]>
Co-authored-by: Pietralberto Mazza <[email protected]> Signed-off-by: louisinger <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
pkg/ark-lib/txutils/utils.go (1)
108-117: Fix the function name typo.The function
txscript.CalcTapscriptSignaturehash(lowercase "h") doesn't exist in btcsuite/btcd. The correct function name isCalcTapscriptSignatureHash(capital "H").Apply this diff:
- sighash, err = txscript.CalcTapscriptSignaturehash( + sighash, err = txscript.CalcTapscriptSignatureHash(
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
pkg/ark-lib/txutils/utils.go(3 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: louisinger
Repo: arkade-os/arkd PR: 691
File: internal/core/application/service.go:557-562
Timestamp: 2025-08-19T10:58:41.042Z
Learning: In the arkd SubmitOffchainTx method, using the checkpoint PSBT input's tapscript (forfeit path) for the VtxoInput.Tapscript field is the correct behavior, not a bug as initially thought. The system correctly handles the relationship between checkpoint inputs and Ark transaction inputs.
📚 Learning: 2025-08-19T10:58:41.042Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 691
File: internal/core/application/service.go:557-562
Timestamp: 2025-08-19T10:58:41.042Z
Learning: In the arkd SubmitOffchainTx method, using the checkpoint PSBT input's tapscript (forfeit path) for the VtxoInput.Tapscript field is the correct behavior, not a bug as initially thought. The system correctly handles the relationship between checkpoint inputs and Ark transaction inputs.
Applied to files:
pkg/ark-lib/txutils/utils.go
📚 Learning: 2025-09-29T14:33:52.871Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 722
File: pkg/ark-lib/intent/proof.go:52-58
Timestamp: 2025-09-29T14:33:52.871Z
Learning: In btcsuite/btcd's psbt package, the NewFromRawBytes function's boolean parameter (b64) automatically handles base64 decoding when set to true, so passing a base64 string via strings.NewReader with b64=true is the correct usage pattern.
Applied to files:
pkg/ark-lib/txutils/utils.go
📚 Learning: 2025-09-29T14:33:52.871Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 722
File: pkg/ark-lib/intent/proof.go:52-58
Timestamp: 2025-09-29T14:33:52.871Z
Learning: In btcsuite/btcd's psbt package, the NewFromRawBytes function's boolean parameter (b64) automatically handles base64 decoding when set to true, so passing a base64 string via strings.NewReader with b64=true is the correct usage pattern. A common bug is manually base64-decoding the string and then passing b64=true, which causes a double-decode error.
Applied to files:
pkg/ark-lib/txutils/utils.go
🧬 Code graph analysis (1)
pkg/ark-lib/txutils/utils.go (1)
pkg/ark-lib/intent/proof.go (1)
Verify(53-128)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: integration tests
- GitHub Check: unit tests
🔇 Additional comments (3)
pkg/ark-lib/txutils/utils.go (3)
31-31: LGTM: Idiomatic loop refactor.The change to a range-based loop is idiomatic and correct.
41-145: Well-structured tapscript verification logic.The function correctly implements tapscript signature verification:
- Validates control blocks against expected Taproot keys
- Skips inputs appropriately (non-taproot, unsigned, or without leaf scripts)
- Properly computes leaf hashes and signature hashes
- Verifies Schnorr signatures
- Provides descriptive error messages
The logic is sound once the function name typo at line 109 is fixed.
147-161: LGTM: Correct prevout fetcher implementation.The function correctly builds a prevout fetcher from PSBT WitnessUtxo fields with appropriate error handling for missing witness data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
pkg/ark-lib/txutils/utils.go (2)
14-18: Handle the error from ParsePubKey (already flagged).This issue was already identified in a previous review: the error from
ParsePubKeyis silently discarded, and if parsing fails,unspendableKeywill be nil, causing a nil-pointer dereference at line 83.
108-117: Call the correct function name (already flagged).This critical issue was already identified:
txscript.CalcTapscriptSignaturehash(lowercase "h") doesn't exist. The correct function istxscript.CalcTaprootSignatureHash(capital "H").
🧹 Nitpick comments (1)
pkg/ark-lib/txutils/utils.go (1)
123-145: Consider consistent error wrapping.The signature parsing and verification logic is correct. As suggested in previous reviews, you might want to consistently use
%winstead of%sfor error wrapping (lines 126, 134) to preserve the error chain, though this is a minor stylistic improvement.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
pkg/ark-lib/txutils/utils.go(3 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: louisinger
Repo: arkade-os/arkd PR: 691
File: internal/core/application/service.go:557-562
Timestamp: 2025-08-19T10:58:41.042Z
Learning: In the arkd SubmitOffchainTx method, using the checkpoint PSBT input's tapscript (forfeit path) for the VtxoInput.Tapscript field is the correct behavior, not a bug as initially thought. The system correctly handles the relationship between checkpoint inputs and Ark transaction inputs.
📚 Learning: 2025-08-19T10:58:41.042Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 691
File: internal/core/application/service.go:557-562
Timestamp: 2025-08-19T10:58:41.042Z
Learning: In the arkd SubmitOffchainTx method, using the checkpoint PSBT input's tapscript (forfeit path) for the VtxoInput.Tapscript field is the correct behavior, not a bug as initially thought. The system correctly handles the relationship between checkpoint inputs and Ark transaction inputs.
Applied to files:
pkg/ark-lib/txutils/utils.go
📚 Learning: 2025-09-29T14:33:52.871Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 722
File: pkg/ark-lib/intent/proof.go:52-58
Timestamp: 2025-09-29T14:33:52.871Z
Learning: In btcsuite/btcd's psbt package, the NewFromRawBytes function's boolean parameter (b64) automatically handles base64 decoding when set to true, so passing a base64 string via strings.NewReader with b64=true is the correct usage pattern.
Applied to files:
pkg/ark-lib/txutils/utils.go
📚 Learning: 2025-09-29T14:33:52.871Z
Learnt from: louisinger
Repo: arkade-os/arkd PR: 722
File: pkg/ark-lib/intent/proof.go:52-58
Timestamp: 2025-09-29T14:33:52.871Z
Learning: In btcsuite/btcd's psbt package, the NewFromRawBytes function's boolean parameter (b64) automatically handles base64 decoding when set to true, so passing a base64 string via strings.NewReader with b64=true is the correct usage pattern. A common bug is manually base64-decoding the string and then passing b64=true, which causes a double-decode error.
Applied to files:
pkg/ark-lib/txutils/utils.go
🧬 Code graph analysis (1)
pkg/ark-lib/txutils/utils.go (1)
pkg/ark-lib/intent/proof.go (1)
Verify(53-128)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build and Scan
- GitHub Check: unit tests
- GitHub Check: integration tests
🔇 Additional comments (4)
pkg/ark-lib/txutils/utils.go (4)
31-31: LGTM: Idiomatic range loop.The change to
for i := range witCountis cleaner and more idiomatic Go.
41-96: LGTM: Solid validation logic.The input validation flow is well-structured:
- Validates PSBT/tx input count consistency
- Correctly filters for single taproot leaf script inputs
- Validates prevout existence and type
- Properly derives and validates the taproot output key using the control block
- Provides clear error messages with context
147-151: LGTM: Clean return handling.The signed input tracking and return logic is correct.
153-167: LGTM: Clean prevout fetcher utility.The implementation correctly builds a
MultiPrevOutFetcherfrom PSBT WitnessUtxo fields with appropriate error handling for missing witness data. This aligns well with the usage pattern shown inintent/proof.go.
This PR is splitting VerifyAndCombinePartialTx into :
It aims to move signature verification before locking the commitment tx mutex. This way, an invalid tx can't block the batch session.
it renames "VerifyTapscriptPartialSigs" to "VerifyVtxoTapscriptSigs".
it removes
CountSignedTaprootInputs:VerifyBoardingTapscriptSigsreturns the count of signed inputsadd generic functions
VerifyTapscriptSigsandGetPrevOutputFetcherto txutil package in arklib.@altafan please review
Summary by CodeRabbit
New Features
Refactor
Tests
Chores