-
Notifications
You must be signed in to change notification settings - Fork 129
taproot/script limits; default unknown-witness off; BIP8 stub #222
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
base: 29.x-knots
Are you sure you want to change the base?
Conversation
… expose -datacarrierwitnesslimit and -v1perinputwitnesslimit
…n SetupServerArgs; remove stray scoped block in InitParameterInteraction
…ript push-run and IF-branch push-only guards; drop redundant element check
…ierwitnesslimit and field
…mits) with TBD params and versionbits wiring
…ushlen<=256, disallow OP_IF in tapscript policy; default -acceptunknownwitness=false
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.
Needs work. Here are the main points:
- No test coverage: No functional tests added for new policy rules
- Performance concerns: Triple-parsing tapscripts (witness check, push runs, IF bodies) is inefficient. Should be single-pass.
- Policy rationale undocumented: Why 1024, 256, 80, 257? Need comments linking to BIP-0444 or analysis.
- Code duplication: Opcode parser copy-pasted 3+ times
- Incomplete opcode handling:
OP_0,OP_1NEGATE,OP_1-OP_16not recognized as pushes
…n; constants for limits; bounds for -v1perinputwitnesslimit; fix whichType use order; add comments with BIP-0444 rationale
…itness default; note tapscript tests as follow-up
…per-input witness cap, IF ban, push-run cap, and IF-body cap
…n-witness rejection
|
All points should be addressed @kwsantiago, very much appreciate the feedback |
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.
Excellent improvements @justinfilip !
Most previous issues were addressed. I left some remaining minor comments.
| // Small integer push has no explicit payload | ||
| return true; | ||
| } | ||
| size_t need = 0; |
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.
This is an unused variable?
| if (pos >= s.size()) return false; | ||
| pushed_len = s[pos++]; | ||
| } else if (op == OP_PUSHDATA2) { | ||
| if (pos + 1 >= s.size()) return false; |
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.
if (pos + 1 >= s.size()) should be if (pos + 2 > s.size()) for consistency (needs 2 bytes). Same pattern in lines 73, 94, 95.
| pushed_len = s[pos++]; | ||
| } else if (op == OP_PUSHDATA2) { | ||
| if (pos + 1 >= s.size()) return false; | ||
| pushed_len = s[pos] | (uint32_t(s[pos+1]) << 8); |
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.
On lines 70 and 74, casting to uint32_t then assigning to uint64_t pushed_len. If PUSHDATA4 has value > 2^32-1, the upper bits are lost.
Should cast directly to uint64_t.
| size_t payload = 0; | ||
| if (op >= 0x01 && op <= 0x4b) payload = op; | ||
| else if (op == OP_PUSHDATA1) { if (pos >= s.size()) return false; payload = s[pos++]; } | ||
| else if (op == OP_PUSHDATA2) { if (pos + 1 >= s.size()) return false; payload = s[pos] | (uint32_t(s[pos+1]) << 8); pos += 2; } |
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.
AdvanceOneOp repeats the same bounds checks as ParsePush.
Consider refactoring to share logic.
| } else if (op == OP_ELSE) { | ||
| if (!if_stack.empty()) { | ||
| size_t body_start = if_stack.back(); | ||
| size_t body_end = j - 1; |
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.
When body_end == body_start, no branch is added, but this represents an empty IF body.
Should this be checked/rejected?
| control[0] = 0xc0; | ||
|
|
||
| // Leaf with OP_IF containing 80-byte push-only body (would be rejected by IF ban first) | ||
| CScript leaf_if_80 = CScript() << OP_FALSE << OP_IF << std::vector<unsigned char>(80, 0) << OP_ENDIF << OP_TRUE; |
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.
On lines 228 and 237, these scripts use OP_FALSE << OP_IF which means the IF body never executes. The test is checking IF ban, not IF-body limit.
Consider testing actual IF-body limit separately if IF ban is lifted.
| args.SoftSetArg("-blockmaxweight", "4000000"); | ||
| } | ||
|
|
||
|
|
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.
Empty lines added without purpose. Remove.
| mempool_opts.persist_v1_dat = argsman.GetBoolArg("-persistmempoolv1", mempool_opts.persist_v1_dat); | ||
|
|
||
| // Policy flags to constrain per-input witness size for segwit v1 | ||
| if (auto lim = argsman.GetIntArg("-v1perinputwitnesslimit")) { |
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.
User sets -v1perinputwitnesslimit=50, gets 128 with no warning.
Should log when clamping occurs or return error for out-of-range values.
| bool permitephemeral_send{DEFAULT_PERMITEPHEMERAL_SEND}; | ||
| bool permitephemeral_dust{DEFAULT_PERMITEPHEMERAL_DUST}; | ||
| bool persist_v1_dat{DEFAULT_PERSIST_V1_DAT}; | ||
| // Policy to limit inscription-like data in witnesses/tapscripts |
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.
"inscription-like data" is vague.
Be more specific: "Total witness bytes per v1 input to prevent witness stuffing/inscription abuse."
|
|
||
| ## References | ||
|
|
||
| - BIP-0444: https://github.com/bitcoin/bips/blob/master/bip-0444.mediawiki (pending merge) |
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.
BIP-0444 link shows "(pending merge)" but links to non-existent file (404).
Update when BIP number is assigned or remove until finalized.
Appreciate the continual feedback and have noted the additional code review you've done. Before I continue with addressing the code problems you've pointed out, I'd like to get your thoughts on my response in the BIP discussion: bitcoin/bips#2005 (comment) |
|
I'd like to get @luke-jr thoughts on moving forward with this on Knots, given that Core shut down the BIP discussion. |
Policy items (each reject reason and where enforced).
Defaults and new flags (e.g., -v1perinputwitnesslimit, default -acceptunknownwitness=0).
Deployment stub: new deployment ID/name, TBD versionbits params, BIP8 delayed activation.
Testing plan: might add unit/functional tests for SPK size/push caps, tapscript IF-ban, push-run/IF-body, control block cap, per-input v1 cap.
Link to BIP-0444 PR/discussion.