# Full OP\_RETURN value pruning

**URL:** <https://delvingbitcoin.org/t/full-op-return-value-pruning/3026>\
**Category:** Implementation\
**Created:** [November 2, 2026, 8:30pm UTC](https://delvingbitcoin.org/t/full-op-return-value-pruning/3026 "2026-11-02T20:30:37Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![bkeroack](https://delvingbitcoin.org/user_avatar/delvingbitcoin.org/bkeroack/32/2418_2.png) [@bkeroack](https://delvingbitcoin.org/u/bkeroack)\
**Post date:** [November 2, 2026, 8:30pm UTC](https://delvingbitcoin.org/t/full-op-return-value-pruning/3026/1 "2026-11-02T20:30:37Z")

</div>

satd is the first Bitcoin node implementation to allow optional full OP\_RETURN value pruning. It is controlled by these options:

- `-pruneopreturn=N` (N is the number of blocks behind tip, 288 minimum to match NODE\_NETWORK\_LIMITED guarantee)
- `-pruneopreturnsize=X` (X is the value size in bytes, greater than or equal to X will be pruned)
- `-restoreopreturns` (stop pruning and restore all pruned blocks; mutually-exclusive with above options)

Why do OP\_RETURN value pruning? The recent BIP-110 controversy made it apparent that a certain proportion of node runners care deeply about OP\_RETURN value sizes and what they see as spam on the blockchain. My personal view is that an objective analysis of mainnet shows that OP\_RETURN value footprint is negligible currently. That said, the philosophical argument that non-financial data is spam and doesn’t belong on the chain is real and resonates with some people. Since value pruning can be implemented without breaking consensus or most full node functionality, I believe it’s better to allow this flexibility in node software to allow operators to express their preferences. If all major implementations adopt this type of flexibility hopefully we can avoid future distracting controversies.

When you combine pruning with the [Transaction Filter Policy language](https://delvingbitcoin.org/t/cost-bounded-transaction-filtering-language/2966) you can also prevent matching transactions from being relayed or added to block templates. Use a conditional like `sum outputs (out.op_return_size) > 80` in your filter rule (see the [manual](https://epochbtc.github.io/satd/policy.html) for details). This addresses the “I don’t want my node assisting or storing large OP\_RETURN values” concern.

The implementation punches holes in the on-disk block files, redacting values that match the threshold. This uses the FALLOC\_FL\_PUNCH\_HOLE | FALLOC\_FL\_KEEP\_SIZE (Linux) and F\_PUNCHHOLE (MacOS) syscalls to redact values in place.

There are some consequences of pruning OP\_RETURN values:

1. Your node advertises NODE\_NETWORK\_LIMITED just like a standard pruned node, which means you won’t serve blocks to most peers (even if you have them intact, but see below for mitigation).
2. The disk usage will go **up** , not down. Hole-punching only returns storage to the system when it meets or exceeds the block size, typically 4kb. The vast majority of OP\_RETURN values are less than this, so very little space reclaiming will happen. On top of that, every pruned block requires extra index entries to preserve txids and allow reindexing. So net disk usage tends to go UP with value pruning, not down.
3. Your node can no longer serve raw transaction bytes when values are pruned. Those JSON-RPC requests are refused with an error (for example, “-1 Block not available (pruned data)”). Blocks without pruned values are returned normally. `getblock` at verbosity 1 returns an additional custom field, ex: `"opreturn_stripped": { "transactions": 2, "outputs": 2, "bytes": 18432 }`. Verbosity 2 returns original txid, but no hex and the additional field `"opreturn_stripped": true.`
4. SSDs make it essentially impossible to securely delete anything, so the pruned values are likely forensically recoverable for a period of time.
5. Snapshots on CoW filesystems like ZFS, btrfs will retain the bytes despite pruning.

satd supports a special option: `-pruneopreturnpeers=intact` (default: “pruned”) which causes the node to advertise NODE\_INTACT\_BLOCKS (service bit 28, within bits 24-31 that are reserved by Core for temporary experiments). This allows satd to serve whatever intact non-pruned blocks it has to peers (pruned blocks return `notfound`). Other satd 0.7.0+ peers will recognize this service bit and will request blocks even though the node is NODE\_NETWORK\_LIMITED. Core peers will likely continue to treat the peer as fully pruned and will not request blocks.

OP\_RETURN pruning is reversible. Use the `-restoreopreturns` option to trigger the node to re-download all pruned blocks as background restore process (node stays NODE\_NETWORK\_LIMITED during this process). Once complete, the node switches back to NODE\_NETWORK and fully serves peers blocks as before. Then the option can be dropped and the node works normally from that point forward.

You can download and install [satd 0.7.0 here](https://github.com/epochbtc/satd/releases/tag/v0.7.0). The manual talks about OP\_RETURN pruning in the [Disk Footprint chapter](https://epochbtc.github.io/satd/disk-footprint.html#op_return-data-pruning). Any feedback or questions are welcome!
