diff --git a/Cargo.lock b/Cargo.lock index f8b61f9..f858b68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4293,6 +4293,14 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p2p" +version = "0.0.0" +dependencies = [ + "alloy", + "kona-primitives", +] + [[package]] name = "page_size" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index 90c9c14..bee5586 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ categories = ["cryptography", "cryptography::cryptocurrencies"] [workspace] members = [ "bin/hera", + "crates/p2p", "crates/kona-providers", "crates/ser", ] diff --git a/crates/p2p/Cargo.toml b/crates/p2p/Cargo.toml new file mode 100644 index 0000000..72c1a07 --- /dev/null +++ b/crates/p2p/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "p2p" +description = "Consensus P2P Stack for L2" +version = "0.0.0" +edition.workspace = true +authors.workspace = true +license.workspace = true +keywords.workspace = true +repository.workspace = true +categories.workspace = true +rust-version.workspace = true + +[dependencies] +alloy.workspace = true + +kona-primitives = { git = "https://github.com/ethereum-optimism/kona", default-features = true } diff --git a/crates/p2p/src/lib.rs b/crates/p2p/src/lib.rs new file mode 100644 index 0000000..93d7aa6 --- /dev/null +++ b/crates/p2p/src/lib.rs @@ -0,0 +1,10 @@ +//! Consensus P2P Stack + +#![doc(issue_tracker_base_url = "https://github.com/paradigmxyz/op-rs/issues/")] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(not(test), no_std)] + +extern crate alloc; + +pub mod types; diff --git a/crates/p2p/src/types.rs b/crates/p2p/src/types.rs new file mode 100644 index 0000000..e7f939a --- /dev/null +++ b/crates/p2p/src/types.rs @@ -0,0 +1,58 @@ +//! Types for the P2P network. + +use alloc::vec::Vec; +use alloy::primitives::{keccak256, Signature, B256}; +use kona_primitives::L2ExecutionPayload; + +/// An envelope around the execution payload for L2. +#[derive(Debug)] +pub struct ExecutionPayloadEnvelope { + /// The execution payload. + pub payload: L2ExecutionPayload, + /// A signature for the payload. + pub signature: Signature, + /// The hash of the payload. + pub hash: PayloadHash, + /// The parent beacon block root. + pub parent_beacon_block_root: Option, +} + +/// Represents the Keccak256 hash of the block +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct PayloadHash(B256); + +impl From<&[u8]> for PayloadHash { + /// Returns the Keccak256 hash of a sequence of bytes + fn from(value: &[u8]) -> Self { + Self(keccak256(value)) + } +} + +impl PayloadHash { + /// The expected message that should be signed by the unsafe block signer. + pub fn signature_message(&self, chain_id: u64) -> B256 { + let domain = B256::ZERO; + let chain_id = B256::left_padding_from(&chain_id.to_be_bytes()[..]); + let payload_hash = self.0; + + let data: Vec = + [domain.as_slice(), chain_id.as_slice(), payload_hash.as_slice()].concat(); + + keccak256(data) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy::primitives::b256; + + #[test] + fn test_signature_message() { + let inner = b256!("9999999999999999999999999999999999999999999999999999999999999999"); + let hash = PayloadHash::from(inner.as_slice()); + let chain_id = 10; + let expected = b256!("44a0e2b1aba1aae1771eddae1dcd2ad18a8cdac8891517153f03253e49d3f206"); + assert_eq!(hash.signature_message(chain_id), expected); + } +}