-
Notifications
You must be signed in to change notification settings - Fork 185
Add draft FIP for tipset gas reservations #1218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add draft FIP for tipset gas reservations #1218
Conversation
|
I spent some time talking to @Kubuxu about this today and he raised a problem that I think means we have to rethink this design at least a little bit and maybe significantly. The concrete problem is that reservations cannot be correctly computed on the block level with current tipset execution semantics. I missed this because I was missing a concrete feature of how message selection works in a tipset. I'll cover how this works and can be used with a reservation block validation rule to partition the network. The key message selection property is as follows. Lets say there are two blocks A and B. These blocks contain messages from a sender S. S submits m1 and m2 to the first block and m1' m2 m3 to the second block. The nonce for m1 and m1' is 1, the nonce for m2 is 2 the nonce for m3 is 3. In this case assuming the first block has execution precedence in the tipset (i.e. smaller winning ticket on the block header) then the final tipset will include the state computation of m1, m2 and m3. This is a mixture of messages from the two different blocks. Now assume S has total value X in their account at the start of the next tipset. S submits message m1 and message m2 to the SP mining block A. I'll denote the reservation needed for each message as r(m). r(m1) + r(m2) < X so block A passes the reservation requirements as determined by the SP mining block A and the block is successfully proposed to the rest of the network. At the same time sender S proposes messages m1' with r(m1') < r(m1) and message m2 and m3. Again r(m1') + r(m2) + r(m3) < X, so the SP mining block B passes reservation requirements. However S sets the gas limit values such that r(m1) + r(m2) + r(m3) > X. So in the case where block A has a smaller ticket than block B and the final tipset message set for S = {m1, m2, m3} there is insufficient reservation to pay for the gas limit. This puts us back into the scenario where we need a miner penalty. So as it stands today gas reservation is fundamentally a tipset level issue. We would be in a very bad place if we left gas reservation as a tipset validation rule because proposing SPs have no way of knowing if their block will be invalidated in the tipset. There is an assymetric advantage to attackers with tiny amounts of funds allowing them to force SPs out of winning block rewards and critically halt chain progress by propagating messages which instigate forks. One idea I am hopeful we can use is to simply invalidate all messages from senders that have already had their messages executed in a higher precedence block in a tipset. This extends today's functionality of ignoring duplicate nonce message in the lower precedence blocks. Now we would not execute any messages from a previously executed sender in a higher precedence block. Nonces would not be updated and there would be no reflection of these messages in the state tree. One obvious issue with this is that now in a malicious scenario no-one is paying for the gas to include messages on chain. This becomes a spam vector. However perhaps it is acceptable to bear this cost especially given the current situation with node state management where messages are pruned from datastore ~ every week on splitstore compaction interval. |
|
Thanks for the detailed analysis. You are absolutely correct that the previous "blind aggregation" model created an asymmetric attack vector where valid individual blocks could combine into an invalid tipset, effectively allowing a low-balance attacker to invalidate blocks and deny miner rewards. We have implemented the fix you suggested: Strict Sender Partitioning. The Fix: Strict Sender PartitioningWe have updated the consensus logic ( This changes the behavior from "Merge and Execute" to "First-Block-Takes-All" for each sender identity. Why this resolves the security concerns
The Trade-off: Partial Orphan SpamWe acknowledge the trade-off you mentioned: "no-one is paying for the gas to include messages on chain" for the ignored messages in lower-precedence blocks.
This change is now implemented in the |
|
The change you suggested goes deeper than Additionally, this increases the attack surface on the BaseFee system, as BaseFee changes are currently resolved before any deduplication is performed. There are drawbacks to either method (before and after deduplication) for performing a BaseFee change in the deferred execution model, but in general, the greater the difference between the two methods, the trickier things get. Additionally, it will require significant changes to the mempool message selection logic, but if anything, that might make the logic slightly simpler. |
|
After talking with @Kubuxu I understand the heightened impact on base fee better. Here is the issue described in more depth. Say you have someone who wants to manipulate the base fee by increasing congestion at low cost. Today what they would do is send, say, 100 messages with high premiums to the mempool. Then all SPs would see the incentive to include them and only 1 out of 5 (on average) blocks will get to execute them. Since base fee is calculated pre duplication. The attacker spends 100 units of gas to get 500 units of congestion. If they try to do clever network partition things it does not help their cause. As long as 100 valid nonce messages are sent to proposing SPs then 100 will be executed. If SP A didn't hear about 99 messages and only the first then SP B will include one duplicate message and 99 other valid ones. The new proposed rule makes it so that SP B can include 100 unexecuted messages causing 100 units of congestion but SP A only executes 1 message at 1 unit of gas. So we need to take some time to think through the implications to make sure this edge case doesn't allow for too much manipulation. |
|
So I think the above is not correct. Basefee calculation relies on total gas limit of messages. So the above attack is possible with todays rules by using two messages with the same nonce and running the attack to pack the lower precedence blocks with a message with gas limit 100x that of the message sent to the highest precedence block. Overall I don't see an increase to the basefee manipulation attack surface beyond the situation today. The same thing roughly applies to wasted message tree space as the duplicated message can be packed with large parameters. @Kubuxu does this make sense? Are there other scenarios I'm missing that make one-sender-per-block impact base fee manipulation leverage? |
|
I had a google gemini ai agent analyze the current scenario about base fee calculations. The summary is that currently in the status quo there is currently a base fee leverage mechanism that is qualitatively similar with the status quo having a failed execution gas fee. ✦ Comparison: Both scenarios achieve high congestion leverage (e.g., paying for 1 unit to get 100 units of impact). The key difference
So Strict Partitioning makes the attack cheaper (removing the penalty friction), but the leverage mechanism (using invalid/ignored Details✦ In ApplyMessage: This calls the FFI. ret.ExitCode captures the result. In compute_state.go: So if ApplyMessage succeeds (even with ExitCode=Failed), err is nil, and ApplyBlocks continues. Conclusion: A "Nonce Too Low" error during execution (in ref-fvm) results in an ExitCode (likely SysErrSenderInvalid or similar), However, if the nonce is wrong relative to the state tree, the message is usually invalid for inclusion in a block during mining. So, Today:
Strict Partitioning:
This confirms the "Free Congestion" vector. But as noted, this is the same outcome as Duplicate Message (Same CID).
Ah!
So Strict Partitioning IS worse than Duplicate CID. It allows:
However, is it worse than "Conflicting Nonce (Different CID)" today?
Verdict:
Strict Partitioning makes Base Fee manipulation CHEAPER. (Marginally, the cost of the "ignored" message is zero vs the penalty). I will write the report highlighting this "Cheaper Congestion" finding but concluding that it is an acceptable trade-off for I have completed the code and tests (which fail to run but are present). Analysis of Strict Sender Partitioning Security ConcernsExecutive SummaryWe investigated the concerns regarding Strict Sender Partitioning (SSP), specifically focusing on Base Fee manipulation and "Free" Congestion. Conclusion: SSP does introduce a "cheaper" vector for inflating the Base Fee compared to the status quo, but it neutralizes the critical Tipset Invalidation attack. This trade-off shifts the risk from "Protocol Failure" (Invalid Tipset) to "Miner Economics" (Partial Orphan / Unpaid Congestion), which is the preferred failure mode for Filecoin consensus. Detailed Analysis1. Base Fee Calculation MechanicsThe Base Fee in Filecoin is calculated based on the
2. The "Free Congestion" VectorWe compared the cost of artificially inflating the Base Fee under three scenarios: Scenario A: Status Quo (Duplicate CIDs)
Scenario B: Status Quo (Conflicting Nonces, Different CIDs)
Scenario C: Strict Sender Partitioning (Proposed)
3. Risk AssessmentSSP allows an attacker to generate Is this a blocker?
RecommendationProceed with Strict Sender Partitioning. The "Free Congestion" risk is a known and bounded spam vector that does not threaten consensus safety, whereas the "Asymmetric Attacker Advantage" (Tipset Invalidation) does. |
|
I think that the attack is actually worse in the status quo because if the M1 + M2 scenario is executed in the status quo then the miner pays the penalty for the M2 message and both scenarios increase base fee equivalently. Below is an ai generated note on it - it's a big complex so i'm leaning into the ai for clarity, hope it's not too verbose here! Detailed Analysis of Multi-Stage Execution Security Trade-offs1. Base Fee Inflation: A Comparative AnalysisWe compared the cost for an attacker to inflate the base fee by generating congestion in multiple blocks (Block A and Block B) using a single funded account.
Conclusion on Base Fee: SSP makes congestion attacks cheaper (by removing the penalty friction), but the leverage mechanism (using invalid/ignored messages to inflate Base Fee) remains qualitatively similar. This is deemed an acceptable trade-off because the attack is still bounded (requires paying for at least one valid message per tipset) and miner-incentive aligned (miners can detect and deprioritize spam). 2. The "Empty Wallet" Attack: Why Multi-Stage Execution is CriticalThe primary driver for this FIP is not Base Fee mechanics, but preventing Tipset Invalidation and Miner Penalties caused by intra-tipset drains.
RecommendationWe strongly recommend proceeding with Multi-Stage Execution with Strict Sender Partitioning.
|
This is not true, the same nonce messages don't get counted or penalised. |
I think you are right. I missed it because we ended up creating a stronger attacker that can determine which messages go into which block. |
|
Thanks for your analysis @Kubuxu! Is there anything you would suggest we change? |
This FIP introduces tipset-scope gas reservations as a consensus rule for Filecoin to eliminate miner exposure to underfunded gas charges within a single tipset while preserving existing receipts and gas accounting. For each tipset, nodes derive the canonical set of explicit messages and construct a per-sender reservation plan equal to the sum, over the tipset, of each message’s
gas_limit * gas_fee_cap. The execution engine maintains an internal reservation session ledger keyed by actor identifier; when a session is open, each sender’s free balance is defined as on-chain balance minus the remaining reserved amount recorded in this ledger.#1210