Skip to content

Commit

Permalink
feat: configure presignature generation to limit max supply of presig…
Browse files Browse the repository at this point in the history
…nature (#507)

* Added max_concurrent_generation for limiting triple timeouts

* Added concurrent introduction param to limit each node generating

* Added naive intersection check for threshold

* Make stockpile test use 8 nodes (#506)

* Added PresignatureConfig and adjusted defaults

* Make triple generation use ongoing for concurrent generation

* Each node can only produce Presignatures by max concurrent introduction

* Do not take in triple generation on reaching max capacity

* back to generators

---------

Co-authored-by: Serhii Volovyk <sergeyvolovyk@gmail.com>
  • Loading branch information
ChaoticTempest and volovyks authored Mar 26, 2024
1 parent 0a3986b commit d6673c5
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 77 deletions.
2 changes: 2 additions & 0 deletions integration-tests/src/multichain/containers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ impl<'a> Node<'a> {
max_triples: cfg.triple_cfg.max_triples,
max_concurrent_introduction: cfg.triple_cfg.max_concurrent_introduction,
max_concurrent_generation: cfg.triple_cfg.max_concurrent_generation,
min_presignatures: cfg.presig_cfg.min_presignatures,
max_presignatures: cfg.presig_cfg.max_presignatures,
}
.into_str_args();
let image: GenericImage = GenericImage::new("near/mpc-recovery-node", "latest")
Expand Down
2 changes: 2 additions & 0 deletions integration-tests/src/multichain/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ impl Node {
max_triples: cfg.triple_cfg.max_triples,
max_concurrent_introduction: cfg.triple_cfg.max_concurrent_introduction,
max_concurrent_generation: cfg.triple_cfg.max_concurrent_generation,
min_presignatures: cfg.presig_cfg.min_presignatures,
max_presignatures: cfg.presig_cfg.max_presignatures,
};

let mpc_node_id = format!("multichain/{account_id}", account_id = account_id);
Expand Down
6 changes: 6 additions & 0 deletions integration-tests/src/multichain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::mpc::TARGET_CONTRACT_DIR;
use crate::{initialize_lake_indexer, LakeIndexerCtx};
use mpc_contract::primitives::CandidateInfo;
use mpc_recovery_node::gcp::GcpService;
use mpc_recovery_node::protocol::presignature::PresignatureConfig;
use mpc_recovery_node::protocol::triple::TripleConfig;
use mpc_recovery_node::storage;
use mpc_recovery_node::storage::triple_storage::TripleNodeStorageBox;
Expand All @@ -22,6 +23,7 @@ pub struct MultichainConfig {
pub nodes: usize,
pub threshold: usize,
pub triple_cfg: TripleConfig,
pub presig_cfg: PresignatureConfig,
}

impl Default for MultichainConfig {
Expand All @@ -35,6 +37,10 @@ impl Default for MultichainConfig {
max_concurrent_introduction: 8,
max_concurrent_generation: 24,
},
presig_cfg: PresignatureConfig {
min_presignatures: 2,
max_presignatures: 20,
},
}
}
}
Expand Down
15 changes: 12 additions & 3 deletions integration-tests/tests/multichain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use k256::elliptic_curve::point::AffineCoordinates;
use mpc_recovery_integration_tests::env::containers::DockerClient;
use mpc_recovery_integration_tests::multichain::MultichainConfig;
use mpc_recovery_node::kdf::{self, x_coordinate};
use mpc_recovery_node::protocol::presignature::PresignatureConfig;
use mpc_recovery_node::protocol::triple::TripleConfig;
use mpc_recovery_node::test_utils;
use mpc_recovery_node::types::LatestBlockHeight;
Expand Down Expand Up @@ -130,9 +131,9 @@ async fn test_signature_offline_node() -> anyhow::Result<()> {
#[ignore = "This test is too slow to run in CI"]
async fn test_signature_large_stockpile() -> anyhow::Result<()> {
const SIGNATURE_AMOUNT: usize = 10;
const NODES: usize = 3;
const THRESHOLD: usize = 2;
const MIN_TRIPLES: usize = 20;
const NODES: usize = 8;
const THRESHOLD: usize = 4;
const MIN_TRIPLES: usize = 10;
const MAX_TRIPLES: usize = 2 * NODES * MIN_TRIPLES;

let triple_cfg = TripleConfig {
Expand All @@ -145,8 +146,16 @@ async fn test_signature_large_stockpile() -> anyhow::Result<()> {
// This is the maximum amount of triples that can be generated concurrently by the whole system.
max_concurrent_generation: 24,
};
let presig_cfg = PresignatureConfig {
// this is the min presignatures required by each node
min_presignatures: 10,
// This is the total amount of presignatures that will be generated by all nodes.
max_presignatures: 1000,
};

let config = MultichainConfig {
triple_cfg,
presig_cfg,
nodes: NODES,
threshold: THRESHOLD,
};
Expand Down
37 changes: 30 additions & 7 deletions node/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::gcp::GcpService;
use crate::protocol::presignature::PresignatureConfig;
use crate::protocol::triple::TripleConfig;
use crate::protocol::{MpcSignProtocol, SignQueue};
use crate::protocol::{Config, MpcSignProtocol, SignQueue};
use crate::storage::triple_storage::LockTripleNodeStorageBox;
use crate::{indexer, storage, web};
use clap::Parser;
Expand Down Expand Up @@ -76,6 +77,14 @@ pub enum Cli {
default_value("32")
)]
max_concurrent_generation: usize,

/// At minimum, how many presignatures to stockpile on this node.
#[arg(long, env("MPC_RECOVERY_MIN_PRESIGNATURES"), default_value("10"))]
min_presignatures: usize,

/// At maximum, how many presignatures to stockpile on the network.
#[arg(long, env("MPC_RECOVERY_MAX_PRESIGNATURES"), default_value("100"))]
max_presignatures: usize,
},
}

Expand All @@ -97,6 +106,8 @@ impl Cli {
max_triples,
max_concurrent_introduction,
max_concurrent_generation,
min_presignatures,
max_presignatures,
} => {
let mut args = vec![
"start".to_string(),
Expand All @@ -122,6 +133,10 @@ impl Cli {
max_concurrent_introduction.to_string(),
"--max-concurrent-generation".to_string(),
max_concurrent_generation.to_string(),
"--min-presignatures".to_string(),
min_presignatures.to_string(),
"--max-presignatures".to_string(),
max_presignatures.to_string(),
];
if let Some(my_address) = my_address {
args.extend(vec!["--my-address".to_string(), my_address.to_string()]);
Expand Down Expand Up @@ -163,6 +178,8 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> {
max_triples,
max_concurrent_introduction,
max_concurrent_generation,
min_presignatures,
max_presignatures,
} => {
let sign_queue = Arc::new(RwLock::new(SignQueue::new()));
tokio::runtime::Builder::new_multi_thread()
Expand Down Expand Up @@ -205,13 +222,19 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> {
sign_queue.clone(),
hpke::PublicKey::try_from_bytes(&hex::decode(cipher_pk)?)?,
key_storage,
TripleConfig {
min_triples,
max_triples,
max_concurrent_introduction,
max_concurrent_generation,
},
triple_storage,
Config {
triple_cfg: TripleConfig {
min_triples,
max_triples,
max_concurrent_introduction,
max_concurrent_generation,
},
presig_cfg: PresignatureConfig {
min_presignatures,
max_presignatures,
},
},
);
tracing::debug!("protocol initialized");
let protocol_handle = tokio::spawn(async move { protocol.run().await });
Expand Down
11 changes: 6 additions & 5 deletions node/src/protocol/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ use super::state::{
JoiningState, NodeState, PersistentNodeData, RunningState, StartedState,
WaitingForConsensusState,
};
use super::triple::TripleConfig;
use super::SignQueue;
use super::{Config, SignQueue};
use crate::gcp::error::DatastoreStorageError;
use crate::gcp::error::SecretStorageError;
use crate::protocol::contract::primitives::Participants;
Expand Down Expand Up @@ -41,8 +40,8 @@ pub trait ConsensusCtx {
fn sign_pk(&self) -> near_crypto::PublicKey;
fn sign_sk(&self) -> &near_crypto::SecretKey;
fn secret_storage(&self) -> &SecretNodeStorageBox;
fn triple_cfg(&self) -> TripleConfig;
fn triple_storage(&mut self) -> LockTripleNodeStorageBox;
fn cfg(&self) -> Config;
}

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -132,12 +131,13 @@ impl ConsensusProtocol for StartedState {
contract_state.threshold,
epoch,
account_id.clone(),
ctx.cfg(),
);
let triple_manager = TripleManager::new(
me,
contract_state.threshold,
epoch,
ctx.triple_cfg(),
ctx.cfg(),
self.triple_data,
ctx.triple_storage(),
);
Expand Down Expand Up @@ -349,7 +349,7 @@ impl ConsensusProtocol for WaitingForConsensusState {
me,
self.threshold,
self.epoch,
ctx.triple_cfg(),
ctx.cfg(),
vec![],
ctx.triple_storage(),
);
Expand All @@ -367,6 +367,7 @@ impl ConsensusProtocol for WaitingForConsensusState {
self.threshold,
self.epoch,
ctx.my_account_id().clone(),
ctx.cfg(),
))),
signature_manager: Arc::new(RwLock::new(SignatureManager::new(
me,
Expand Down
43 changes: 8 additions & 35 deletions node/src/protocol/cryptography.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,41 +369,14 @@ impl CryptographicProtocol for RunningState {
.set(triple_manager.ongoing.len() as i64);

let mut presignature_manager = self.presignature_manager.write().await;
// TODO: separate out into our own presignature_cfg
if presignature_manager.my_len() < triple_manager.triple_cfg.min_triples
&& presignature_manager.potential_len() < triple_manager.triple_cfg.max_triples
{
// To ensure there is no contention between different nodes we are only using triples
// that we proposed. This way in a non-BFT environment we are guaranteed to never try
// to use the same triple as any other node.
if let Some((triple0, triple1)) = triple_manager.take_two_mine().await {
let presig_participants = active
.intersection(&[&triple0.public.participants, &triple1.public.participants]);
if presig_participants.len() < self.threshold {
tracing::debug!(
participants = ?presig_participants.keys_vec(),
"running(pre): we don't have enough participants to generate a presignature"
);

// Insert back the triples to be used later since this active set of
// participants were not able to make use of these triples.
triple_manager.insert_mine(triple0).await;
triple_manager.insert_mine(triple1).await;
} else {
presignature_manager.generate(
&presig_participants,
triple0,
triple1,
&self.public_key,
&self.private_share,
)?;
}
} else {
tracing::debug!(
"running(pre): we don't have enough triples to generate a presignature"
);
}
}
presignature_manager
.stockpile(
active,
&self.public_key,
&self.private_share,
&mut triple_manager,
)
.await?;
drop(triple_manager);
for (p, msg) in presignature_manager.poke()? {
let info = self.fetch_participant(&p)?;
Expand Down
17 changes: 12 additions & 5 deletions node/src/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pub use state::NodeState;
use self::consensus::ConsensusCtx;
use self::cryptography::CryptographicCtx;
use self::message::MessageCtx;
use self::presignature::PresignatureConfig;
use self::triple::TripleConfig;
use crate::mesh::Mesh;
use crate::protocol::consensus::ConsensusProtocol;
Expand All @@ -41,6 +42,12 @@ use url::Url;

use mpc_keys::hpke;

#[derive(Copy, Clone, Debug)]
pub struct Config {
pub triple_cfg: TripleConfig,
pub presig_cfg: PresignatureConfig,
}

struct Ctx {
my_address: Url,
account_id: AccountId,
Expand All @@ -52,8 +59,8 @@ struct Ctx {
cipher_pk: hpke::PublicKey,
sign_sk: near_crypto::SecretKey,
secret_storage: SecretNodeStorageBox,
triple_cfg: TripleConfig,
triple_storage: LockTripleNodeStorageBox,
cfg: Config,
mesh: Mesh,
}

Expand Down Expand Up @@ -102,8 +109,8 @@ impl ConsensusCtx for &mut MpcSignProtocol {
&self.ctx.secret_storage
}

fn triple_cfg(&self) -> TripleConfig {
self.ctx.triple_cfg
fn cfg(&self) -> Config {
self.ctx.cfg
}

fn triple_storage(&mut self) -> LockTripleNodeStorageBox {
Expand Down Expand Up @@ -179,8 +186,8 @@ impl MpcSignProtocol {
sign_queue: Arc<RwLock<SignQueue>>,
cipher_pk: hpke::PublicKey,
secret_storage: SecretNodeStorageBox,
triple_cfg: TripleConfig,
triple_storage: LockTripleNodeStorageBox,
cfg: Config,
) -> (Self, Arc<RwLock<NodeState>>) {
let state = Arc::new(RwLock::new(NodeState::Starting));
let ctx = Ctx {
Expand All @@ -194,8 +201,8 @@ impl MpcSignProtocol {
sign_sk: signer.secret_key.clone(),
signer,
secret_storage,
triple_cfg,
triple_storage,
cfg,
mesh: Mesh::default(),
};
let protocol = MpcSignProtocol {
Expand Down
Loading

0 comments on commit d6673c5

Please sign in to comment.