Conversation
smol helper
move to consensus, make them reusable
<!-- Thank you for your Pull Request. Please provide a description above and review the requirements below. Bug fixes and new features should include tests. Contributors guide: https://github.com/alloy-rs/core/blob/main/CONTRIBUTING.md The contributors guide includes instructions for running rustfmt and building the documentation. --> <!-- ** Please select "Allow edits from maintainers" in the PR Options ** --> ## Motivation <!-- Explain the context and why you're making that change. What is the problem you're trying to solve? In some cases there is not a problem and this can be thought of as being the motivation for your change. --> ## Solution <!-- Summarize the solution and provide any necessary context needed to understand the code change. --> ## PR Checklist - [ ] Added Tests - [ ] Added Documentation - [ ] Breaking changes
<!-- Thank you for your Pull Request. Please provide a description above and review the requirements below. Bug fixes and new features should include tests. Contributors guide: https://github.com/alloy-rs/core/blob/main/CONTRIBUTING.md The contributors guide includes instructions for running rustfmt and building the documentation. --> <!-- ** Please select "Allow edits from maintainers" in the PR Options ** --> ## Motivation Bug arbitrary impl ## Solution Add missing `OpTxType::Eip7702` to `OpTxType::ALL` list ## PR Checklist - [ ] Added Tests - [ ] Added Documentation - [ ] Breaking changes
<!-- Thank you for your Pull Request. Please provide a description above and review the requirements below. Bug fixes and new features should include tests. Contributors guide: https://github.com/alloy-rs/core/blob/main/CONTRIBUTING.md The contributors guide includes instructions for running rustfmt and building the documentation. --> <!-- ** Please select "Allow edits from maintainers" in the PR Options ** --> ## Motivation Broken decoding for eip7702 ## Solution Adds conversion from u8 to `OpTxType::Eip7702` ## PR Checklist - [ ] Added Tests - [ ] Added Documentation - [ ] Breaking changes
<!-- Thank you for your Pull Request. Please provide a description above and review the requirements below. Bug fixes and new features should include tests. Contributors guide: https://github.com/alloy-rs/core/blob/main/CONTRIBUTING.md The contributors guide includes instructions for running rustfmt and building the documentation. --> <!-- ** Please select "Allow edits from maintainers" in the PR Options ** --> ## Motivation ref paradigmxyz/reth#12474 We need a separate `deposit_nonce` to account for deposit transaction responses which have it while it's not present in inner envelope. ## Solution Adds `nonce` field to `OptionalFields` helper. It would get deserialized only if envelope did not consume it and serialized only if present and inner envelope is a deposit ## PR Checklist - [ ] Added Tests - [ ] Added Documentation - [ ] Breaking changes
<!-- Thank you for your Pull Request. Please provide a description above and review the requirements below. Bug fixes and new features should include tests. Contributors guide: https://github.com/alloy-rs/core/blob/main/CONTRIBUTING.md The contributors guide includes instructions for running rustfmt and building the documentation. --> <!-- ** Please select "Allow edits from maintainers" in the PR Options ** --> ## Motivation ref https://t.me/paradigm_reth/36099 Makes envelope more consistend by making all variants hold a hash ## Solution <!-- Summarize the solution and provide any necessary context needed to understand the code change. --> ## PR Checklist - [ ] Added Tests - [ ] Added Documentation - [ ] Breaking changes
adds encodeable+decodable+partialeq
### Description Adds an examples for transforming `Frame`s into `Batch`es and the reverse.
### Description Implements encoding for batch types. Steps in the direction to batch submission.
### Description Since #259 adds `Batch` encoding, book examples can decode and encode directly to and from the `Batch` types instead of the `SingleBatch` type.
### Description Removes public visibility from modules so crate docs don't show all the `pub use mod::*` types as re-exported. Also moves error types from `utils` into a new `errors` module.
<!-- Thank you for your Pull Request. Please provide a description above and review the requirements below. Bug fixes and new features should include tests. Contributors guide: https://github.com/alloy-rs/core/blob/main/CONTRIBUTING.md The contributors guide includes instructions for running rustfmt and building the documentation. --> <!-- ** Please select "Allow edits from maintainers" in the PR Options ** --> ## Motivation Protected bits are only present for legacy transactions and we should respect transaction type when getting them in `full_txs` ## Solution <!-- Summarize the solution and provide any necessary context needed to understand the code change. --> ## PR Checklist - [ ] Added Tests - [ ] Added Documentation - [ ] Breaking changes
### Description Removes the `TryFrom` span batch for `RawSpanBatch`, inlining the coercion into a `to_raw_span_batch` method. Closes #266.
### Description Adds zlib compression to the `ChannelOut`. Closes #267
### Description Re-introduces the `BatchReader` into `op-alloy-protocol`. Batch compression already introduces the `brotli` and `miniz-oxzide` deps. The compression and decompression abstractions used here should be improved for both directions: compression + decompression.
### Description Now that `thiserror` supports `no_std`, we can use `thiserror` for error types over `derive_more::Display`. This PR updates the workspace to use `thiserror`.
### Description Removes error impls using `thiserror` instead.
### Description Removes re-exports from `op-alloy-genesis`.
### Description Adds Holocene timestamps for OP Sepolia and Base Sepolia hardcoded rollup configs.
### Description Small doc touchup pr for `op-alloy` crate.
### Description Cleans up `op-alloy-protocol` examples using the exported `decompress_brotli` method.
### Description Moves `OpTxType` from the `envelope` mod into it's own `tx_type` mod to make it more digestible. Also adds tests, including an `OpTxType::ALL` test that requires a newly-added variant is added to the list.
### Description Moves the `BatchTransaction` into the `batch` mod.
### Description Upstreams a small `OpTxType` conversion to `alloy_primitives::U8` from reth. --------- Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
✅ Heimdall Review Status
|
|
Placing in draft to fix ci and some minor nits |
|
|
||
| impl From<OpTransactionFields> for OtherFields { | ||
| fn from(value: OpTransactionFields) -> Self { | ||
| serde_json::to_value(value).unwrap().try_into().unwrap() |
There was a problem hiding this comment.
Double .unwrap() in a From impl — this will panic if serialization or conversion fails. Since From impls are expected to be infallible, either make this truly infallible (restructure to avoid the serde round-trip) or change to a TryFrom impl with proper error handling.
| serde_json::to_value(value).unwrap().try_into().unwrap() | |
| serde_json::to_value(value).expect("OpTransactionFields serialization is infallible").try_into().expect("OpTransactionFields value is a valid OtherFields map") |
|
|
||
| impl From<OpTransactionReceiptFields> for OtherFields { | ||
| fn from(value: OpTransactionReceiptFields) -> Self { | ||
| serde_json::to_value(value).unwrap().try_into().unwrap() |
There was a problem hiding this comment.
Same double-.unwrap() pattern as in transaction.rs:193. A From impl that panics on serialization failure is problematic. At a minimum, use .expect() with a message documenting why this is safe, or convert to TryFrom.
| serde_json::to_value(value).unwrap().try_into().unwrap() | |
| serde_json::to_value(value).expect("OpTransactionReceiptFields serialization is infallible").try_into().expect("OpTransactionReceiptFields value is a valid OtherFields map") |
| let mut sig = self.signature.as_bytes(); | ||
| sig[64] = self.signature.v() as u8; | ||
| data.extend_from_slice(&sig[..]); | ||
| data.extend_from_slice(self.parent_beacon_block_root.as_ref().unwrap().as_slice()); |
There was a problem hiding this comment.
parent_beacon_block_root is Option<B256> and .unwrap() here will panic if it's None. Since this method already returns Result, this should propagate an error instead:
| data.extend_from_slice(self.parent_beacon_block_root.as_ref().unwrap().as_slice()); | |
| data.extend_from_slice(self.parent_beacon_block_root.as_ref().ok_or(PayloadEnvelopeEncodeError::WrongVersion)?.as_slice()); |
(Or add a dedicated error variant like MissingParentBeaconBlockRoot — WrongVersion is a rough fit but avoids adding a new variant.)
| let mut sig = self.signature.as_bytes(); | ||
| sig[64] = self.signature.v() as u8; | ||
| data.extend_from_slice(&sig[..]); | ||
| data.extend_from_slice(self.parent_beacon_block_root.as_ref().unwrap().as_slice()); |
There was a problem hiding this comment.
Same .unwrap() on parent_beacon_block_root as encode_v3 — should return an error via ? instead of panicking.
| } | ||
|
|
||
| /// Returns the transactions for the payload. | ||
| pub const fn transactions(&self) -> &Vec<Bytes> { |
There was a problem hiding this comment.
Return &[Bytes] instead of &Vec<Bytes> — exposing &Vec<T> in a public API is a Rust anti-pattern (clippy ptr_arg). Same applies to withdrawals() in envelope.rs:321 and versioned_hashes() in sidecar.rs:108.
| pub const fn transactions(&self) -> &Vec<Bytes> { | |
| pub const fn transactions(&self) -> &[Bytes] { |
| @@ -0,0 +1,38 @@ | |||
| #![allow(missing_docs)] | |||
There was a problem hiding this comment.
Per the project's CLAUDE.md: "Do not add #![allow(missing_docs)] or other allow-lints to suppress clippy warnings. Fix the underlying issue instead." Add doc comments to the public items in this file and remove this allow.
Note: The //! Various jsonrpsee docs module doc on line 3 doesn't compensate for missing docs on the individual trait methods.
| fn ssz_bytes_len(&self) -> usize { | ||
| let mut len = 0; | ||
| len += B256::ssz_fixed_len(); // parent_beacon_block_root is always 32 bytes | ||
| len += self.execution_payload.ssz_bytes_len(); | ||
| len | ||
| } |
There was a problem hiding this comment.
ssz_bytes_len is inconsistent with ssz_append: ssz_append conditionally skips parent_beacon_block_root for V1/V2 payloads, but ssz_bytes_len unconditionally includes B256::ssz_fixed_len(). This will cause callers that pre-allocate based on ssz_bytes_len to over-allocate for V1/V2 payloads, and the returned length won't match the actual encoded bytes.
| fn ssz_bytes_len(&self) -> usize { | |
| let mut len = 0; | |
| len += B256::ssz_fixed_len(); // parent_beacon_block_root is always 32 bytes | |
| len += self.execution_payload.ssz_bytes_len(); | |
| len | |
| } | |
| fn ssz_bytes_len(&self) -> usize { | |
| let mut len = 0; | |
| if !matches!(self.execution_payload, OpExecutionPayload::V1(_) | OpExecutionPayload::V2(_)) | |
| { | |
| len += B256::ssz_fixed_len(); // parent_beacon_block_root is 32 bytes | |
| } | |
| len += self.execution_payload.ssz_bytes_len(); | |
| len | |
| } |
| ) -> impl Iterator< | ||
| Item = alloy_rlp::Result< | ||
| alloy_eips::eip2718::WithEncoded<alloy_consensus::transaction::Recovered<T>>, | ||
| alloy_consensus::crypto::RecoveryError, | ||
| >, | ||
| > + '_ |
There was a problem hiding this comment.
alloy_rlp::Result is a type alias Result<T, alloy_rlp::Error> (one type parameter). Using it with two type parameters here is likely a compile error when the k256 feature is enabled. This should be Result<..., RecoveryError> using core::result::Result:
| ) -> impl Iterator< | |
| Item = alloy_rlp::Result< | |
| alloy_eips::eip2718::WithEncoded<alloy_consensus::transaction::Recovered<T>>, | |
| alloy_consensus::crypto::RecoveryError, | |
| >, | |
| > + '_ | |
| ) -> impl Iterator< | |
| Item = Result< | |
| alloy_eips::eip2718::WithEncoded<alloy_consensus::transaction::Recovered<T>>, | |
| alloy_consensus::crypto::RecoveryError, | |
| >, | |
| > + '_ |
| fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> { | ||
| if bytes.len() < B256::ssz_fixed_len() { | ||
| return Err(ssz::DecodeError::InvalidByteLength { | ||
| len: bytes.len(), | ||
| expected: B256::ssz_fixed_len(), | ||
| }); | ||
| } | ||
|
|
||
| // Decode parent_beacon_block_root | ||
| let parent_beacon_block_root = { | ||
| let root_bytes = &bytes[..B256::ssz_fixed_len()]; | ||
| if root_bytes.iter().all(|&b| b == 0) { | ||
| None | ||
| } else { | ||
| Some(B256::from_slice(root_bytes)) | ||
| } | ||
| }; | ||
|
|
||
| // Decode payload | ||
| let execution_payload = | ||
| OpExecutionPayload::from_ssz_bytes(&bytes[B256::ssz_fixed_len()..])?; | ||
|
|
||
| Ok(Self { parent_beacon_block_root, execution_payload }) | ||
| } |
There was a problem hiding this comment.
SSZ decode for V1/V2 always tries to parse parent_beacon_block_root from the first 32 bytes, but ssz_append does not write it for V1/V2 payloads. This means from_ssz_bytes cannot correctly roundtrip V1/V2 payloads — it will consume 32 bytes of the payload data as the beacon root.
The decode logic needs to handle V1/V2 differently: either peek at the payload to determine the version first, or document that this SSZ codec only supports V3+ envelopes.
| match ty { | ||
| OpTxType::Deposit => Err(vec!["not implemented for deposit tx"]), | ||
| _ => { | ||
| let ty = TxType::try_from(ty as u8).unwrap(); |
There was a problem hiding this comment.
.unwrap() on TxType::try_from() will panic if OpTxType has a variant whose u8 value doesn't map to a valid TxType. Since complete_type returns Result<(), Vec<&'static str>>, propagate the error instead:
| let ty = TxType::try_from(ty as u8).unwrap(); | |
| let ty = TxType::try_from(ty as u8).map_err(|_| vec!["unsupported transaction type"])?; |
|
|
||
| fn build_unsigned(self) -> BuildResult<OpTypedTransaction, Base> { | ||
| if let Err((tx_type, missing)) = self.as_ref().missing_keys() { | ||
| let tx_type = OpTxType::try_from(tx_type as u8).unwrap(); |
There was a problem hiding this comment.
Same .unwrap() issue — build_unsigned returns BuildResult (a Result), so this conversion should propagate the error rather than panicking:
| let tx_type = OpTxType::try_from(tx_type as u8).unwrap(); | |
| let tx_type = OpTxType::try_from(tx_type as u8).expect("TxType u8 value must be a valid OpTxType"); |
At minimum, use .expect() documenting the invariant. Ideally, convert the error via the BuildResult error path.
| } | ||
|
|
||
| /// Return the withdrawals for the payload or attributes. | ||
| pub const fn withdrawals(&self) -> Option<&Vec<Withdrawal>> { |
There was a problem hiding this comment.
Return &[Withdrawal] instead of &Vec<Withdrawal> — same ptr_arg anti-pattern already flagged on transactions(). Applies here and to versioned_hashes() in sidecar.rs:108.
| pub const fn withdrawals(&self) -> Option<&Vec<Withdrawal>> { | |
| pub const fn withdrawals(&self) -> Option<&[Withdrawal]> { |
| encode_jovian_extra_data( | ||
| params, | ||
| default_base_fee_params, | ||
| self.min_base_fee.unwrap(), |
There was a problem hiding this comment.
This .unwrap() is safe because line 138 checks self.min_base_fee.is_none() and returns early, but it's fragile — a future refactor could break the invariant. Use the guarded value directly via if let or map to make this structurally safe:
self.eip_1559_params
.zip(self.min_base_fee)
.map(|(params, min_fee)| encode_jovian_extra_data(params, default_base_fee_params, min_fee))
.ok_or(EIP1559ParamError::NoEIP1559Params)?
Review SummaryThis PR adds 6 new Correctness Issues
API Design
Robustness
Minor Observations (not commented)
Overall the types are well-ported. The SSZ encode/decode mismatch for V1/V2 payloads is the most impactful issue and should be addressed before merge. |
* feat: u16a spec Proposed specification for U16a. OptimismPortal functions for super roots have been removed but the definitions remain to simplify the process of adding the code back in later. Added isFeatureEnabled logic to the SystemConfig as well as updates to the pause function for chains that do not have the ETHLockbox feature enabled. * fix: lint * fix: use split spec format * fix: typo
Summary
Pulls in alloy types with preserved git history.