Skip to content

Commit

Permalink
Make bids and timeouts configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
cronokirby authored and redshiftzero committed Nov 1, 2023
1 parent ac07d2f commit 5ecf948
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 28 deletions.
49 changes: 49 additions & 0 deletions tools/summonerd/src/config.rs
Original file line number Diff line number Diff line change
@@ -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<u64>) -> Self {
if let Some(x) = x {
self.phase1_timeout_secs = x;
}
self
}

pub fn with_phase2_timeout_secs(mut self, x: Option<u64>) -> Self {
if let Some(x) = x {
self.phase2_timeout_secs = x;
}
self
}

pub fn with_min_bid_u64(mut self, x: Option<u64>) -> Self {
if let Some(x) = x {
self.min_bid_u64 = x;
}
self
}

pub fn with_max_strikes(mut self, x: Option<u64>) -> Self {
if let Some(x) = x {
self.max_strikes = x;
}
self
}
}
16 changes: 12 additions & 4 deletions tools/summonerd/src/coordinator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<P: Phase + 'static>(mut self) -> Result<()> {
Expand Down Expand Up @@ -46,7 +54,7 @@ impl Coordinator {
async fn contribute<P: Phase>(&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::<P>(contributor),
)
.await
Expand Down
36 changes: 31 additions & 5 deletions tools/summonerd/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod config;
mod coordinator;
mod participant;
mod penumbra_knower;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<u64>,
#[clap(long, display_order = 1001)]
phase2_timeout_secs: Option<u64>,
#[clap(long, display_order = 1002)]
min_bid_u64: Option<u64>,
#[clap(long, display_order = 1002)]
max_strikes: Option<u64>,
},
/// Export the output of the ceremony
Export {
Expand Down Expand Up @@ -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()
Expand All @@ -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 => {
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down
18 changes: 11 additions & 7 deletions tools/summonerd/src/phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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<CeremonyCrs>;
Expand Down Expand Up @@ -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<CeremonyCrs> {
data.try_into()
Expand Down Expand Up @@ -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<CeremonyCrs> {
data.try_into()
Expand Down
29 changes: 17 additions & 12 deletions tools/summonerd/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand All @@ -53,21 +50,28 @@ pub enum ContributionAllowed {

#[derive(Clone)]
pub struct Storage {
config: Config,
pool: r2d2::Pool<SqliteConnectionManager>,
}

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<Utf8Path>) -> anyhow::Result<Self> {
pub async fn load_or_initialize(
config: Config,
storage_path: impl AsRef<Utf8Path>,
) -> anyhow::Result<Self> {
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<Utf8Path>) -> anyhow::Result<Self> {
async fn initialize(
config: Config,
storage_path: impl AsRef<Utf8Path>,
) -> anyhow::Result<Self> {
// Connect to the database (or create it)
let pool = Self::connect(storage_path)?;

Expand All @@ -81,13 +85,14 @@ impl Storage {

tx.commit()?;

Ok(Storage { pool })
Ok(Storage { config, pool })
})
.await?
}

async fn load(path: impl AsRef<Utf8Path>) -> anyhow::Result<Self> {
async fn load(config: Config, path: impl AsRef<Utf8Path>) -> anyhow::Result<Self> {
let storage = Self {
config,
pool: Self::connect(path)?,
};

Expand Down Expand Up @@ -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 = {
Expand All @@ -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))
Expand Down

0 comments on commit 5ecf948

Please sign in to comment.