Skip to main content

Transaction Filtering

Bitcoin Knots provides comprehensive tools to filter transactions you consider spam from your mempool. This is one of the most significant differences from Bitcoin Core and a primary reason for Knots' 850% adoption surge in 2024-2025.

Transaction Filtering FlowTransaction Filtering Flow

Why Filter Transactions?

The Problem

Since late 2022, several protocols have emerged that embed non-financial data into Bitcoin transactions:

ProtocolData LocationUTXO ImpactPrunable?
Ordinals/InscriptionsWitness data (OP_FALSE OP_IF)MinimalYes
BRC-20 TokensInscriptions (JSON)MinimalYes
RunesOP_RETURNNoneYes
StampsBare multisig outputsSevereNo

These protocols have caused:

  • Mempool congestion during high-activity periods
  • Fee spikes that price out small transactions
  • UTXO set bloat (80M → 160M+ UTXOs in 2023)
  • Increased node resource requirements

The Philosophy

Bitcoin Knots gives node operators choice:

"Bitcoin works with the assumption that a majority of miners are honest, not malicious. Besides, spam-filtered blocks often have more fees anyway for some reason." — Luke Dashjr

You decide what your node relays. These are policy rules, not consensus rules — your node still accepts all valid blocks regardless of your filter settings.

How Each Protocol Works

Understanding how these protocols work helps you understand what the filters target.

Ordinals & Inscriptions

Ordinals assign a serial number to each satoshi based on mining order. Inscriptions attach data to these satoshis using a clever trick that bypasses the traditional datacarriersize limit:

OP_FALSE
OP_IF
OP_PUSH "ord"
OP_PUSH 1 # content-type tag
OP_PUSH "image/png" # MIME type
OP_PUSH 0 # content tag
OP_PUSH [image data] # actual content
OP_PUSH [more data] # split into 520-byte chunks
OP_ENDIF

Why this bypasses limits:

  • Traditional datacarriersize only applied to OP_RETURN
  • The OP_FALSE OP_IF ... OP_ENDIF envelope is technically valid script that never executes
  • Data is stored in the witness field, which gets a 75% fee discount (SegWit)
  • This was filed as CVE-2023-50428 by Luke Dashjr

BRC-20 Tokens

BRC-20 tokens embed JSON in inscriptions:

{"p":"brc-20","op":"deploy","tick":"ordi","max":"21000000","lim":"1000"}
{"p":"brc-20","op":"mint","tick":"ordi","amt":"1000"}
{"p":"brc-20","op":"transfer","tick":"ordi","amt":"100"}

The token rules aren't enforced by Bitcoin — off-chain indexers interpret the JSON and track balances. The inscriptions just store the data.

Runes

Runes use OP_RETURN more efficiently than BRC-20:

OP_RETURN
OP_13 # Rune protocol identifier
[encoded data] # Rune ID, amounts, outputs

Runestones (valid Runes messages) define token operations. Cenotaphs (malformed runestones) cause tokens to be burned.

Advantage over inscriptions: OP_RETURN outputs are provably unspendable, so they don't bloat the UTXO set.

Stamps (Most Harmful)

Bitcoin Stamps are the most problematic because they abuse bare multisig outputs:

OP_1 [pubkey1] [pubkey2] [pubkey3] OP_3 OP_CHECKMULTISIG

The "public keys" are actually encoded image data. These outputs:

  • Look spendable to nodes (but aren't — the "keys" are fake)
  • Must be stored in the UTXO set forever
  • Cannot be pruned by pruned nodes
  • Increase every node's memory and storage requirements

This is why permitbaremultisig=0 is particularly important.

Configuration Options

Quick Reference

OptionDefault (Knots)Effect
rejectparasites1 (on)Filters CAT21 spam
rejecttokens0 (off)Filters Runes
datacarriersize83Max OP_RETURN bytes
datacarriercost1Weight multiplier for data
maxscriptsizevariesMax witness script size
permitbaremultisig0 (off)Blocks Stamps
acceptnonstddatacarrier0 (off)Strict OP_RETURN format
corepolicy0 (off)Use Core defaults instead

Detailed Options

rejectparasites

Filters CAT21 spam transactions. Enabled by default in Knots.

bitcoin.conf
# Default in Knots - filters CAT21 spam
rejectparasites=1

# Disable filtering
rejectparasites=0

Note: This option specifically targets CAT21 spam, not inscriptions or ordinals in general.

rejecttokens

Filters Runes protocol transactions.

bitcoin.conf
# Filter Runes
rejecttokens=1

Detects OP_RETURN outputs starting with OP_13 (the Runes identifier). Updated in v29.1 to also detect "OLGA" spam variants.

datacarriersize

Maximum size of data in OP_RETURN outputs.

bitcoin.conf
# Knots default (legacy compatibility)
datacarriersize=83

# Traditional limit (80 bytes of data)
datacarriersize=83

# Stricter (42 bytes - enough for hashes)
datacarriersize=42

# Disable all OP_RETURN relay
datacarriersize=0

Why 83? 1 byte OP_RETURN + 1-2 bytes pushdata + 80 bytes data = ~83 bytes.

Filtering Runes

Luke Dashjr's recommendation for filtering Runes: set datacarriersize=0 in bitcoin.conf. Source

datacarriercost

Adjusts the "virtual size" calculation for data-carrying bytes, making data more expensive.

bitcoin.conf
# Default - data bytes count as 1 vbyte each
datacarriercost=1

# Make data 4x more expensive (removes witness discount)
datacarriercost=4

# Effectively prohibit large data (very expensive)
datacarriercost=10

Higher values mean data-heavy transactions need higher fees to enter your mempool.

maxscriptsize

Limits the total witness script size per input.

bitcoin.conf
# Limit witness scripts (targets large inscriptions)
maxscriptsize=10000

In v29.1+, this applies to the entire witness stack of each input, closing evasion attempts.

permitbaremultisig

Controls relay of bare multisig outputs. Disabled by default in Knots.

bitcoin.conf
# Default in Knots - blocks Stamps
permitbaremultisig=0

# Allow bare multisig (Core behavior)
permitbaremultisig=1

This is critical for preventing UTXO bloat from Stamps.

acceptnonstddatacarrier

Controls whether non-standard OP_RETURN formats are accepted.

bitcoin.conf
# Default in Knots - strict format only
acceptnonstddatacarrier=0

# Allow any OP_RETURN format
acceptnonstddatacarrier=1

corepolicy

Revert to Bitcoin Core's default policies (disabling Knots filtering).

bitcoin.conf
# Use Core-compatible policies (no filtering)
corepolicy=1

Useful for testing or if you want Knots features but Core relay behavior.

Maximum Filtering (Ocean-style)

Used by Ocean mining pool:

bitcoin.conf
# Inscriptions and ordinals
rejectparasites=1

# Runes and tokens
rejecttokens=1

# Minimal OP_RETURN (or 0 to disable)
datacarriersize=42

# Remove witness discount for data
datacarriercost=4

# Block Stamps
permitbaremultisig=0

# Strict OP_RETURN format
acceptnonstddatacarrier=0

# Limit script sizes
maxscriptsize=10000

Moderate Filtering (Knots Default)

Default Knots behavior:

bitcoin.conf
# These are default in Knots - shown for clarity
rejectparasites=1
permitbaremultisig=0
acceptnonstddatacarrier=0
datacarriersize=83

No Filtering (Core-compatible)

If you want Knots features but Core relay policy:

bitcoin.conf
corepolicy=1

Or explicitly:

bitcoin.conf
rejectparasites=0
rejecttokens=0
permitbaremultisig=1
acceptnonstddatacarrier=1
datacarriersize=100000

How Detection Works

Pattern Matching

Knots examines transaction structure for known patterns:

Inscriptions:

Witness contains: OP_FALSE OP_IF "ord" ... OP_ENDIF

Runes:

Output script: OP_RETURN OP_13 [data]

Stamps:

Output script: OP_n [pubkey...] OP_m OP_CHECKMULTISIG
(where pubkeys don't correspond to valid points)

Limitations

Heuristic Filtering

Filtering is based on pattern matching, not perfect detection. Determined actors can:

  • Modify envelope formats slightly
  • Use novel encoding schemes
  • Pay higher fees to get into blocks directly

These are policy tools, not consensus rules. They reduce spam propagation but cannot prevent it entirely.

Monitoring Filtered Transactions

Check Filter Status

# See current mempool policies
bitcoin-cli getmempoolinfo

# Check specific policy settings (if exposed via RPC)
bitcoin-cli logging '["mempool"]'

Watch Debug Log

# Monitor rejections in real-time
tail -f ~/.bitcoin/debug.log | grep -iE "reject|filter|policy"

# Count rejections
grep -c "rejected" ~/.bitcoin/debug.log

Test Transaction Acceptance

# Test if a transaction would be accepted
bitcoin-cli testmempoolaccept '["<raw_transaction_hex>"]'

Impact on Mining

If you mine (solo or pool), your filtering affects block templates:

# Get block template (filtered based on your policy)
bitcoin-cli getblocktemplate '{"rules":["segwit"]}'

Revenue considerations:

  • Filtered transactions = potentially missed fees
  • However, Dashjr notes "spam-filtered blocks often have more fees anyway"
  • Ocean pool runs filtered and reports competitive revenue

Per-Template Overrides (v27.1+)

# Override policy for specific template
bitcoin-cli getblocktemplate '{
"rules": ["segwit"],
"minfeerate": 10
}'

The Filtering Debate

Arguments For Filtering

  1. Resource protection — Reduces mempool churn and bandwidth
  2. UTXO set health — Especially important for Stamps
  3. Network sustainability — Prevents unbounded growth
  4. User choice — Node operators decide their policy
  5. Historical precedent — Spam filtering has existed since 2013

Arguments Against Filtering

  1. Revenue — May miss some fee-paying transactions
  2. Censorship concerns — Who defines "spam"?
  3. Effectiveness — Miners ultimately include what they want
  4. Cat and mouse — Spammers adapt to filters

The Reality

  • Filtering is your node's policy — you're not preventing others from mining transactions
  • Even without filtering, you can't prevent data on Bitcoin
  • These are relay policies, not consensus changes
  • Most pools don't filter, so filtered transactions still get mined

GUI Configuration

Bitcoin Knots includes GUI options for filtering (unlike Core):

  1. Settings → Options → Network tab
  2. Look for policy options
  3. Set datacarriersize, permitbaremultisig, etc.

The GUI exposes what would otherwise require editing bitcoin.conf.

Verifying Your Configuration

After setting options, verify they're active:

# Restart bitcoind to apply changes
bitcoin-cli stop
bitcoind -daemon

# Check that node started with your settings
grep -E "datacarrier|permit|reject" ~/.bitcoin/debug.log | tail -20

See Also

Sources