From e22d4277dfcb569e28952c3efc1476b64a779495 Mon Sep 17 00:00:00 2001 From: Lucas Meier Date: Wed, 1 Nov 2023 10:52:18 -0700 Subject: [PATCH] Make bids and timeouts configurable --- tools/summonerd/src/config.rs | 49 ++++++++++++++++++++++++++++++ tools/summonerd/src/coordinator.rs | 16 +++++++--- tools/summonerd/src/main.rs | 36 +++++++++++++++++++--- tools/summonerd/src/phase.rs | 18 ++++++----- tools/summonerd/src/storage.rs | 29 ++++++++++-------- 5 files changed, 120 insertions(+), 28 deletions(-) create mode 100644 tools/summonerd/src/config.rs diff --git a/tools/summonerd/src/config.rs b/tools/summonerd/src/config.rs new file mode 100644 index 0000000000..c43ac41455 --- /dev/null +++ b/tools/summonerd/src/config.rs @@ -0,0 +1,49 @@ +/// Configuration for the +#[derive(Clone, Copy)] +pub struct Config { + pub phase1_timeout_secs: u64, + pub phase2_timeout_secs: u64, + pub min_bid_u64: u64, + pub max_strikes: u64, +} + +impl Default for Config { + fn default() -> Self { + Self { + phase1_timeout_secs: 12 * 60, + phase2_timeout_secs: 8 * 60, + min_bid_u64: 1, + max_strikes: 3, + } + } +} + +impl Config { + pub fn with_phase1_timeout_secs(mut self, x: Option) -> Self { + if let Some(x) = x { + self.phase1_timeout_secs = x; + } + self + } + + pub fn with_phase2_timeout_secs(mut self, x: Option) -> Self { + if let Some(x) = x { + self.phase2_timeout_secs = x; + } + self + } + + pub fn with_min_bid_u64(mut self, x: Option) -> Self { + if let Some(x) = x { + self.min_bid_u64 = x; + } + self + } + + pub fn with_max_strikes(mut self, x: Option) -> Self { + if let Some(x) = x { + self.max_strikes = x; + } + self + } +} diff --git a/tools/summonerd/src/coordinator.rs b/tools/summonerd/src/coordinator.rs index da915c5e81..d9be3c8fab 100644 --- a/tools/summonerd/src/coordinator.rs +++ b/tools/summonerd/src/coordinator.rs @@ -2,18 +2,26 @@ use std::time::Duration; use anyhow::Result; -use crate::{participant::Participant, phase::Phase, queue::ParticipantQueue, storage::Storage}; +use crate::{ + config::Config, participant::Participant, phase::Phase, queue::ParticipantQueue, + storage::Storage, +}; const QUEUE_SLEEP_TIME_SECS: u64 = 1; pub struct Coordinator { + config: Config, storage: Storage, queue: ParticipantQueue, } impl Coordinator { - pub fn new(storage: Storage, queue: ParticipantQueue) -> Self { - Self { storage, queue } + pub fn new(config: Config, storage: Storage, queue: ParticipantQueue) -> Self { + Self { + config, + storage, + queue, + } } pub async fn run(mut self) -> Result<()> { @@ -46,7 +54,7 @@ impl Coordinator { async fn contribute(&mut self, contributor: Participant) -> Result<()> { let address = contributor.address(); match tokio::time::timeout( - Duration::from_secs(P::CONTRIBUTION_TIME_SECS), + Duration::from_secs(P::contribution_time(self.config)), self.contribute_inner::

(contributor), ) .await diff --git a/tools/summonerd/src/main.rs b/tools/summonerd/src/main.rs index aedecfff6f..82a9ef2cb0 100644 --- a/tools/summonerd/src/main.rs +++ b/tools/summonerd/src/main.rs @@ -1,3 +1,4 @@ +mod config; mod coordinator; mod participant; mod penumbra_knower; @@ -36,6 +37,7 @@ use tracing::Instrument; use tracing_subscriber::{prelude::*, EnvFilter}; use url::Url; +use crate::config::Config; use crate::phase::Phase1; use crate::phase::Phase2; use crate::phase::PhaseMarker; @@ -131,6 +133,14 @@ enum Command { #[clap(long, display_order = 902, default_value = "127.0.0.1:8080")] /// The address to bind the gRPC and web servers to. bind_addr: SocketAddr, + #[clap(long, display_order = 1000)] + phase1_timeout_secs: Option, + #[clap(long, display_order = 1001)] + phase2_timeout_secs: Option, + #[clap(long, display_order = 1002)] + min_bid_u64: Option, + #[clap(long, display_order = 1002)] + max_strikes: Option, }, /// Export the output of the ceremony Export { @@ -158,13 +168,23 @@ impl Opt { fvk, node, bind_addr, + phase1_timeout_secs, + phase2_timeout_secs, + min_bid_u64, + max_strikes, } => { + let config = Config::default() + .with_phase1_timeout_secs(phase1_timeout_secs) + .with_phase2_timeout_secs(phase2_timeout_secs) + .with_min_bid_u64(min_bid_u64) + .with_max_strikes(max_strikes); let marker = match phase { 1 => PhaseMarker::P1, 2 => PhaseMarker::P2, _ => anyhow::bail!("Phase must be 1 or 2."), }; - let storage = Storage::load_or_initialize(ceremony_db(&storage_dir)).await?; + let storage = + Storage::load_or_initialize(config, ceremony_db(&storage_dir)).await?; // Check if we've transitioned, for a nice error message if marker == PhaseMarker::P2 && storage.transition_extra_information().await?.is_none() @@ -175,7 +195,7 @@ impl Opt { PenumbraKnower::load_or_initialize(storage_dir.join("penumbra.db"), &fvk, node) .await?; let queue = ParticipantQueue::new(); - let coordinator = Coordinator::new(storage.clone(), queue.clone()); + let coordinator = Coordinator::new(config, storage.clone(), queue.clone()); let coordinator_span = tracing::error_span!("coordinator"); let coordinator_handle = match marker { PhaseMarker::P1 => { @@ -226,13 +246,17 @@ impl Opt { // This is assumed to be valid as it's the starting point for the ceremony. let phase_1_root = phase_1_raw_root.assume_valid(); - let mut storage = Storage::load_or_initialize(ceremony_db(&storage_dir)).await?; + let mut storage = + Storage::load_or_initialize(Config::default(), ceremony_db(&storage_dir)) + .await?; storage.set_root(phase_1_root).await?; Ok(()) } Command::Transition { storage_dir } => { - let mut storage = Storage::load_or_initialize(ceremony_db(&storage_dir)).await?; + let mut storage = + Storage::load_or_initialize(Config::default(), ceremony_db(&storage_dir)) + .await?; let phase1_crs = match storage.phase1_current_crs().await? { Some(x) => x, @@ -247,7 +271,9 @@ impl Opt { storage_dir, target_dir, } => { - let storage = Storage::load_or_initialize(ceremony_db(&storage_dir)).await?; + let storage = + Storage::load_or_initialize(Config::default(), ceremony_db(&storage_dir)) + .await?; // Grab phase1 output let phase1_crs = match storage.phase1_current_crs().await? { Some(x) => x, diff --git a/tools/summonerd/src/phase.rs b/tools/summonerd/src/phase.rs index 27b41306bd..adea757005 100644 --- a/tools/summonerd/src/phase.rs +++ b/tools/summonerd/src/phase.rs @@ -9,7 +9,7 @@ use penumbra_proto::tools::summoning::v1alpha1::{ participate_request::Contribution as PBContribution, CeremonyCrs, }; -use crate::storage::Storage; +use crate::{config::Config, storage::Storage}; /// A simple marker for which phase we're in, which some code can depend on at runtime. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -36,10 +36,8 @@ pub trait Phase { /// The constant value for the marker we use, for runtime dispatch. const MARKER: PhaseMarker; - /// The amount of time we should wait for a contribution. - /// - /// This varies since one phase is more expensive than the other. - const CONTRIBUTION_TIME_SECS: u64; + /// Get the contribution time from a config + fn contribution_time(config: Config) -> u64; /// Serialize the CRS value, in a potentially failing way. fn serialize_crs(data: Self::CRS) -> Result; @@ -80,7 +78,10 @@ impl Phase for Phase1 { type RawContribution = Phase1RawCeremonyContribution; type Contribution = Phase1CeremonyContribution; const MARKER: PhaseMarker = PhaseMarker::P1; - const CONTRIBUTION_TIME_SECS: u64 = 20 * 60; + + fn contribution_time(config: Config) -> u64 { + config.phase1_timeout_secs + } fn serialize_crs(data: Self::CRS) -> Result { data.try_into() @@ -128,7 +129,10 @@ impl Phase for Phase2 { type RawContribution = Phase2RawCeremonyContribution; type Contribution = Phase2CeremonyContribution; const MARKER: PhaseMarker = PhaseMarker::P2; - const CONTRIBUTION_TIME_SECS: u64 = 10 * 60; + + fn contribution_time(config: Config) -> u64 { + config.phase2_timeout_secs + } fn serialize_crs(data: Self::CRS) -> Result { data.try_into() diff --git a/tools/summonerd/src/storage.rs b/tools/summonerd/src/storage.rs index 07027dd2f9..5e7f3ba6cb 100644 --- a/tools/summonerd/src/storage.rs +++ b/tools/summonerd/src/storage.rs @@ -24,10 +24,7 @@ use r2d2_sqlite::{ }; use tokio::task::spawn_blocking; -use crate::{penumbra_knower::PenumbraKnower, phase::PhaseMarker}; - -const MIN_BID_AMOUNT_U64: u64 = 1u64; -const MAX_STRIKES: u64 = 3u64; +use crate::{config::Config, penumbra_knower::PenumbraKnower, phase::PhaseMarker}; /// The current time as a unix timestamp. /// @@ -53,21 +50,28 @@ pub enum ContributionAllowed { #[derive(Clone)] pub struct Storage { + config: Config, pool: r2d2::Pool, } impl Storage { /// If the database at `storage_path` exists, [`Self::load`] it, otherwise, [`Self::initialize`] it. - pub async fn load_or_initialize(storage_path: impl AsRef) -> anyhow::Result { + pub async fn load_or_initialize( + config: Config, + storage_path: impl AsRef, + ) -> anyhow::Result { if storage_path.as_ref().exists() { - return Self::load(storage_path).await; + return Self::load(config, storage_path).await; } - Self::initialize(storage_path).await + Self::initialize(config, storage_path).await } /// Initialize creates the database, but does not insert anything into it. - async fn initialize(storage_path: impl AsRef) -> anyhow::Result { + async fn initialize( + config: Config, + storage_path: impl AsRef, + ) -> anyhow::Result { // Connect to the database (or create it) let pool = Self::connect(storage_path)?; @@ -81,13 +85,14 @@ impl Storage { tx.commit()?; - Ok(Storage { pool }) + Ok(Storage { config, pool }) }) .await? } - async fn load(path: impl AsRef) -> anyhow::Result { + async fn load(config: Config, path: impl AsRef) -> anyhow::Result { let storage = Self { + config, pool: Self::connect(path)?, }; @@ -196,7 +201,7 @@ impl Storage { // - Hasn't already contributed // - Not banned let amount = knower.total_amount_sent_to_me(&address).await?; - if amount < Amount::from(MIN_BID_AMOUNT_U64) { + if amount < Amount::from(self.config.min_bid_u64) { return Ok(ContributionAllowed::DidntBidEnough(amount)); } let has_contributed = { @@ -213,7 +218,7 @@ impl Storage { if has_contributed { return Ok(ContributionAllowed::AlreadyContributed); } - if self.get_strikes(address).await? >= MAX_STRIKES { + if self.get_strikes(address).await? >= self.config.max_strikes { return Ok(ContributionAllowed::Banned); } Ok(ContributionAllowed::Yes(amount))