From fd7e08eead15864a3a84e7b6cf300db4c64f2386 Mon Sep 17 00:00:00 2001 From: refcell Date: Fri, 22 Nov 2024 13:22:38 -0500 Subject: [PATCH] feat(book): Hardfork Change Example (#306) ### Description Adds an example to the `op-alloy` book that walks through implementing `L1BlockInfo` hardfork changes in `op-alloy`. Closes #279 --- book/src/SUMMARY.md | 1 + book/src/examples/README.md | 1 + .../examples/new-l1-block-info-tx-hardfork.md | 113 ++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 book/src/examples/new-l1-block-info-tx-hardfork.md diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 61535472..69b127ab 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -15,6 +15,7 @@ - [Batches](./building/protocol/batches.md) - [Examples](./examples/README.md) - [Load a Rollup Config](./examples/load-a-rollup-config.md) + - [Create a new L1BlockInfoTx Hardfork Variant](./examples/new-l1-block-info-tx-hardfork.md) - [Transform Frames to a Batch](./examples/frames-to-batch.md) - [Transform a Batch into Frames](./examples/batch-to-frames.md) - [Contributing](./CONTRIBUTING.md) diff --git a/book/src/examples/README.md b/book/src/examples/README.md index ab5bf420..7e241ba7 100644 --- a/book/src/examples/README.md +++ b/book/src/examples/README.md @@ -3,5 +3,6 @@ Examples for working with `op-alloy-*` crates. - [Load a Rollup Config for a Chain ID](./load-a-rollup-config.md) +- [Create a new L1BlockInfoTx Hardfork Variant](./new-l1-block-info-tx-hardfork.md) - [Transform Frames to a Batch](./frames-to-batch.md) - [Transform a Batch to Frames](./batch-to-frames.md) diff --git a/book/src/examples/new-l1-block-info-tx-hardfork.md b/book/src/examples/new-l1-block-info-tx-hardfork.md new file mode 100644 index 00000000..a16ad3e4 --- /dev/null +++ b/book/src/examples/new-l1-block-info-tx-hardfork.md @@ -0,0 +1,113 @@ +# Create a L1BlockInfoTx Variant for a new Hardfork + +This example walks through creating a variant of the [`L1BlockInfoTx`][info-tx] +for a new Hardfork. + +> [!NOTE] +> +> This example is very verbose. +> To grok required changes, view [this PR diff][pr-diff] +> which introduces Isthmus hardfork changes to the `L1BlockInfoTx` with a new variant. + + +## Required Genesis Updates + +The first updates that need to be made are to [`op-alloy-genesis`][genesis] +types, namely the [`RollupConfig`][rc] and [`HardForkConfiguration`][hfc]. + +First, add a timestamp field to the [`RollupConfig`][rc]. Let's use the +hardfork name "Glacier" as an example. + +```rust +pub struct RollupConfig { + ... + /// `glacier_time` sets the activation time for the Glacier network upgrade. + /// Active if `glacier_time` != None && L2 block timestamp >= Some(glacier_time), inactive + /// otherwise. + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + pub glacier_time: Option, + ... +} +``` + +Add an accessor on the [`RollupConfig`][rc] to provide a way of checking whether the +"Glacier" hardfork is active for a given timestamp. Also update the prior hardfork +accessor to call this method (let's use "Isthmus" as the prior hardfork). + +```rust + /// Returns true if Isthmus is active at the given timestamp. + pub fn is_isthmus_active(&self, timestamp: u64) -> bool { + self.isthmus_time.map_or(false, |t| timestamp >= t) || self.is_glacier_active(timestamp) + } + + /// Returns true if Glacier is active at the given timestamp. + pub fn is_glacier_active(&self, timestamp: u64) -> bool { + self.glacier_time.map_or(false, |t| timestamp >= t) + } +``` + +Lastly, add the "Glacier" timestamp to the [`HardForkConfiguration`][hfc]. + +```rust +pub struct HardForkConfiguration { + ... + /// Glacier hardfork activation time + pub glacier_time: Option, +} +``` + + +## Protocol Changes + +Introduce a new `glacier.rs` module containing a `L1BlockInfoGlacier` type +in [`op_alloy_genesis::info` module][info-mod]. + +This should include a few methods used in the `L1BlockInfoTx` later. + +```rust + pub fn encode_calldata(&self) -> Bytes { ... } + + pub fn decode_calldata(r: &[u8]) -> Result { ... } +``` + +Use other hardfork variants like the [`L1BlockInfoEcotone`][ecotone] +for reference. + +Next, add the new "Glacier" variant to the [`L1BlockInfoTx`][info-tx]. + +```rust +pub enum L1BlockInfoTx { + ... + Glacier(L1BlockInfoGlacier) +} +``` + +Update [`L1BlockInfoTx::try_new`][try-new] to construct the `L1BlockInfoGlacier` +if the hardfork is active using the `RollupConfig::is_glacier_active`. + +Also, be sure to update [`L1BlockInfoTx::decode_calldata`][decode-calldata] +with the new variant decoding, as well as other [`L1BlockInfoTx`][info-tx] +methods. + +Once some tests are added surrounding the decoding and encoding of the new +`L1BlockInfoGlacier` variant, all required changes are complete! + +Now, [this example PR diff][pr-diff] introducing the Isthmus changes should +make sense, since it effectively implements the above changes for the Isthmus +hardfork (replacing "Glacier" with "Isthmus"). Notice, Isthmus introduces +some new "operator fee" fields as part of it's `L1BlockInfoIsthmus` type. +Some new error variants to the [`BlockInfoError`][bie] are needed as well. + + + + +[bie]: https://docs.rs/op-alloy-protocol/latest/op_alloy_protocol/enum.BlockInfoError.html +[pr-diff]: https://github.com/alloy-rs/op-alloy/pull/130/files +[decode-calldata]: https://docs.rs/op-alloy-protocol/latest/op_alloy_protocol/enum.L1BlockInfoTx.html#method.decode_calldata +[try-new]: https://docs.rs/op-alloy-protocol/latest/op_alloy_protocol/enum.L1BlockInfoTx.html#method.try_new +[ecotone]: https://github.com/alloy-rs/op-alloy/blob/main/crates/protocol/src/info/ecotone.rs +[info-mod]: https://github.com/alloy-rs/op-alloy/blob/main/crates/protocol/src/info/mod.rs +[genesis]: https://docs.rs/op-alloy-genesis/latest/op_alloy_genesis/index.html +[rc]: https://docs.rs/op-alloy-genesis/latest/op_alloy_genesis/struct.RollupConfig.html +[hfc]: https://docs.rs/op-alloy-genesis/latest/op_alloy_genesis/struct.HardForkConfiguration.html +[info-tx]: https://docs.rs/op-alloy-protocol/latest/op_alloy_protocol/enum.L1BlockInfoTx.html