RFC: Minimum-bid PoX (to thwart Bitcoin MEV)

Hey folks,

This is an RFC for a consensus-breaking change to the mining protocol in order to provide a minimum-bid PoX payout. If the aggregate PoX payout – defined as the sum of all block-commits’ payouts – does not meet a protocol-defined minimum value, then no sortition takes place in that Bitcoin block.


The good news is that @friedger and @Babo discovered that F2Pool, currently the 3rd-largest Bitcoin miner, is also a Stacks miner. The bad news is that F2Pool, being a Bitcoin miner, currently ensures that their Stacks miner wins 100% of the time in the Bitcoin blocks they produce (about 14% of all Bitcoin blocks). Doing so is trivial: F2Pool simply ignores other Stacks miners’ block-commit transactions when creating a Bitcoin block, thereby ensuring that their Stacks miners’ block-commit is the only block-commit in that Bitcoin block. Moreover, F2Pool’s Stacks miner only mines in F2Pool-produced blocks.

F2Pool’s behavior is currently allowed by the Stacks consensus algorithm. Normally in Stacks, miners must mine for a few consecutive Bitcoin blocks in order to have a non-negligible chance of winning. This ramp-up period prevents opportunistic miners who also stack STX from only mining when their PoX addresses are up for reward. But in the event that a ramping-up miner is the only miner in that Bitcoin block, then even though they’d otherwise have a negligible chance of winning (1/(2^256) odds), the fact that their chance is still non-zero when they’re the only miner means that they’re guaranteed to win.

This is very cost-effective for F2Pool, and would be for any Bitcoin miner that did this. Their block-commit transactions pay a 0 sat/vbyte transaction fee, and their PoX payouts are a paltry 196 sats (well below the dust minimum). The only payment they make is the opportunity cost incurred by bumping the least-valuable Bitcoin transaction from their block and replacing it with their own block-commit. Given that a block-commit transaction is about 390 bytes, this means it costs F2Pool a few USD to produce a Stacks block worth over $1000 USD each time they mine a Bitcoin block.

This behavior was predicted earlier, and is actually a positive sign. It means that Stacks is now valuable enough that miners are starting to consider it as part of the Bitcoin MEV. It doesn’t hurt the Stacks chain, but if you’re Stacking, this sucks. Instead of paying Stackers BTC, F2Pool gets to keep their BTC while also winning Stacks blocks as often as they win Bitcoin blocks. This drives the Stacking APY down.

What to Do About It?

If we want to stop this, we’ll need to do another hard fork. Fortunately, the change is very small and can be done relatively quickly (before sBTC).

I think addressing this is important for two reasons. First, Stacking a very popular component of Stacks that has found product/market fit, and it would be a shame to see it destroyed by MEV. Second, Stacking plays a central role in sBTC by serving as the ongoing reward to sBTC wallet signers for being available to process sBTC unwrapping without charging the user a basis point fee.

To address this, I propose creating a minimum PoX bid function. If the aggregate PoX payout – that is, the sum of a Bitcoin block’s block-commit transactions – is less than the minimum bid, then no Stacks block wins. This way, F2Pool would be obliged to pay out an amount of BTC that is comparable to the total payouts from the other Stacks miners if it wants to win the Stacks block.

How would this work? The consensus rules would be need to be updated so that the system looks at the past B Bitcoin block’s aggregate PoX payouts, and if the current Bitcoin block’s aggregate PoX payout has less than F(B) satoshis, then there is no sortition.

What are B and F? B is a function of how much Bitcoin mining power we expect to participate in MEV. If it’s 100%, then this tactic is unworkable – we’d need to find some other way to set a minimum PoX payout. But if it’s 90%, then B would be at least 10. If it’s 95%, then B would be at least 20. As long as the window includes at least one honest Bitcoin block, then we have something to work with.

F is the function that takes the aggregate PoX payouts as input for each of the B blocks, and outputs the minimum PoX bid. We’d need to be careful about choosing F so that mundane events like Bitcoin flash blocks don’t needlessly punish honest Stacks miners. For example, a flash block can cause most but not all Stacks miners’ block-commits to get bumped to the next Bitcoin block, leaving behind only one or two valid block-commits.

This is where I can use your help. I don’t know what a good F value looks like right now, but I’m confident we can find one. I have all the block-commit data for the chain in a Google sheet. I’ve highlighted sortitions in red where the aggregate PoX payout was abnormally small, due to miner MEV. They’re all towards the bottom, but as you can see, they’re starting to pick up.

If you’re feeling ambitious, please make a copy of the sheet and propose values for F and B. We’d want F to ensure that F2Pool does not win any blocks, but other Stacks miners are not unfairly punished.

We’d love to hear from you!

Drop a comment below on what you think the values of F and B should be! Support your claims with charts and data. The change to the code is pretty small, so if we can find good values, we can ship a SIP quickly and get a hard-fork going to stop this MEV behavior.


When we plan the a hard fork, can we include the changes from RFC: L1 Speed Improvements as well?


I was going to ask a similar question. If the changes proposed in RFC: L1 Speed Improvements are implemented will that reduce the need for having a minimum-bid or do we envision these would work hand in hand well into the future?

The other consideration is also how soon these changes can be implemented and tested thoroughly. If the minimum-bid change is rather small and helps us get it out the door faster that could be a reason for going forward with that first.

1 Like

I made an attempt at back testing various values for how well the minimum-bid logic presented by @jude would work. I would appreciate it if someone can either confirm to have arrived at a similar conclusion or can check my work. Here is the summary of my findings. Attached is a google sheet that has the detailed logic.

Window Size False Positive (Percent of blocks with valid miners
that missed Sortition. Ideally this value would be 0%)
False Negative (Percent of blocks (since row 101896) where malicious miner was awarded the block anyway. We want this to be close to 0%) Malicious Blocks Saved (total of 11.24% of blocks where malicious since row 101896)
3 10.60% 3.82% 66%
4 9.59% 4.79% 57%
5 8.79% 5.63% 50%
6 8.06% 6.26% 44%
7 7.43% 6.90% 39%
8 6.89% 7.36% 35%
9 6.42% 7.66% 32%
10 5.98% 8.08% 28%
11 5.59% 8.46% 25%
12 5.26% 8.75% 22%
13 4.99% 9.03% 20%
14 4.73% 9.36% 17%
15 4.49% 9.57% 15%
16 4.27% 9.72% 14%
17 4.09% 9.93% 12%
18 3.91% 10.06% 10%
19 3.74% 10.16% 10%
20 3.57% 10.29% 8%

Link to spreadsheet: Muthu's Copy of PoX payouts over all time - Google Sheets


This RFC would only add the minimum PoX bid. The L1 speed improvements will take the better part of the year to implement and test, so they belong in a separate SIP.


Thank you @jude for the clarity and assuring the community that this is something that can be addressed in a timely manner. I am in favor.


Looks like a serious issue indeed! I support a resolution. Thanks to everyone involved in bringing this to light :pray:

If we’re going to do a quick fork, it would be wise to also get a resolution to the issue in where it currently takes 2 stacks blocks instead of 1 to fetch the Bitcoin block header (see issue here). Currently Stacks 2.1 doesn’t work as described in SIP-15 which is a problem for governance

@FriendsFerdinand is currently working on a PR. We’ll see if we can get something out by 9am ET today, if not it would make sense to get help from someone from the Core Engineering team here


Given the minimum-bid has a high percentage of false positive (percent of blocks with valid miners that missed sortition) (see message above), I also created an alternate version that defines F(B) as Minimum(Median(last B blocks)). But, this creates an even higher rate of false positives although it vastly reduces false negative.

So, then I tried including a percentage factor P. The idea being we are looking for the bid to be a certain percent of the min of median of last B blocks. Below is the false positive and false negative rates with different values for the percentage factor and window size of 10.

Percentage Factor (window size 10) False Positive False Negative Malicious Blocks Saved
0.1 0.48% 0.11% 99%
0.2 0.97% 0.08% 99%
0.3 1.69% 0.08% 99%
0.4 2.41% 0.08% 99%
0.5 3.23% 0.08% 99%
0.6 4.33% 0.08% 99%
0.7 5.73% 0.08% 99%
0.8 8.75% 0.08% 99%
0.9 13.60% 0.08% 99%
1 17.80% 0.08% 99%

Percentage factor of 0.5 would result in only half of the PoX payout returning while reducing to False Positive rate of 3.23% and achieving False Negative rate to 0.08% (compared to 5.98% false positive 8.08% false negative with a simpler F(B) that looks at minimum aggregate pay out of last 10 blocks).

Spreadsheet here for perusal. Min of Median PoX Bid (with percentage factor) - Google Sheets

Please let me know if there are any errors in my logic or if I have any misunderstanding in my interpretation of the proposal. Thanks.


Thanks for the proposal Jude. And sorry for crushing the party right away.

As some of us know - Stacks is confronted with a critical centralization problem. About half a year ago one mining entity gained >51% of the mining power and is censoring the blockchain. To be clear, at the moment they don´t censor transactions (as far as we know) but they rule out other miners who want to start mining. They simply don´t download their blocks from time to time and initiate siblings/forks. This leads to BTC losses, a centralized mining field and a lower stacking yield.

Since last September they are in control of 70-100% of the mining power most of the time!

Atm 77% due to the fact that the F2Pool miner joined the party with around 15%.

We understand that the actual MEV situation is critical for sBTC but unfortunately the SP2Z miner is the last anchor against a 100% centralized mining field at the moment.

For those who are in disbelief, we published a new stacks dump for 2.1 at: Stacks Dump

Have a look at the red (orphaned) blocks e.g. BTC Block 781607. SP11 won Stacks block 99153 but the entity simply ignored it and created a sibling in BTC Block 781607. No block reward for SP11.

You can find all addresses which belong to the entity at the end of the Dump (one color).

Btw. we had forks >4 blocks deep yesterday due to this issue/behavior. Kraken as an example confirms deposits after 4 blocks.

At the moment the entity earns around ~1BTC per day due to the missing competition. BTC which should partly belong to Stackers. What if they would decide tomorrow to raise the tx fees by let´s say 500%?

We appreciate an emergency hard fork but it must include a fix like RFC: L1 Speed Improvements if we want to call Stacks a decentralized blockchain again.

If we add a minimum payout before we solve this centralized situation, we will remove the final obstacle for the controlling entity.

1 Like

The minimum proposed is to be a function of the aggregate bids in the block. Not a minimum for each miner. Can you clarify how you think this provides an unfair advantage ?

The comment is about how removing MEV today effects the current mining landscape, not about technical details.

1 Like

Have a look at BTC Block 781455-781456 (Link). Small miners like SP2P and SPN8 produced correct blocks in an event where the entity was offline. Without these miners 3 out of 5 BTC Blocks (781451-781456) would be empty.
And the controlling entity would win+3000STX on top without a single commit. => It supports centralization.

Pre-Commits like proposed in “RFC: L1 Speed Improvements” could solve this isssue?

Another possible mechanism could use reward weighting. Mining rewards mature after a period of time, and in a weighting scheme, the rewards do not necessarily go directly to the block winner. Instead, the protocol looks at a window of block winners, and splits the reward over that window according to the proportion of funds committed during that bitcoin block.

For example,

Bitcoin block 1 → 3 miners participate, total committed funds are 1 BTC, block A is selected
Bitcoin block 2 → 3 miners participate, total committed funds are 1 BTC, block B is selected
Bitcoin block 3 → 1 miners participate, total committed funds are 0.001 BTC, block C is selected
Bitcoin block 4 → 3 miners participate, total committed funds are 1 BTC, block D is selected
Bitcoin block 5 → 3 miners participate, total committed funds are 1 BTC, block E is selected
Bitcoin block 6 → 3 miners participate, total committed funds are 1 BTC, block F is selected
Bitcoin block 7 → 3 miners participate, total committed funds are 1 BTC, block G is selected

Say the “reward window” is size 5. When Block A’s reward matures, its coinbase reward (let’s use 4 STX as the reward to simplify things) is split amongst the miners of A, B, C, D, E – weighted by the amount of funds committed in their bitcoin blocks. So miners of A, B, D, E get ~1 STX, and the miner of block C gets ~0 STX. When Block B’s reward matures, miners of B, D, E, F get ~1 STX, and the miner of block C gets ~0 STX. When Block C’s reward matures, miners of D, E, F, G get ~1 STX, and the miner of block C gets ~0 STX.

Obviously, this proposal would alter the incentive structure of the protocol (almost any change to the protocol does) and would require further investigation, but it would eliminate the coinbase incentive for MEV.


Another possible mechanism could use reward weighting . Mining rewards mature after a period of time, and in a weighting scheme, the rewards do not necessarily go directly to the block winner. Instead, the protocol looks at a window of block winners, and splits the reward over that window according to the proportion of funds committed during that bitcoin block.

This is interesting and seems more incentive aligned.

Ultimately, I think this is a good thing to happen now and discuss solutions before sBTC goes live. It’s also validating to see major BTC miners participating in STX!

Now that 2.1 is live we should have mining pools live soon so it would good to put extra attention on the efforts the Stacks Degens team is making with that. I can see the launch of these mining pools raising mining participation by at least 100x.


Hey everyone! Thanks for all the comments and suggestions here. @jude and I discussed this issue some weeks ago and in general, we’ve known about this potential MEV vector for a long long time. For example, I even responded to comments by @bergealex4 on Twitter about Bitcoin miners potentially doing this.

We’ve floated the idea of a minimum bid as a clear way to stop MEV from Bitcoin miners. It basically means that Bitcoin miners will have to bid at least a minimum amount of BTC to get the STX rewards (if they don’t bid at least the minimum amount then they get 0 STX even if they try to censor other miners).

The solution Jude proposed above is in-line with this thinking. Jude is debating what would be a good way to calculate the minimum bid. I think aiming for 90th percentile of the bids in the last 1,050 blocks (so approx one week) is one way to do it.

Also, it’s great that Stacks layer is becoming so successful that even Bitcoin miners are looking for MEV. This was only a theoretically thing earlier and now we have some evidence. We could’ve implemented the minimum bid earlier but thought the issue was very theoretical at that time and didn’t prioritize it enough. It can be prioritized now.

In terms of the actual implementation and roll out. I don’t think there is any need to rush the update. This mining pool has been doing this for weeks already. There is no direct impact on the protocol correctness. It’s a question of potentially reduced BTC rewards to stackers but the absolute reward rate is significantly up already from a few months ago. I’d personally treat this as any other upgrade that improves the network. Test it throughly. Also, consider if there are any other small tweaks after the 2.1 launch (like the mempool issue that Aaron discovered recently) that can also be packaged into the same release and then follow the standard upgrade process to put a new binary out.

If a new binary can be out within weeks that’d be amazing!


If this was not already implied: A possible approach could be to use the stacks miner Btc pre-commitments described from the rfc L1-speed increase (when live) to judge the difference between the aggregate amount of Btc that was precommited vs actual to determine whether to grant the Coinbase reward.


Agree with Muneeb, I don’t think there’s any rush on this. It’s doesn’t break Stacks and stacking rewards are way up in $$ terms regardless. It was expected this would happen at some point. Many may not agree but I wouldn’t even be worried if all miners started doing this now and PoX rewards went to zero in the short term. It doesn’t even break sBTC fundamentally. While Stacking has Product/Market Fit there will be many other Product/Market Fits from apps built on top of it. It’s validating miners are taking note of STX and there’s several viable ideas on how to counter this we can explore to figure this out and implement before sBTC goes live.

1 Like

I believe stacking yield is one of the most compelling use cases for hodling STX. I fear concentrating too much on the decentralization of mining and/or taking more time to implement a hard fork to correct this issue will be to the detriment of stackers earning their associated yields. I know continuing the network as it currently is doesn’t break the network at the moment but Stackers and the TVL they provide should not be put on the back burner. There are far more stackers than miners yet both are equally as important to the successful operation of the network imo. I’m part of the keep yields high camp as I ultimately believe this is what will also attract the most users to Stacks. We start accepting the fact of lower yields now, regardless of its USD value, stackers will have a hard time getting that value back :weary:

I don’t think anyone is arguing that the update should not go live soon. Technically the change is not very complicated so it can be tested relatively quickly. My comment is more like that instead of doing something within days and rushing, it is OK to take a few weeks and not rush this out. I do not think a few weeks make any meaningful difference if the tradeoff is that developers can do more testing and follow the standard procedure for pushing new upgrades. It will not take months or years to push this live :slight_smile:


We appreciate this proposal and look forward for an implementation. Anyway, we strongly believe that it must go hand in hand with the proposal: “Improve Throughput by Disincentivizing Missed Sortitions”.

Otherwise Stacks won’t get decentralized again - upcoming decentralized mining pools will suffer big losses (like other independent and smaller miners at the moment) and won´t be able to compete.