You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tracking Plumb's filters as policy overlays in bitcoin-kernel #3
We are tracking Plumb's filters from bitcoin-kernel, an independent JavaScript implementation of the consensus rules that runs in Node and the browser. The plan is to mirror each of the five filters as a separate, composable policy overlay beside the consensus engine, with the same on/off granularity as your -reject… options, used first as a gauge (what share of a block a Plumb node would have declined to relay or mine) and later as a mempool gate. Consensus code stays untouched. Umbrella issue with the design and measurements: bitcoin-kernel/kernel#9, one issue per filter: #10–#14 there.
Two things that may be useful to you from the first pass, measured on the Knots BLAKE2b mainnet chain, blocks 976646–976650 (836 transactions):
-rejectfakemultisig alone accounts for 53.7% of mined weight in that sample (a 1-of-15 P2WSH loop, 255 inputs per tx, 513-byte witness scripts, ~1 sat/vB), with no false positives among the ordinary transactions. Our first overlay mirrors it and is tested against those real transactions.
A naive reading of the README for -rejectbareenvelopes (any push followed by OP_DROP) matched 44 of the 323 ordinary transactions in one block: a wallet whose tapscript leaf is <3-byte nonce> OP_DROP <key> OP_CHECKSIG. Likewise a constant-false OP_IF <32 bytes> OP_ENDIF appended to a 3-of-5 P2WSH wallet script matched -rejectdeadbranches. We assume your implementations carry size floors that the README does not state; we intend to take the exact thresholds from your code so the overlays report what Plumb actually does rather than our guess. If there is a commit or file you would point us at as the reference for each option, that would save us misreading it.
Happy to share the vectors (raw transactions plus prevouts) if they are of any use for your own tests. Thanks for the work.
Thanks for the note. plumb/filters.json is the reference: for each option it names a branch and the commit Plumb merges, and the diff from the Knots release tag (v29.4.2.knots20260508) to that commit is the rule. The exception is -rejectfakemultisig, which sits on -rejectbareenvelopes: diff it from c1d056e, the -rejectbareenvelopes commit, instead. The README and FILTERS.md summarize it.
Neither case has a size floor, and your reading matches what the nodes do. In both the data sits in an input, and Knots refuses any data carrier bytes it counts in an input unless -acceptnonstddatacarrier is set (txn-datacarrier-nonstandard, in src/validation.cpp). Stock Knots counts <data> OP_DROP and OP_FALSE OP_IF ... OP_ENDIF itself, so it refuses both as Plumb does: all 44 of the <3-byte nonce> OP_DROP <key> OP_CHECKSIG spends in block 976646 and all 104 multisig spends since the fork that carry an OP_FALSE OP_IF envelope, as your 3-of-5 does. -rejectbareenvelopes and -rejectdeadbranches add further cases to that count. With -acceptnonstddatacarrier set, the count is held to -datacarriersize instead.
The fix for #4 is in #5. Closing this one; comment here if anything in filters.json reads wrong.
Activity
jasonsopko commentedon Oct 19, 2026
Thanks for the note.
plumb/filters.jsonis the reference: for each option it names a branch and the commit Plumb merges, and the diff from the Knots release tag (v29.4.2.knots20260508) to that commit is the rule. The exception is-rejectfakemultisig, which sits on-rejectbareenvelopes: diff it from c1d056e, the-rejectbareenvelopescommit, instead. The README and FILTERS.md summarize it.Neither case has a size floor, and your reading matches what the nodes do. In both the data sits in an input, and Knots refuses any data carrier bytes it counts in an input unless
-acceptnonstddatacarrieris set (txn-datacarrier-nonstandard, insrc/validation.cpp). Stock Knots counts<data> OP_DROPandOP_FALSE OP_IF ... OP_ENDIFitself, so it refuses both as Plumb does: all 44 of the<3-byte nonce> OP_DROP <key> OP_CHECKSIGspends in block 976646 and all 104 multisig spends since the fork that carry anOP_FALSE OP_IFenvelope, as your 3-of-5 does.-rejectbareenvelopesand-rejectdeadbranchesadd further cases to that count. With-acceptnonstddatacarrierset, the count is held to-datacarriersizeinstead.The fix for #4 is in #5. Closing this one; comment here if anything in filters.json reads wrong.