Skip to content

Tracking Plumb's filters as policy overlays in bitcoin-kernel #3

Closed

Description

@melvincarvalho

Hi, a courtesy note rather than a bug.

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.

Activity

  1. jasonsopko commented on Oct 19, 2026

    @jasonsopko
    Contributor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions