Skip to content

Commit

Permalink
Merge branch 'ab/st' into ma/hotshot-0.5.83
Browse files Browse the repository at this point in the history
  • Loading branch information
imabdulbasit authored Dec 20, 2024
2 parents bd74fe5 + 9d0bf9c commit 6a6be1a
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 2 deletions.
1 change: 1 addition & 0 deletions sequencer/src/bin/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ struct Options {
/// stake_table_key = "BLS_VER_KEY~...",
/// state_ver_key = "SCHNORR_VER_KEY~...",
/// da = true,
/// stake = 1, # this value is ignored, but needs to be set
/// },
/// ]
#[clap(long, env = "ESPRESSO_SEQUENCER_INITIAL_PERMISSIONED_STAKE_TABLE_PATH")]
Expand Down
104 changes: 104 additions & 0 deletions sequencer/src/bin/update-permissioned-stake-table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use anyhow::Result;
use clap::Parser;
use espresso_types::parse_duration;
use ethers::types::Address;
use sequencer_utils::{logging, stake_table::{update_stake_table, PermissionedStakeTableUpdate}};
use std::{path::PathBuf, time::Duration};
use url::Url;

#[derive(Debug, Clone, Parser)]
struct Options {
/// RPC URL for the L1 provider.
#[clap(
short,
long,
env = "ESPRESSO_SEQUENCER_L1_PROVIDER",
default_value = "http://localhost:8545"
)]
rpc_url: Url,

/// Request rate when polling L1.
#[clap(
long,
env = "ESPRESSO_SEQUENCER_L1_POLLING_INTERVAL",
default_value = "7s",
value_parser = parse_duration,
)]
pub l1_polling_interval: Duration,

/// Mnemonic for an L1 wallet.
///
/// This wallet is used to deploy the contracts, so the account indicated by ACCOUNT_INDEX must
/// be funded with with ETH.
#[clap(
long,
name = "MNEMONIC",
env = "ESPRESSO_SEQUENCER_ETH_MNEMONIC",
default_value = "test test test test test test test test test test test junk"
)]
mnemonic: String,

/// Account index in the L1 wallet generated by MNEMONIC to use when deploying the contracts.
#[clap(
long,
name = "ACCOUNT_INDEX",
env = "ESPRESSO_DEPLOYER_ACCOUNT_INDEX",
default_value = "0"
)]
account_index: u32,

/// Permissioned stake table contract address.
#[clap(long, env = "ESPRESSO_SEQUENCER_PERMISSIONED_STAKE_TABLE_ADDRESS")]
contract_address: Address,

/// Path to the toml file containing the update information.
///
/// Schema of toml file:
/// ```toml
/// stakers_to_remove = [
/// {
/// stake_table_key = "BLS_VER_KEY~...",
/// state_ver_key = "SCHNORR_VER_KEY~...",
/// da = false,
/// stake = 1, # this value is ignored, but needs to be set
/// },
/// ]
///
/// new_stakers = [
/// {
/// stake_table_key = "BLS_VER_KEY~...",
/// state_ver_key = "SCHNORR_VER_KEY~...",
/// da = true,
/// stake = 1, # this value is ignored, but needs to be set
/// },
/// ]
/// ```
#[clap(
long,
env = "ESPRESSO_SEQUENCER_PERMISSIONED_STAKE_TABLE_UPDATE_TOML_PATH",
verbatim_doc_comment
)]
update_toml_path: PathBuf,
#[clap(flatten)]
logging: logging::Config,
}

#[tokio::main]
async fn main() -> Result<()> {
let opts = Options::parse();
opts.logging.init();
let update = PermissionedStakeTableUpdate::from_toml_file(&opts.update_toml_path)?;


update_stake_table(
opts.rpc_url,
opts.l1_polling_interval,
opts.mnemonic,
opts.account_index,
opts.contract_address,
update,
)
.await?;

Ok(())
}
87 changes: 85 additions & 2 deletions utils/src/stake_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
///
/// The initial stake table is passed to the permissioned stake table contract
/// on deployment.
use contract_bindings::permissioned_stake_table::NodeInfo;
use contract_bindings::permissioned_stake_table::{NodeInfo, PermissionedStakeTable};
use ethers::{
middleware::SignerMiddleware,
providers::{Http, Middleware as _, Provider},
signers::{coins_bip39::English, MnemonicBuilder, Signer as _},
types::Address,
};
use hotshot::types::BLSPubKey;
use hotshot_contract_adapter::stake_table::NodeInfoJf;
use hotshot_types::network::PeerConfigKeys;
use url::Url;

use std::{fs, path::Path};
use std::{fs, path::Path, sync::Arc, time::Duration};

/// A stake table config stored in a file
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
Expand Down Expand Up @@ -48,6 +55,82 @@ impl From<PermissionedStakeTableConfig> for Vec<NodeInfo> {
}
}

/// Information to add and remove stakers in the permissioned stake table contract.
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(bound(deserialize = ""))]
pub struct PermissionedStakeTableUpdate {
#[serde(default)]
stakers_to_remove: Vec<PeerConfigKeys<BLSPubKey>>,
#[serde(default)]
new_stakers: Vec<PeerConfigKeys<BLSPubKey>>,
}

impl PermissionedStakeTableUpdate {
pub fn from_toml_file(path: &Path) -> anyhow::Result<Self> {
let config_file_as_string: String = fs::read_to_string(path)
.unwrap_or_else(|_| panic!("Could not read config file located at {}", path.display()));

Ok(
toml::from_str::<Self>(&config_file_as_string).unwrap_or_else(|err| {
panic!(
"Unable to convert config file {} to TOML: {err}",
path.display()
)
}),
)
}

fn stakers_to_remove(&self) -> Vec<NodeInfo> {
self.stakers_to_remove
.iter()
.map(|peer_config| {
let node_info: NodeInfoJf = peer_config.clone().into();
node_info.into()
})
.collect()
}

fn new_stakers(&self) -> Vec<NodeInfo> {
self.new_stakers
.iter()
.map(|peer_config| {
let node_info: NodeInfoJf = peer_config.clone().into();
node_info.into()
})
.collect()
}
}

pub async fn update_stake_table(
l1url: Url,
l1_interval: Duration,
mnemonic: String,
account_index: u32,
contract_address: Address,
update: PermissionedStakeTableUpdate,
) -> anyhow::Result<()> {
let provider = Provider::<Http>::try_from(l1url.to_string())?.interval(l1_interval);
let chain_id = provider.get_chainid().await?.as_u64();
let wallet = MnemonicBuilder::<English>::default()
.phrase(mnemonic.as_str())
.index(account_index)?
.build()?
.with_chain_id(chain_id);
let l1 = Arc::new(SignerMiddleware::new(provider.clone(), wallet));

let contract = PermissionedStakeTable::new(contract_address, l1);

tracing::info!("sending stake table update transaction");

let tx_receipt = contract
.update(update.stakers_to_remove(), update.new_stakers())
.send()
.await?
.await?;
tracing::info!("Transaction receipt: {:?}", tx_receipt);
Ok(())
}

#[cfg(test)]
mod test {
use crate::stake_table::PermissionedStakeTableConfig;
Expand Down

0 comments on commit 6a6be1a

Please sign in to comment.