Skip to content

fix: refresh the basefee sharing percentage from the inbox at runtime - #4

Closed
davidtaikocha wants to merge 1 commit into
masterfrom
bugfix/refresh-basefee-sharing-pctg
Closed

davidtaikocha wants to merge 1 commit into
masterfrom
bugfix/refresh-basefee-sharing-pctg

Conversation

@davidtaikocha

Copy link
Copy Markdown
Member

🧩 What was the bug?

The basefee sharing percentage stamped into every preconfirmed block's extraData (byte 0) was read from Inbox.getConfig() exactly once, at startup: ProtocolConfig::from in Taiko::new copied it into a plain u8, and Node::new cloned that struct into the block advancer. Nothing ever updated it.

The percentage is an immutable of the inbox implementation, so it changes whenever the DAO upgrades the inbox proxy. taikoxyz/taiko-mono#22127 (Proposal0024) does exactly that on mainnet, raising it from 75 to 100. The driver derives the blocks of a proposal with the value the inbox emits in the Proposed event, so a Catalyst node still on the cached 75 after the upgrade keeps building blocks that get replaced once they are proposed: same transactions, different extraData and state root. That is one preconfirmation reorg per block, for as long as the node is not restarted.


📎 Related issues (optional)

taikoxyz/taiko-mono#22127 (Proposal0024, the upgrade that changes the value).


🔧 What's been fixed?

  • ProtocolConfig keeps basefee_sharing_pctg behind an Arc<AtomicU8>, so every clone of the config (the block advancer's included) sees the current value. ProtocolConfig::new(chain_id, pctg) is added and from delegates to it; set_basefee_sharing_pctg returns the previous value.
  • ProtocolConfig::spawn_basefee_sharing_pctg_refresh runs a background task that re-reads the percentage through a caller-supplied fetch every period, logs a change at info, keeps the last value on an RPC error (retried next tick), and exits when the cancellation token fires. It returns the JoinHandle.
  • create_shasta_node spawns it with EthereumL1::fetch_inbox_config and a period of one L1 slot (L1_SLOT_DURATION_SEC), right after Taiko is built. One getConfig call per L1 slot, off the block-building path.

After an inbox upgrade, blocks built from the next L1 slot on carry the new value, with no restart.


💬 Anything else reviewers should know?

  • What this does not avoid. Blocks preconfirmed before the upgrade executes and carried by the first proposal after it are still re-derived with the new value, once. Their percentage is fixed by the proposal that carries them, which is built after the blocks; no node-side change can alter that. Executing the upgrade right after a proposal lands bounds it to the blocks of a single proposal, which now also covers at most one L1 slot of blocks built before the refresh picks the change up. With this fix the reorg happens once, at the switch, instead of on every block until someone restarts the node.
  • The realtime mode has its own copy of ProtocolConfig (realtime/src/l1/protocol_config.rs) and passes the percentage by value into its node and submitter. It is not touched here.
  • cargo clippy --tests trips a pre-existing unusual_byte_groupings lint in shasta/src/l2/extra_data.rs (a test literal); CI lints without --tests, and this PR leaves that file alone.

✅ Checklist

  • Confirmed the bug no longer occurs: refresh_tracks_the_inbox_and_keeps_the_last_value_on_errors drives the refresh loop with a fake inbox under paused time, sees the value flip 75 → 100 on the next tick, stay at 100 through a failed read, and the task exit on cancellation; clones_share_the_basefee_sharing_pctg pins that the block advancer's clone observes the update.
  • Existing tests pass: cargo test -p shasta --lib --locked (64 tests), cargo fmt --all -- --check, cargo clippy -p shasta --all-features --locked -- -D warnings.
  • Added new test(s) for the bug.
  • The branch with the bugfix is named bugfix/<name>: bugfix/refresh-basefee-sharing-pctg.

🤖 Generated with Claude Code

The percentage stamped into every preconfirmed block's extraData was read
once at startup, copied by value into ProtocolConfig and cloned into the
block advancer, so it could only change with a restart. It is an
immutable of the inbox implementation and changes when the DAO upgrades
the inbox proxy (taikoxyz/taiko-mono#22127 raises it from 75 to 100).
A node still on the stale value after the upgrade builds blocks the
driver re-derives with the new value once they are proposed: the same
transactions with a different extraData and state root, i.e. one
preconfirmation reorg per block until the node restarts.

ProtocolConfig now keeps the percentage behind an Arc<AtomicU8> shared by
every clone, and the shasta node spawns a task that re-reads it from
Inbox.getConfig() every L1 slot, logging a change, keeping the last value
on RPC errors and exiting on shutdown. Blocks built from the next slot
after an upgrade carry the new value with no restart.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant