Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions crates/genesis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ Genesis configuration and utilities for the Signet Node.

This library contains the following:

- `GenesisSpec` - An enum representing different genesis specifications, either
Pecorino, Test, or a custom genesis file path, which can be used to load
genesis data.
- `PECORINO_GENESIS` - The Pecorino genesis data.
- `TEST_GENESIS` - A local test genesis for testing purposes.
- `GenesisSpec` - An enum representing different genesis specifications (Mainnet,
Pecorino, Test, or custom file paths), which can be used to load genesis data.
- `NetworkGenesis` - A struct containing both rollup and host genesis configurations.
- `PECORINO_GENESIS` / `PECORINO_HOST_GENESIS` - The Pecorino genesis data.
- `TEST_GENESIS` / `TEST_HOST_GENESIS` - Local test genesis for testing purposes.
- `GenesisError` - Errors that can occur when loading or parsing genesis data.

## Example
Expand All @@ -17,6 +17,10 @@ This library contains the following:
# use signet_genesis::GenesisSpec;
# fn _main() -> Result<(), Box<dyn std::error::Error>> {
let genesis = GenesisSpec::Pecorino.load_genesis()?;
// Access rollup (L2/Signet) genesis
let rollup = &genesis.rollup;
// Access host (L1/Ethereum) genesis
let host = &genesis.host;
# Ok(())
# }
```
154 changes: 119 additions & 35 deletions crates/genesis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,29 +21,56 @@ use std::{borrow::Cow, path::PathBuf, str::FromStr, sync::LazyLock};
/// Signet mainnet genesis file.
pub const MAINNET_GENESIS_JSON: &str = include_str!("./mainnet.genesis.json");

/// Signet mainnet host genesis file.
pub const MAINNET_HOST_GENESIS_JSON: &str = include_str!("./mainnet.host.genesis.json");

/// Pecorino genesis file.
pub const PECORINO_GENESIS_JSON: &str = include_str!("./pecorino.genesis.json");

/// Pecorino host genesis file.
pub const PECORINO_HOST_GENESIS_JSON: &str = include_str!("./pecorino.host.genesis.json");

/// Local genesis file for testing purposes.
pub const TEST_GENESIS_JSON: &str = include_str!("./local.genesis.json");

/// Local host genesis file for testing purposes.
pub const TEST_HOST_GENESIS_JSON: &str = include_str!("./local.host.genesis.json");

/// Mainnet genesis for the Signet mainnet.
pub static MAINNET_GENESIS: LazyLock<Genesis> = LazyLock::new(|| {
serde_json::from_str(MAINNET_GENESIS_JSON).expect("Failed to parse mainnet genesis")
});

/// Signet mainnet host genesis for the Signet mainnet.
pub static MAINNET_HOST_GENESIS: LazyLock<Genesis> = LazyLock::new(|| {
serde_json::from_str(MAINNET_HOST_GENESIS_JSON).expect("Failed to parse mainnet host genesis")
});

/// Genesis for the Pecorino testnet.
pub static PECORINO_GENESIS: LazyLock<Genesis> = LazyLock::new(|| {
serde_json::from_str(PECORINO_GENESIS_JSON).expect("Failed to parse pecorino genesis")
});

/// Genesis for the Pecorino host testnet.
pub static PECORINO_HOST_GENESIS: LazyLock<Genesis> = LazyLock::new(|| {
serde_json::from_str(PECORINO_HOST_GENESIS_JSON).expect("Failed to parse pecorino host genesis")
});

/// Test genesis for local testing.
pub static TEST_GENESIS: LazyLock<Genesis> = LazyLock::new(|| {
serde_json::from_str(TEST_GENESIS_JSON).expect("Failed to parse test genesis")
});

/// Environment variable for specifying the genesis JSON file path.
const GENESIS_JSON_PATH: &str = "GENESIS_JSON_PATH";
/// Test host genesis for local testing.
pub static TEST_HOST_GENESIS: LazyLock<Genesis> = LazyLock::new(|| {
serde_json::from_str(TEST_HOST_GENESIS_JSON).expect("Failed to parse test host genesis")
});

/// Environment variable for specifying the rollup genesis JSON file path.
const ROLLUP_GENESIS_JSON_PATH: &str = "ROLLUP_GENESIS_JSON_PATH";

/// Environment variable for specifying the host genesis JSON file path.
const HOST_GENESIS_JSON_PATH: &str = "HOST_GENESIS_JSON_PATH";

/// Result type for genesis operations.
pub type Result<T, E = GenesisError> = std::result::Result<T, E>;
Expand All @@ -59,6 +86,24 @@ pub enum GenesisError {
Json(#[from] serde_json::Error),
}

/// Genesis configurations for a network, containing both rollup and host chain genesis.
#[derive(Debug, Clone)]
pub struct NetworkGenesis {
/// The rollup genesis configuration.
pub rollup: Genesis,
/// The host genesis configuration.
pub host: Genesis,
}

/// Raw genesis JSON strings for a network.
#[derive(Debug, Clone)]
pub struct RawNetworkGenesis {
/// The rollup genesis JSON.
pub rollup: Cow<'static, str>,
/// The host genesis JSON.
pub host: Cow<'static, str>,
}

/// Different genesis configurations available.
#[derive(Debug, Clone, serde::Deserialize)]
#[serde(untagged)]
Expand All @@ -69,49 +114,80 @@ pub enum GenesisSpec {
Pecorino,
/// Local testnet.
Test,
/// Custom path to a genesis file.
Path(PathBuf),
/// Custom paths to genesis files.
Custom {
/// Path to the rollup genesis file.
rollup: PathBuf,
/// Path to the host genesis file.
host: PathBuf,
},
}

impl GenesisSpec {
/// Load the genesis JSON from the specified source.
/// Load the raw genesis JSON strings from the specified source.
///
/// This will alwys return a valid string for [`KnownChains`].
pub fn load_raw_genesis(&self) -> Result<Cow<'static, str>> {
/// Returns both rollup and host genesis JSON strings.
pub fn load_raw_genesis(&self) -> Result<RawNetworkGenesis> {
match self {
GenesisSpec::Mainnet => Ok(Cow::Borrowed(MAINNET_GENESIS_JSON)),
GenesisSpec::Pecorino => Ok(Cow::Borrowed(PECORINO_GENESIS_JSON)),
GenesisSpec::Test => Ok(Cow::Borrowed(TEST_GENESIS_JSON)),
GenesisSpec::Path(path) => {
std::fs::read_to_string(path).map(Cow::Owned).map_err(Into::into)
}
GenesisSpec::Mainnet => Ok(RawNetworkGenesis {
rollup: Cow::Borrowed(MAINNET_GENESIS_JSON),
host: Cow::Borrowed(MAINNET_HOST_GENESIS_JSON),
}),
GenesisSpec::Pecorino => Ok(RawNetworkGenesis {
rollup: Cow::Borrowed(PECORINO_GENESIS_JSON),
host: Cow::Borrowed(PECORINO_HOST_GENESIS_JSON),
}),
GenesisSpec::Test => Ok(RawNetworkGenesis {
rollup: Cow::Borrowed(TEST_GENESIS_JSON),
host: Cow::Borrowed(TEST_HOST_GENESIS_JSON),
}),
GenesisSpec::Custom { rollup, host } => Ok(RawNetworkGenesis {
rollup: Cow::Owned(std::fs::read_to_string(rollup)?),
host: Cow::Owned(std::fs::read_to_string(host)?),
}),
}
}

/// Load the genesis from the specified source.
/// Load the genesis configurations from the specified source.
///
/// This will always return a valid genesis for [`KnownChains`].
pub fn load_genesis(&self) -> Result<alloy::genesis::Genesis> {
/// Returns both rollup and host genesis configurations.
pub fn load_genesis(&self) -> Result<NetworkGenesis> {
match self {
GenesisSpec::Mainnet => Ok(MAINNET_GENESIS.clone()),
GenesisSpec::Pecorino => Ok(PECORINO_GENESIS.clone()),
GenesisSpec::Test => Ok(TEST_GENESIS.clone()),
GenesisSpec::Path(_) => self
.load_raw_genesis()
.and_then(|raw| serde_json::from_str(&raw).map_err(Into::into)),
GenesisSpec::Mainnet => Ok(NetworkGenesis {
rollup: MAINNET_GENESIS.clone(),
host: MAINNET_HOST_GENESIS.clone(),
}),
GenesisSpec::Pecorino => Ok(NetworkGenesis {
rollup: PECORINO_GENESIS.clone(),
host: PECORINO_HOST_GENESIS.clone(),
}),
GenesisSpec::Test => {
Ok(NetworkGenesis { rollup: TEST_GENESIS.clone(), host: TEST_HOST_GENESIS.clone() })
}
GenesisSpec::Custom { .. } => self.load_raw_genesis().and_then(|genesis| {
Ok(NetworkGenesis {
rollup: serde_json::from_str(&genesis.rollup)?,
host: serde_json::from_str(&genesis.host)?,
})
}),
}
}
}

/// Error returned when parsing an unknown chain name.
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
#[error("unknown chain name: {0}")]
pub struct UnknownChainError(String);

impl FromStr for GenesisSpec {
type Err = <PathBuf as FromStr>::Err;
type Err = UnknownChainError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(known) = KnownChains::from_str(s) {
return Ok(known.into());
}

Ok(GenesisSpec::Path(s.parse()?))
Err(UnknownChainError(s.to_string()))
}
}

Expand All @@ -134,17 +210,31 @@ impl FromEnv for GenesisSpec {
optional: true,
},
&EnvItemInfo {
var: GENESIS_JSON_PATH,
description: "A filepath to the genesis JSON file. Required if CHAIN_NAME is not set.",
var: ROLLUP_GENESIS_JSON_PATH,
description: "A filepath to the rollup genesis JSON file. Required if CHAIN_NAME is not set.",
optional: true,
},
&EnvItemInfo {
var: HOST_GENESIS_JSON_PATH,
description: "A filepath to the host genesis JSON file. Required if CHAIN_NAME is not set.",
optional: true,
},
]
}

fn from_env() -> Result<Self, FromEnvErr<Self::Error>> {
parse_env_if_present::<KnownChains>("CHAIN_NAME")
.map(Into::into)
.or_else(|_| parse_env_if_present::<PathBuf>(GENESIS_JSON_PATH).map(Into::into))
// First try to parse from CHAIN_NAME
if let Ok(spec) = parse_env_if_present::<KnownChains>("CHAIN_NAME").map(Into::into) {
return Ok(spec);
}

// Otherwise, try to load from custom paths
let rollup = parse_env_if_present::<PathBuf>(ROLLUP_GENESIS_JSON_PATH)
.map_err(|_| FromEnvErr::empty(ROLLUP_GENESIS_JSON_PATH))?;
let host = parse_env_if_present::<PathBuf>(HOST_GENESIS_JSON_PATH)
.map_err(|_| FromEnvErr::empty(HOST_GENESIS_JSON_PATH))?;

Ok(GenesisSpec::Custom { rollup, host })
}
}

Expand All @@ -156,9 +246,3 @@ impl From<KnownChains> for GenesisSpec {
}
}
}

impl From<PathBuf> for GenesisSpec {
fn from(path: PathBuf) -> Self {
GenesisSpec::Path(path)
}
}
55 changes: 55 additions & 0 deletions crates/genesis/src/local.host.genesis.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"chainId": 1,
"homesteadBlock": 1150000,
"daoForkBlock": 1920000,
"daoForkSupport": true,
"eip150Block": 2463000,
"eip155Block": 2675000,
"eip158Block": 2675000,
"byzantiumBlock": 4370000,
"constantinopleBlock": 7280000,
"petersburgBlock": 7280000,
"istanbulBlock": 9069000,
"muirGlacierBlock": 9200000,
"berlinBlock": 12244000,
"londonBlock": 12965000,
"arrowGlacierBlock": 13773000,
"grayGlacierBlock": 15050000,
"shanghaiTime": 1681338455,
"cancunTime": 1710338135,
"pragueTime": 1746612311,
"osakaTime": 1764798551,
"bpo1Time": 1765290071,
"bpo2Time": 1767747671,
"terminalTotalDifficulty": 58750000000000000000000,
"terminalTotalDifficultyPassed": true,
"depositContractAddress": "0x00000000219ab540356cbb839cbe05303d7705fa",
"ethash": {},
"blobSchedule": {
"cancun": {
"target": 3,
"max": 6,
"baseFeeUpdateFraction": 3338477
},
"prague": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
},
"osaka": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
},
"bpo1": {
"target": 10,
"max": 15,
"baseFeeUpdateFraction": 8346193
},
"bpo2": {
"target": 14,
"max": 21,
"baseFeeUpdateFraction": 11684671
}
}
}
Loading