Skip to content

Commit

Permalink
Define a genesis config file (#1443)
Browse files Browse the repository at this point in the history
This aims to separate onchain data, which must be the same for all nodes
(chain ID, base fee, etc) from node-specific configuration. Node
configuration continues to be done via environment variables, whereas
onchain data is defined in a configuration file which we can distribute
to all node operators when launching a network. This should greatly
simplify coordination and reduce the frequency of errors due to
misconfigured nodes.

For officially supported networks (demo, staging, testnet, and
eventually mainnet) the genesis file is distributed via the sequencer
docker image itself, which makes the deployment process far less error
prone -- the only thing we need to get right is to ensure all node
operators are using the same Docker tag. It is also a bit easier to
toggle between networks now, as you can switch over all the onchain data
just by changing `ESPRESSO_SEQUENCER_GENESIS_FILE` to a different
bundled genesis file. You still have to change the other env vars to
connect to the right orchestrator, CDN, etc though.

# Key places to review

* Changes in `genesis.rs` and `options.rs` are the meat of the change
* Serialization changes (to allow flexible deserialization from string
or integer) in `utils/src/ser.rs`, `sequencer/src/state.rs`, and
`sequencer/src/chain_config.rs`. In particular check the new tests, that
are intended to prove this is backwards compatible with Cappuccino
serialization
* Changes to `docker-compose.yaml` and `process-compose.yaml`
  • Loading branch information
jbearer authored May 28, 2024
2 parents daf5023 + 9c51afa commit 8182221
Show file tree
Hide file tree
Showing 32 changed files with 816 additions and 222 deletions.
5 changes: 2 additions & 3 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@ ESPRESSO_SEQUENCER1_API_PORT=24001
ESPRESSO_SEQUENCER2_API_PORT=24002
ESPRESSO_SEQUENCER3_API_PORT=24003
ESPRESSO_SEQUENCER4_API_PORT=24004
ESPRESSO_SEQUENCER_MAX_BLOCK_SIZE=1mb
ESPRESSO_SEQUENCER_BASE_FEE=1
ESPRESSO_SEQUENCER_URL=http://sequencer0:${ESPRESSO_SEQUENCER_API_PORT}
ESPRESSO_SEQUENCER_STORAGE_PATH=/store/sequencer
ESPRESSO_SEQUENCER_GENESIS_FILE=/genesis/demo.toml
ESPRESSO_SEQUENCER_L1_PORT=8545
ESPRESSO_SEQUENCER_L1_WS_PORT=8546
ESPRESSO_SEQUENCER_L1_PROVIDER=http://demo-l1-network:${ESPRESSO_SEQUENCER_L1_PORT}
Expand All @@ -55,7 +54,6 @@ ESPRESSO_DEPLOYER_ACCOUNT_INDEX=9

# Contracts
ESPRESSO_SEQUENCER_HOTSHOT_ADDRESS=0xb19b36b1456e65e3a6d514d3f715f204bd59f431
ESPRESSO_SEQUENCER_FEE_CONTRACT_PROXY_ADDRESS=0xa15bb66138824a1c7167f5e85b957d04dd34e468
ESPRESSO_SEQUENCER_LIGHT_CLIENT_PROXY_ADDRESS=0x0c8e79f3534b00d9a3d4a856b665bf4ebc22f2ba
ESPRESSO_SEQUENCER_LIGHTCLIENT_ADDRESS=$ESPRESSO_SEQUENCER_LIGHT_CLIENT_PROXY_ADDRESS

Expand Down Expand Up @@ -104,6 +102,7 @@ ESPRESSO_BUILDER_INIT_NODE_COUNT=$ESPRESSO_ORCHESTRATOR_NUM_NODES
ESPRESSO_BUILDER_BOOTSTRAPPED_VIEW=0
ESPRESSO_BUILDER_WEBSERVER_RESPONSE_TIMEOUT_DURATION=1500ms
ESPRESSO_BUILDER_BUFFER_VIEW_NUM_COUNT=50
ESPRESSO_BUILDER_GENESIS_FILE=$ESPRESSO_SEQUENCER_GENESIS_FILE

# Load generator
ESPRESSO_SUBMIT_TRANSACTIONS_DELAY=2s
Expand Down
29 changes: 7 additions & 22 deletions builder/src/bin/permissioned-builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use hotshot_types::light_client::StateSignKey;
use hotshot_types::signature_key::BLSPrivKey;
use hotshot_types::traits::metrics::NoMetrics;
use hotshot_types::traits::node_implementation::ConsensusTime;
use sequencer::eth_signature_key::EthKeyPair;
use sequencer::persistence::no_storage::NoStorage;
use sequencer::{options::parse_size, BuilderParams, L1Params, NetworkParams};
use sequencer::{eth_signature_key::EthKeyPair, Genesis};
use sequencer::{L1Params, NetworkParams};
use snafu::Snafu;
use std::net::ToSocketAddrs;
use std::num::NonZeroUsize;
Expand All @@ -21,10 +21,6 @@ use url::Url;

#[derive(Parser, Clone, Debug)]
pub struct PermissionedBuilderOptions {
/// Unique identifier for this instance of the sequencer network.
#[clap(long, env = "ESPRESSO_SEQUENCER_CHAIN_ID", default_value = "0")]
pub chain_id: u16,

/// URL of the HotShot orchestrator.
#[clap(
short,
Expand Down Expand Up @@ -80,6 +76,10 @@ pub struct PermissionedBuilderOptions {
)]
pub webserver_poll_interval: Duration,

/// Path to TOML file containing genesis state.
#[clap(long, name = "GENESIS_FILE", env = "ESPRESSO_BUILDER_GENESIS_FILE")]
pub genesis_file: PathBuf,

/// Path to file containing private keys.
///
/// The file should follow the .env format, with two keys:
Expand Down Expand Up @@ -129,10 +129,6 @@ pub struct PermissionedBuilderOptions {
#[clap(long, env = "ESPRESSO_SEQUENCER_STATE_PEERS", value_delimiter = ',')]
pub state_peers: Vec<Url>,

/// Maximum size in bytes of a block
#[clap(long, env = "ESPRESSO_SEQUENCER_MAX_BLOCK_SIZE", value_parser = parse_size)]
pub max_block_size: u64,

/// Port to run the builder server on.
#[clap(short, long, env = "ESPRESSO_BUILDER_SERVER_PORT")]
pub port: u16,
Expand Down Expand Up @@ -174,10 +170,6 @@ pub struct PermissionedBuilderOptions {
/// Whether or not we are a DA node.
#[clap(long, env = "ESPRESSO_SEQUENCER_IS_DA", action)]
pub is_da: bool,

/// Base Fee for a block
#[clap(long, env = "ESPRESSO_BUILDER_BLOCK_BASE_FEE", default_value = "0")]
base_fee: u64,
}

#[derive(Clone, Debug, Snafu)]
Expand Down Expand Up @@ -226,16 +218,11 @@ async fn main() -> anyhow::Result<()> {

let l1_params = L1Params {
url: opt.l1_provider_url,
finalized_block: None,
events_max_block_range: 10000,
};

let builder_key_pair = EthKeyPair::from_mnemonic(&opt.eth_mnemonic, opt.eth_account_index)?;

let builder_params = BuilderParams {
prefunded_accounts: vec![],
};

// Parse supplied Libp2p addresses to their socket form
// We expect all nodes to be reachable via IPv4, so we filter out any IPv6 addresses.
// Downstream in HotShot we pin the IP address to v4, but this can be fixed in the future.
Expand Down Expand Up @@ -277,9 +264,9 @@ async fn main() -> anyhow::Result<()> {

// it will internally spawn the builder web server
let ctx = init_node(
Genesis::from_file(&opt.genesis_file)?,
network_params,
&NoMetrics,
builder_params,
l1_params,
builder_server_url.clone(),
builder_key_pair,
Expand All @@ -291,8 +278,6 @@ async fn main() -> anyhow::Result<()> {
buffer_view_num_count,
opt.is_da,
txn_timeout_duration,
opt.base_fee,
opt.max_block_size,
)
.await?;

Expand Down
38 changes: 14 additions & 24 deletions builder/src/bin/permissionless-builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ use builder::non_permissioned::{build_instance_state, BuilderConfig};
use clap::Parser;
use cld::ClDuration;
use es_version::SEQUENCER_VERSION;
use ethers::types::U256;
use hotshot_types::data::ViewNumber;
use hotshot_types::traits::node_implementation::ConsensusTime;
use sequencer::{eth_signature_key::EthKeyPair, options::parse_size, ChainConfig, L1Params};
use sequencer::{eth_signature_key::EthKeyPair, Genesis, L1Params};
use snafu::Snafu;
use std::num::NonZeroUsize;
use std::{str::FromStr, time::Duration};
use std::{path::PathBuf, str::FromStr, time::Duration};
use url::Url;

#[derive(Parser, Clone, Debug)]
Expand Down Expand Up @@ -42,18 +41,6 @@ struct NonPermissionedBuilderOptions {
#[clap(long, env = "ESPRESSO_SEQUENCER_STATE_PEERS", value_delimiter = ',')]
state_peers: Vec<Url>,

/// Unique identifier for this instance of the sequencer network.
#[clap(long, env = "ESPRESSO_SEQUENCER_CHAIN_ID", default_value = "0")]
chain_id: u64,

/// Maximum size in bytes of a block
#[clap(long, env = "ESPRESSO_SEQUENCER_MAX_BLOCK_SIZE", value_parser = parse_size)]
max_block_size: u64,

/// Minimum fee in WEI per byte of payload
#[clap(long, env = "ESPRESSO_SEQUENCER_BASE_FEE")]
base_fee: U256,

/// Port to run the builder server on.
#[clap(short, long, env = "ESPRESSO_BUILDER_SERVER_PORT")]
port: u16,
Expand Down Expand Up @@ -87,6 +74,10 @@ struct NonPermissionedBuilderOptions {
default_value = "15"
)]
buffer_view_num_count: usize,

/// Path to TOML file containing genesis state.
#[clap(long, name = "GENESIS_FILE", env = "ESPRESSO_BUILDER_GENESIS_FILE")]
genesis_file: PathBuf,
}

#[derive(Clone, Debug, Snafu)]
Expand All @@ -108,12 +99,12 @@ async fn main() -> anyhow::Result<()> {
setup_backtrace();

let opt = NonPermissionedBuilderOptions::parse();
let genesis = Genesis::from_file(&opt.genesis_file)?;

let sequencer_version = SEQUENCER_VERSION;

let l1_params = L1Params {
url: opt.l1_provider_url,
finalized_block: None,
events_max_block_range: 10000,
};

Expand All @@ -122,14 +113,13 @@ async fn main() -> anyhow::Result<()> {

let builder_server_url: Url = format!("http://0.0.0.0:{}", opt.port).parse().unwrap();

let chain_config = ChainConfig {
chain_id: opt.chain_id.into(),
max_block_size: opt.max_block_size,
base_fee: opt.base_fee.into(),
..Default::default()
};
let instance_state =
build_instance_state(l1_params, opt.state_peers, chain_config, sequencer_version).unwrap();
let instance_state = build_instance_state(
genesis.chain_config,
l1_params,
opt.state_peers,
sequencer_version,
)
.unwrap();

let api_response_timeout_duration = opt.max_api_timeout_duration;

Expand Down
2 changes: 1 addition & 1 deletion builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ use sequencer::{
state::FeeAccount,
state::ValidatedState,
state_signature::{static_stake_table_commitment, StateSigner},
BuilderParams, L1Params, NetworkParams, Node, NodeState, PrivKey, PubKey, SeqTypes,
L1Params, NetworkParams, Node, NodeState, PrivKey, PubKey, SeqTypes,
};
use std::{alloc::System, any, fmt::Debug, mem};
use std::{marker::PhantomData, net::IpAddr};
Expand Down
8 changes: 4 additions & 4 deletions builder/src/non_permissioned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ use hotshot_types::{
utils::BuilderCommitment,
};
use sequencer::{
catchup::StatePeers, eth_signature_key::EthKeyPair, l1_client::L1Client, BuilderParams,
ChainConfig, L1Params, NetworkParams, NodeState, Payload, PrivKey, PubKey, SeqTypes,
catchup::StatePeers, eth_signature_key::EthKeyPair, l1_client::L1Client, ChainConfig, L1Params,
NetworkParams, NodeState, Payload, PrivKey, PubKey, SeqTypes,
};

use hotshot_events_service::{
Expand All @@ -59,9 +59,9 @@ pub struct BuilderConfig {
}

pub fn build_instance_state<Ver: StaticVersionType + 'static>(
chain_config: ChainConfig,
l1_params: L1Params,
state_peers: Vec<Url>,
chain_config: ChainConfig,
_: Ver,
) -> anyhow::Result<NodeState> {
let l1_client = L1Client::new(l1_params.url, l1_params.events_max_block_range);
Expand Down Expand Up @@ -154,7 +154,7 @@ impl BuilderConfig {
node_count,
maximize_txns_count_timeout_duration,
instance_state
.chain_config()
.chain_config
.base_fee
.as_u64()
.context("the base fee exceeds the maximum amount that a builder can pay (defined by u64::MAX)")?,
Expand Down
40 changes: 23 additions & 17 deletions builder/src/permissioned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,14 @@ use sequencer::{catchup::mock::MockStateCatchup, eth_signature_key::EthKeyPair,
use sequencer::{
catchup::StatePeers,
context::{Consensus, SequencerContext},
genesis::L1Finalized,
l1_client::L1Client,
network,
persistence::SequencerPersistence,
state::FeeAccount,
state::ValidatedState,
state_signature::{static_stake_table_commitment, StateSigner},
BuilderParams, L1Params, NetworkParams, Node, NodeState, Payload, PrivKey, PubKey, SeqTypes,
Genesis, L1Params, NetworkParams, Node, NodeState, Payload, PrivKey, PubKey, SeqTypes,
};
use std::{alloc::System, any, fmt::Debug, mem};
use std::{marker::PhantomData, net::IpAddr};
Expand Down Expand Up @@ -127,9 +128,9 @@ pub struct BuilderContext<

#[allow(clippy::too_many_arguments)]
pub async fn init_node<P: SequencerPersistence, Ver: StaticVersionType + 'static>(
genesis: Genesis,
network_params: NetworkParams,
metrics: &dyn Metrics,
builder_params: BuilderParams,
l1_params: L1Params,
hotshot_builder_api_url: Url,
eth_key_pair: EthKeyPair,
Expand All @@ -141,8 +142,6 @@ pub async fn init_node<P: SequencerPersistence, Ver: StaticVersionType + 'static
buffered_view_num_count: usize,
is_da: bool,
maximize_txns_count_timeout_duration: Duration,
base_fee: u64,
max_block_size: u64,
) -> anyhow::Result<BuilderContext<network::Production, P, Ver>> {
// Orchestrator client
let validator_args = ValidatorArgs {
Expand Down Expand Up @@ -242,22 +241,29 @@ pub async fn init_node<P: SequencerPersistence, Ver: StaticVersionType + 'static
let _ = NetworkingMetricsValue::new(metrics);

let mut genesis_state = ValidatedState::default();
for address in builder_params.prefunded_accounts {
tracing::warn!("Prefunding account {:?} for demo", address);
genesis_state.prefund_account(address.into(), U256::max_value().into());
for (address, amount) in genesis.accounts {
tracing::warn!(%address, %amount, "Prefunding account for demo");
genesis_state.prefund_account(address, amount);
}

let l1_client = L1Client::new(l1_params.url, l1_params.events_max_block_range);
let instance_state = NodeState::new(
node_index,
ChainConfig {
max_block_size,
base_fee: base_fee.into(),
..Default::default()
},
let l1_genesis = match genesis.l1_finalized {
Some(L1Finalized::Block(b)) => Some(b),
Some(L1Finalized::Number { number }) => {
Some(l1_client.wait_for_finalized_block(number).await)
}
None => None,
};

let instance_state = NodeState {
chain_config: genesis.chain_config,
l1_client,
Arc::new(StatePeers::<Ver>::from_urls(network_params.state_peers)),
);
genesis_header: genesis.header,
genesis_state,
l1_genesis,
peers: Arc::new(StatePeers::<Ver>::from_urls(network_params.state_peers)),
node_id: node_index,
};

let stake_table_commit =
static_stake_table_commitment(&config.config.known_nodes_with_stake, STAKE_TABLE_CAPACITY);
Expand Down Expand Up @@ -441,7 +447,7 @@ impl<N: network::Type, P: SequencerPersistence, Ver: StaticVersionType + 'static
NonZeroUsize::new(1).unwrap(),
maximize_txns_count_timeout_duration,
instance_state
.chain_config()
.chain_config
.base_fee
.as_u64()
.context("the base fee exceeds the maximum amount that a builder can pay (defined by u64::MAX)")?,
Expand Down
2 changes: 1 addition & 1 deletion data/chain_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"chain_id": "35353",
"fee_contract": "0x0000000000000000000000000000000000000000",
"fee_recipient": "0x0000000000000000000000000000000000000000",
"max_block_size": 10240
"max_block_size": "10240"
}
11 changes: 11 additions & 0 deletions data/genesis/cappuccino.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[stake_table]
capacity = 200

[chain_config]
chain_id = 0
base_fee = '0 wei'
max_block_size = '30mb'
fee_recipient = '0x0000000000000000000000000000000000000000'

[header]
timestamp = "1970-01-01T00:00:00Z"
12 changes: 12 additions & 0 deletions data/genesis/demo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[stake_table]
capacity = 10

[chain_config]
chain_id = 999999999
base_fee = '1 wei'
max_block_size = '1mb'
fee_recipient = '0x0000000000000000000000000000000000000000'
fee_contract = '0xa15bb66138824a1c7167f5e85b957d04dd34e468'

[header]
timestamp = "1970-01-01T00:00:00Z"
11 changes: 11 additions & 0 deletions data/genesis/staging.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[stake_table]
capacity = 10

[chain_config]
chain_id = 888888888
base_fee = '0 wei'
max_block_size = '1mb'
fee_recipient = '0x0000000000000000000000000000000000000000'

[header]
timestamp = "1970-01-01T00:00:00Z"
2 changes: 1 addition & 1 deletion data/header.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"chain_id": "35353",
"fee_contract": "0x0000000000000000000000000000000000000000",
"fee_recipient": "0x0000000000000000000000000000000000000000",
"max_block_size": 10240
"max_block_size": "10240"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion data/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"chain_id": "35353",
"fee_contract": null,
"fee_recipient": "0x0000000000000000000000000000000000000000",
"max_block_size": 10240
"max_block_size": "10240"
}
}
},
Expand Down
Loading

0 comments on commit 8182221

Please sign in to comment.