From c2fcf309066cea1e4d7b31e3982a810d7944aa49 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 2 Oct 2024 19:48:29 +0300 Subject: [PATCH 01/64] basic redis setup in the same container --- Dockerfile.multichain | 14 ++++++++++++-- chain-signatures/node/redis.conf | 8 ++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 chain-signatures/node/redis.conf diff --git a/Dockerfile.multichain b/Dockerfile.multichain index 3d02c9d7c..c1807b923 100644 --- a/Dockerfile.multichain +++ b/Dockerfile.multichain @@ -19,9 +19,19 @@ RUN sed -i 's#target-dir = "../target"#target-dir = "target"#' .cargo/config.tom RUN cargo build --release --package mpc-node FROM debian:stable-slim as runtime -RUN apt-get update && apt-get install --assume-yes libssl-dev ca-certificates curl +RUN apt-get update && apt-get install --assume-yes libssl-dev ca-certificates curl redis-server + RUN update-ca-certificates COPY --from=builder /usr/src/app/target/release/mpc-node /usr/local/bin/mpc-node + +# Create a script to start both Redis and the Rust app +RUN echo "#!/bin/bash\nservice redis-server start\nexec mpc-node" > /start.sh \ + && chmod +x /start.sh + WORKDIR /usr/local/bin -ENTRYPOINT [ "mpc-node" ] \ No newline at end of file +# Expose Redis port (6379) and mpc node's port +EXPOSE 6379 8080 + +# Start Redis and the Rust application +ENTRYPOINT [ "/start.sh" ] \ No newline at end of file diff --git a/chain-signatures/node/redis.conf b/chain-signatures/node/redis.conf new file mode 100644 index 000000000..5d8e5492e --- /dev/null +++ b/chain-signatures/node/redis.conf @@ -0,0 +1,8 @@ +# Enable Append Only File (AOF) persistence +appendonly yes + +# Set the appendfsync policy to flush the AOF every second +appendfsync everysec + +# Set the directory for persistence +dir /data \ No newline at end of file From f552f24aa2fcf754980022b092ae822bb0fd608c Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 2 Oct 2024 19:50:51 +0300 Subject: [PATCH 02/64] formatting --- Dockerfile.multichain | 2 +- chain-signatures/node/redis.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile.multichain b/Dockerfile.multichain index c1807b923..c6588809e 100644 --- a/Dockerfile.multichain +++ b/Dockerfile.multichain @@ -34,4 +34,4 @@ WORKDIR /usr/local/bin EXPOSE 6379 8080 # Start Redis and the Rust application -ENTRYPOINT [ "/start.sh" ] \ No newline at end of file +ENTRYPOINT [ "/start.sh" ] diff --git a/chain-signatures/node/redis.conf b/chain-signatures/node/redis.conf index 5d8e5492e..85706cb01 100644 --- a/chain-signatures/node/redis.conf +++ b/chain-signatures/node/redis.conf @@ -5,4 +5,4 @@ appendonly yes appendfsync everysec # Set the directory for persistence -dir /data \ No newline at end of file +dir /data From 704ee5f591ad9da35a8d924421536d178f35e5fa Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 4 Oct 2024 21:39:03 +0300 Subject: [PATCH 03/64] basic presignature-storage using redis --- chain-signatures/Cargo.lock | 40 +++++++++++ chain-signatures/node/Cargo.toml | 1 + chain-signatures/node/src/cli.rs | 11 +++ chain-signatures/node/src/protocol/mod.rs | 4 ++ chain-signatures/node/src/storage/mod.rs | 1 + .../node/src/storage/presignature_storage.rs | 68 +++++++++++++++++++ integration-tests/chain-signatures/Cargo.lock | 48 +++++++++++-- .../chain-signatures/src/containers.rs | 1 + integration-tests/chain-signatures/src/lib.rs | 3 + .../chain-signatures/src/local.rs | 1 + 10 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 chain-signatures/node/src/storage/presignature_storage.rs diff --git a/chain-signatures/Cargo.lock b/chain-signatures/Cargo.lock index 05289ab95..a5febe29b 100644 --- a/chain-signatures/Cargo.lock +++ b/chain-signatures/Cargo.lock @@ -238,6 +238,12 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.7.4" @@ -1533,6 +1539,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "commoncrypto" version = "0.2.0" @@ -3827,6 +3843,7 @@ dependencies = [ "once_cell", "prometheus", "rand 0.8.5", + "redis", "reqwest 0.11.27", "semver", "serde", @@ -5890,6 +5907,23 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "redis" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e86f5670bd8b028edfb240f0616cad620705b31ec389d55e4f3da2c38dcd48" +dependencies = [ + "arc-swap", + "combine", + "itoa", + "num-bigint 0.4.6", + "percent-encoding 2.3.1", + "ryu", + "sha1_smol", + "socket2 0.5.7", + "url 2.5.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -6646,6 +6680,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.9.9" diff --git a/chain-signatures/node/Cargo.toml b/chain-signatures/node/Cargo.toml index f63fa69bf..16e8eba1f 100644 --- a/chain-signatures/node/Cargo.toml +++ b/chain-signatures/node/Cargo.toml @@ -60,3 +60,4 @@ itertools = "0.12.0" http = "1.1.0" prometheus = { version = "0.13.3" } once_cell = "1.13.1" +redis = "0.27.2" diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 02768ddf3..03745e04d 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -56,6 +56,9 @@ pub enum Cli { /// Storage options #[clap(flatten)] storage_options: storage::Options, + /// Redis URL + #[arg(long, env("MPC_REDIS_URL"))] + redis_url: Url, /// The set of configurations that we will use to override contract configurations. #[arg(long, env("MPC_OVERRIDE_CONFIG"), value_parser = clap::value_parser!(OverrideConfig))] override_config: Option, @@ -80,6 +83,7 @@ impl Cli { indexer_options, my_address, storage_options, + redis_url, override_config, client_header_referer, } => { @@ -99,6 +103,8 @@ impl Cli { cipher_pk, "--cipher-sk".to_string(), cipher_sk, + "--redis-url".to_string(), + redis_url.to_string(), ]; if let Some(sign_sk) = sign_sk { args.extend(["--sign-sk".to_string(), sign_sk.to_string()]); @@ -172,6 +178,7 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { indexer_options, my_address, storage_options, + redis_url, override_config, client_header_referer, } => { @@ -196,6 +203,9 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { storage::triple_storage::init(Some(&gcp_service), &account_id), )); + let redis_url: Url = Url::parse(redis_url.as_str())?; + let presignature_storage = storage::presignature_storage::init(redis_url); + let sign_sk = sign_sk.unwrap_or_else(|| account_sk.clone()); let my_address = my_address .map(|mut addr| { @@ -228,6 +238,7 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { sign_queue, key_storage, triple_storage, + presignature_storage, Config::new(LocalConfig { over: override_config.unwrap_or_else(Default::default), network: NetworkConfig { diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 3762c9400..421f3a239 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -27,6 +27,7 @@ use crate::protocol::consensus::ConsensusProtocol; use crate::protocol::cryptography::CryptographicProtocol; use crate::protocol::message::{MessageHandler, MpcMessageQueue}; use crate::rpc_client; +use crate::storage::presignature_storage::PresignatureStorageBox; use crate::storage::secret_storage::SecretNodeStorageBox; use crate::storage::triple_storage::LockTripleNodeStorageBox; @@ -50,6 +51,7 @@ struct Ctx { sign_queue: Arc>, secret_storage: SecretNodeStorageBox, triple_storage: LockTripleNodeStorageBox, + presignature_storage: PresignatureStorageBox, cfg: Config, mesh: Mesh, } @@ -164,6 +166,7 @@ impl MpcSignProtocol { sign_queue: Arc>, secret_storage: SecretNodeStorageBox, triple_storage: LockTripleNodeStorageBox, + presignature_storage: PresignatureStorageBox, cfg: Config, ) -> (Self, Arc>) { let my_address = my_address.into_url().unwrap(); @@ -189,6 +192,7 @@ impl MpcSignProtocol { signer, secret_storage, triple_storage, + presignature_storage, cfg, mesh: Mesh::default(), }; diff --git a/chain-signatures/node/src/storage/mod.rs b/chain-signatures/node/src/storage/mod.rs index 393356c03..03214ad62 100644 --- a/chain-signatures/node/src/storage/mod.rs +++ b/chain-signatures/node/src/storage/mod.rs @@ -1,3 +1,4 @@ +pub mod presignature_storage; pub mod secret_storage; pub mod triple_storage; diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs new file mode 100644 index 000000000..edeb017bc --- /dev/null +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -0,0 +1,68 @@ +use axum::async_trait; +use redis::Connection; +use url::Url; + +use crate::{ + gcp::error, + protocol::presignature::{Presignature, PresignatureId}, +}; + +// TODO: organize errors, get rid of connection with GCP +type PresignatureResult = std::result::Result; +pub type PresignatureStorageBox = Box; + +pub fn init(redis_url: Url) -> PresignatureStorageBox { + Box::new(RedisPresignatureStorage::new(redis_url)) as PresignatureStorageBox +} + +#[async_trait] +pub trait PresignatureStorage { + async fn insert(&mut self, presignature: Presignature) -> PresignatureResult<()>; + async fn insert_mine(&mut self, presignature: Presignature) -> PresignatureResult<()>; + async fn get(&self, id: PresignatureId) -> PresignatureResult>; + async fn get_mine(&self) -> PresignatureResult>; + async fn delete(&mut self, id: PresignatureId) -> PresignatureResult<()>; + async fn clear_all(&mut self) -> PresignatureResult>; +} + +struct RedisPresignatureStorage { + redis_connection: Connection, +} + +impl RedisPresignatureStorage { + fn new(redis_url: Url) -> Self { + Self { + redis_connection: redis::Client::open(redis_url.as_str()) + .expect("Failed to connect to Redis") + .get_connection() + .expect("Failed to get connection"), + } + } +} + +#[async_trait] +impl PresignatureStorage for RedisPresignatureStorage { + async fn insert(&mut self, presignature: Presignature) -> PresignatureResult<()> { + unimplemented!() + } + + async fn insert_mine(&mut self, presignature: Presignature) -> PresignatureResult<()> { + unimplemented!() + } + + async fn get(&self, id: PresignatureId) -> PresignatureResult> { + unimplemented!() + } + + async fn get_mine(&self) -> PresignatureResult> { + unimplemented!() + } + + async fn delete(&mut self, id: PresignatureId) -> PresignatureResult<()> { + unimplemented!() + } + + async fn clear_all(&mut self) -> PresignatureResult> { + unimplemented!() + } +} diff --git a/integration-tests/chain-signatures/Cargo.lock b/integration-tests/chain-signatures/Cargo.lock index 9d1f22678..684430ab0 100644 --- a/integration-tests/chain-signatures/Cargo.lock +++ b/integration-tests/chain-signatures/Cargo.lock @@ -238,6 +238,12 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.7.4" @@ -1605,6 +1611,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "commoncrypto" version = "0.2.0" @@ -4300,6 +4316,7 @@ dependencies = [ "once_cell", "prometheus", "rand 0.8.5", + "redis", "reqwest 0.11.27", "semver", "serde", @@ -5464,7 +5481,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint 0.4.5", + "num-bigint 0.4.6", "num-complex", "num-integer", "num-iter", @@ -5485,9 +5502,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -5547,7 +5564,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "num-bigint 0.4.5", + "num-bigint 0.4.6", "num-integer", "num-traits", ] @@ -6554,6 +6571,23 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "redis" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7e86f5670bd8b028edfb240f0616cad620705b31ec389d55e4f3da2c38dcd48" +dependencies = [ + "arc-swap", + "combine", + "itoa", + "num-bigint 0.4.6", + "percent-encoding 2.3.1", + "ryu", + "sha1_smol", + "socket2 0.5.7", + "url 2.5.1", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -7407,6 +7441,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.9.9" diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 02bf1f2c2..cd1647656 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -112,6 +112,7 @@ impl<'a> Node<'a> { indexer_options: indexer_options.clone(), my_address: None, storage_options: ctx.storage_options.clone(), + redis_url: ctx.redis_url.clone(), sign_sk: Some(config.sign_sk.clone()), override_config: Some(OverrideConfig::new(serde_json::to_value( config.cfg.protocol.clone(), diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index afc4d4059..557402dcb 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -22,6 +22,7 @@ use near_workspaces::network::{Sandbox, ValidatorKey}; use near_workspaces::{Account, AccountId, Contract, Worker}; use serde_json::json; use testcontainers::{Container, GenericImage}; +use url::Url; const NETWORK: &str = "mpc_it_network"; @@ -205,6 +206,7 @@ pub struct Context<'a> { pub mpc_contract: Contract, pub datastore: crate::containers::Datastore<'a>, pub storage_options: storage::Options, + pub redis_url: Url, } pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> { @@ -249,6 +251,7 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> mpc_contract, datastore, storage_options, + redis_url: Url::parse("redis://localhost")?, // TODO:pass real URL }) } diff --git a/integration-tests/chain-signatures/src/local.rs b/integration-tests/chain-signatures/src/local.rs index e9d26b2d3..8980d9407 100644 --- a/integration-tests/chain-signatures/src/local.rs +++ b/integration-tests/chain-signatures/src/local.rs @@ -93,6 +93,7 @@ impl Node { indexer_options, my_address: None, storage_options: ctx.storage_options.clone(), + redis_url: ctx.redis_url.clone(), override_config: Some(OverrideConfig::new(serde_json::to_value( config.cfg.protocol.clone(), )?)), From 3aa2ac303eab8d3b7aeca837f158113b5e5daa98 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 9 Oct 2024 13:38:26 +0300 Subject: [PATCH 04/64] presignature storage wrapped in arc and ewlock --- chain-signatures/node/src/cli.rs | 4 +- .../node/src/protocol/consensus.rs | 69 +++++++++++-------- chain-signatures/node/src/protocol/mod.rs | 10 ++- .../node/src/protocol/presignature.rs | 14 +++- .../node/src/storage/presignature_storage.rs | 9 +++ 5 files changed, 70 insertions(+), 36 deletions(-) diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 03745e04d..8c0fe7c50 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -1,6 +1,7 @@ use crate::config::{Config, LocalConfig, NetworkConfig, OverrideConfig}; use crate::gcp::GcpService; use crate::protocol::{MpcSignProtocol, SignQueue}; +use crate::storage::presignature_storage::LockPresignatureStorageBox; use crate::storage::triple_storage::LockTripleNodeStorageBox; use crate::{indexer, storage, web}; use clap::Parser; @@ -204,7 +205,8 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { )); let redis_url: Url = Url::parse(redis_url.as_str())?; - let presignature_storage = storage::presignature_storage::init(redis_url); + let presignature_storage: LockPresignatureStorageBox = + Arc::new(RwLock::new(storage::presignature_storage::init(redis_url))); let sign_sk = sign_sk.unwrap_or_else(|| account_sk.clone()); let my_address = my_address diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index 8b6065ea2..737c6909f 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -13,6 +13,7 @@ use crate::protocol::signature::SignatureManager; use crate::protocol::state::{GeneratingState, ResharingState}; use crate::protocol::triple::TripleManager; use crate::rpc_client; +use crate::storage::presignature_storage::LockPresignatureStorageBox; use crate::storage::secret_storage::SecretNodeStorageBox; use crate::storage::triple_storage::LockTripleNodeStorageBox; use crate::storage::triple_storage::TripleData; @@ -41,6 +42,7 @@ pub trait ConsensusCtx { fn sign_queue(&self) -> Arc>; fn secret_storage(&self) -> &SecretNodeStorageBox; fn triple_storage(&self) -> LockTripleNodeStorageBox; + fn presignature_storage(&self) -> LockPresignatureStorageBox; fn cfg(&self) -> &Config; } @@ -132,12 +134,6 @@ impl ConsensusProtocol for StartedState { tracing::info!( "started: contract state is running and we are already a participant" ); - let presignature_manager = PresignatureManager::new( - me, - contract_state.threshold, - epoch, - ctx.my_account_id(), - ); let triple_manager = Arc::new(RwLock::new(TripleManager::new( me, contract_state.threshold, @@ -146,6 +142,24 @@ impl ConsensusProtocol for StartedState { ctx.triple_storage(), ctx.my_account_id(), ))); + + let presignature_manager = + Arc::new(RwLock::new(PresignatureManager::new( + me, + contract_state.threshold, + epoch, + ctx.my_account_id(), + ctx.presignature_storage(), + ))); + + let signature_manager = + Arc::new(RwLock::new(SignatureManager::new( + me, + public_key, + epoch, + ctx.my_account_id(), + ))); + let stuck_monitor = Arc::new(RwLock::new( StuckMonitor::new(&triple_manager).await, )); @@ -159,17 +173,8 @@ impl ConsensusProtocol for StartedState { sign_queue, stuck_monitor, triple_manager, - presignature_manager: Arc::new(RwLock::new( - presignature_manager, - )), - signature_manager: Arc::new(RwLock::new( - SignatureManager::new( - me, - contract_state.public_key, - epoch, - ctx.my_account_id(), - ), - )), + presignature_manager, + signature_manager, messages: Default::default(), })) } @@ -370,6 +375,22 @@ impl ConsensusProtocol for WaitingForConsensusState { ctx.triple_storage(), ctx.my_account_id(), ))); + + let presignature_manager = Arc::new(RwLock::new(PresignatureManager::new( + me, + self.threshold, + self.epoch, + ctx.my_account_id(), + ctx.presignature_storage(), + ))); + + let signature_manager = Arc::new(RwLock::new(SignatureManager::new( + me, + self.public_key, + self.epoch, + ctx.my_account_id(), + ))); + let stuck_monitor = Arc::new(RwLock::new(StuckMonitor::new(&triple_manager).await)); @@ -382,18 +403,8 @@ impl ConsensusProtocol for WaitingForConsensusState { sign_queue: ctx.sign_queue(), stuck_monitor, triple_manager, - presignature_manager: Arc::new(RwLock::new(PresignatureManager::new( - me, - self.threshold, - self.epoch, - ctx.my_account_id(), - ))), - signature_manager: Arc::new(RwLock::new(SignatureManager::new( - me, - self.public_key, - self.epoch, - ctx.my_account_id(), - ))), + presignature_manager, + signature_manager, messages: self.messages, })) } diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 421f3a239..9c7c8d9fb 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -27,7 +27,7 @@ use crate::protocol::consensus::ConsensusProtocol; use crate::protocol::cryptography::CryptographicProtocol; use crate::protocol::message::{MessageHandler, MpcMessageQueue}; use crate::rpc_client; -use crate::storage::presignature_storage::PresignatureStorageBox; +use crate::storage::presignature_storage::LockPresignatureStorageBox; use crate::storage::secret_storage::SecretNodeStorageBox; use crate::storage::triple_storage::LockTripleNodeStorageBox; @@ -51,7 +51,7 @@ struct Ctx { sign_queue: Arc>, secret_storage: SecretNodeStorageBox, triple_storage: LockTripleNodeStorageBox, - presignature_storage: PresignatureStorageBox, + presignature_storage: LockPresignatureStorageBox, cfg: Config, mesh: Mesh, } @@ -96,6 +96,10 @@ impl ConsensusCtx for &mut MpcSignProtocol { fn triple_storage(&self) -> LockTripleNodeStorageBox { self.ctx.triple_storage.clone() } + + fn presignature_storage(&self) -> LockPresignatureStorageBox { + self.ctx.presignature_storage.clone() + } } #[async_trait::async_trait] @@ -166,7 +170,7 @@ impl MpcSignProtocol { sign_queue: Arc>, secret_storage: SecretNodeStorageBox, triple_storage: LockTripleNodeStorageBox, - presignature_storage: PresignatureStorageBox, + presignature_storage: LockPresignatureStorageBox, cfg: Config, ) -> (Self, Arc>) { let my_address = my_address.into_url().unwrap(); diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 0859d0228..941ec1898 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -1,6 +1,7 @@ use super::message::PresignatureMessage; use super::triple::{Triple, TripleId, TripleManager}; use crate::protocol::contract::primitives::Participants; +use crate::storage::presignature_storage::LockPresignatureStorageBox; use crate::types::{PresignatureProtocol, SecretKeyShare}; use crate::util::AffinePointExt; @@ -103,7 +104,7 @@ pub enum GenerationError { /// complete some time in the future and a way to take an already generated triple. pub struct PresignatureManager { /// Completed unspent presignatures. - presignatures: HashMap, + presignatures: LockPresignatureStorageBox, /// Ongoing presignature generation protocols. generators: HashMap, /// List of presignature ids generation of which was initiated by the current node. @@ -121,9 +122,16 @@ pub struct PresignatureManager { } impl PresignatureManager { - pub fn new(me: Participant, threshold: usize, epoch: u64, my_account_id: &AccountId) -> Self { + pub fn new( + me: Participant, + threshold: usize, + epoch: u64, + my_account_id: &AccountId, + presignature_storage: LockPresignatureStorageBox, + ) -> Self { Self { - presignatures: HashMap::new(), + //TODO: rename to presignature_storage + presignatures: presignature_storage, generators: HashMap::new(), mine: VecDeque::new(), introduced: HashSet::new(), diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index edeb017bc..f067e54aa 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -1,5 +1,8 @@ +use std::sync::Arc; + use axum::async_trait; use redis::Connection; +use tokio::sync::RwLock; use url::Url; use crate::{ @@ -10,6 +13,7 @@ use crate::{ // TODO: organize errors, get rid of connection with GCP type PresignatureResult = std::result::Result; pub type PresignatureStorageBox = Box; +pub type LockPresignatureStorageBox = Arc>; pub fn init(redis_url: Url) -> PresignatureStorageBox { Box::new(RedisPresignatureStorage::new(redis_url)) as PresignatureStorageBox @@ -19,6 +23,7 @@ pub fn init(redis_url: Url) -> PresignatureStorageBox { pub trait PresignatureStorage { async fn insert(&mut self, presignature: Presignature) -> PresignatureResult<()>; async fn insert_mine(&mut self, presignature: Presignature) -> PresignatureResult<()>; + async fn contrains(&self, id: PresignatureId) -> PresignatureResult; async fn get(&self, id: PresignatureId) -> PresignatureResult>; async fn get_mine(&self) -> PresignatureResult>; async fn delete(&mut self, id: PresignatureId) -> PresignatureResult<()>; @@ -50,6 +55,10 @@ impl PresignatureStorage for RedisPresignatureStorage { unimplemented!() } + async fn contrains(&self, id: PresignatureId) -> PresignatureResult { + unimplemented!() + } + async fn get(&self, id: PresignatureId) -> PresignatureResult> { unimplemented!() } From 2f0e5b1313c4d3963eff5f041f66a2c1efcb480e Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 10 Oct 2024 00:22:40 +0300 Subject: [PATCH 05/64] presignature storage redis functions implemented --- .../node/src/storage/presignature_storage.rs | 120 ++++++++++++++---- 1 file changed, 95 insertions(+), 25 deletions(-) diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index f067e54aa..c01cf29b0 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -1,33 +1,39 @@ use std::sync::Arc; +use anyhow::Ok; use axum::async_trait; -use redis::Connection; +use redis::{Commands, Connection, FromRedisValue, RedisWrite, ToRedisArgs}; use tokio::sync::RwLock; use url::Url; -use crate::{ - gcp::error, - protocol::presignature::{Presignature, PresignatureId}, -}; +use crate::protocol::presignature::{Presignature, PresignatureId}; // TODO: organize errors, get rid of connection with GCP -type PresignatureResult = std::result::Result; +type PresignatureResult = std::result::Result; pub type PresignatureStorageBox = Box; pub type LockPresignatureStorageBox = Arc>; +const FOREIGN_MAP_NAME: &'static str = "presignatures_foreign"; +const MINE_MAP_NAME: &'static str = "presignatures_mine"; + pub fn init(redis_url: Url) -> PresignatureStorageBox { Box::new(RedisPresignatureStorage::new(redis_url)) as PresignatureStorageBox } #[async_trait] pub trait PresignatureStorage { - async fn insert(&mut self, presignature: Presignature) -> PresignatureResult<()>; + async fn insert_foreign(&mut self, presignature: Presignature) -> PresignatureResult<()>; async fn insert_mine(&mut self, presignature: Presignature) -> PresignatureResult<()>; - async fn contrains(&self, id: PresignatureId) -> PresignatureResult; - async fn get(&self, id: PresignatureId) -> PresignatureResult>; - async fn get_mine(&self) -> PresignatureResult>; - async fn delete(&mut self, id: PresignatureId) -> PresignatureResult<()>; - async fn clear_all(&mut self) -> PresignatureResult>; + async fn contains_foreign(&mut self, id: PresignatureId) -> PresignatureResult; + async fn contains_mine(&mut self, id: PresignatureId) -> PresignatureResult; + async fn remove_foreign( + &mut self, + id: PresignatureId, + ) -> PresignatureResult>; + async fn remove_mine(&mut self, id: PresignatureId) + -> PresignatureResult>; + async fn count_all(&mut self) -> PresignatureResult; + async fn count_mine(&mut self) -> PresignatureResult; } struct RedisPresignatureStorage { @@ -43,35 +49,99 @@ impl RedisPresignatureStorage { .expect("Failed to get connection"), } } + + // This function is using a Lua script to read and remove + // a presignature in a single atomic operation + async fn remove_presignature( + &mut self, + hash_map_name: &str, + id: PresignatureId, + ) -> PresignatureResult> { + let script = redis::Script::new( + r" + local value = redis.call('HGET', KEYS[1], ARGV[1]) + redis.call('HDEL', KEYS[1], ARGV[1]) + return value + ", + ); + let presignature: Option = redis::pipe() + .invoke_script(script.key(hash_map_name).arg(id)) + .query(&mut self.redis_connection)?; + Ok(presignature) as redis::RedisResult + } } #[async_trait] impl PresignatureStorage for RedisPresignatureStorage { - async fn insert(&mut self, presignature: Presignature) -> PresignatureResult<()> { - unimplemented!() + async fn insert_foreign(&mut self, presignature: Presignature) -> PresignatureResult<()> { + self.redis_connection + .hset(FOREIGN_MAP_NAME, presignature.id, presignature)?; + Ok(()) } async fn insert_mine(&mut self, presignature: Presignature) -> PresignatureResult<()> { - unimplemented!() + self.redis_connection + .hset(MINE_MAP_NAME, presignature.id, presignature)?; + Ok(()) } - async fn contrains(&self, id: PresignatureId) -> PresignatureResult { - unimplemented!() + async fn contains_foreign(&mut self, id: PresignatureId) -> PresignatureResult { + let result: bool = self.redis_connection.hexists(FOREIGN_MAP_NAME, id)?; + Ok(result) } - async fn get(&self, id: PresignatureId) -> PresignatureResult> { - unimplemented!() + async fn contains_mine(&mut self, id: PresignatureId) -> PresignatureResult { + let result: bool = self.redis_connection.hexists(MINE_MAP_NAME, id)?; + Ok(result) } - async fn get_mine(&self) -> PresignatureResult> { - unimplemented!() + async fn remove_foreign( + &mut self, + id: PresignatureId, + ) -> PresignatureResult> { + let result: Option = self.remove_presignature(FOREIGN_MAP_NAME, id).await?; + Ok(result) } - async fn delete(&mut self, id: PresignatureId) -> PresignatureResult<()> { - unimplemented!() + async fn remove_mine( + &mut self, + id: PresignatureId, + ) -> PresignatureResult> { + let result: Option = self.remove_presignature(MINE_MAP_NAME, id).await?; + Ok(result) } - async fn clear_all(&mut self) -> PresignatureResult> { - unimplemented!() + async fn count_all(&mut self) -> PresignatureResult { + let count: usize = self.redis_connection.hlen(FOREIGN_MAP_NAME)?; + Ok(count) + } + + async fn count_mine(&mut self) -> PresignatureResult { + let count: usize = self.redis_connection.hlen(MINE_MAP_NAME)?; + Ok(count) + } +} + +impl ToRedisArgs for Presignature { + fn write_redis_args(&self, out: &mut W) + where + W: ?Sized + RedisWrite, + { + let json = serde_json::to_string(self).expect("Failed to serialize Presignature"); + out.write_arg(json.as_bytes()); + } +} + +impl FromRedisValue for Presignature { + fn from_redis_value(v: &redis::Value) -> redis::RedisResult { + let json = String::from_redis_value(v)?; + let presignature: Presignature = serde_json::from_str(&json).map_err(|e| { + redis::RedisError::from(( + redis::ErrorKind::TypeError, + "Failed to deserialize presignature", + e.to_string(), + )) + })?; + Ok(presignature) } } From 8539fc8e14e70db45aea6c43af1ff3f6b765448f Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 11 Oct 2024 18:06:01 +0300 Subject: [PATCH 06/64] redis presignature storage used in presignature manager --- .../node/src/protocol/cryptography.rs | 11 +- chain-signatures/node/src/protocol/message.rs | 27 ++- .../node/src/protocol/presignature.rs | 229 ++++++++++++------ .../node/src/protocol/signature.rs | 10 +- .../node/src/storage/presignature_storage.rs | 109 ++++----- chain-signatures/node/src/web/mod.rs | 6 +- 6 files changed, 233 insertions(+), 159 deletions(-) diff --git a/chain-signatures/node/src/protocol/cryptography.rs b/chain-signatures/node/src/protocol/cryptography.rs index 294a8242c..eeb6e782f 100644 --- a/chain-signatures/node/src/protocol/cryptography.rs +++ b/chain-signatures/node/src/protocol/cryptography.rs @@ -407,20 +407,23 @@ impl CryptographicProtocol for RunningState { tracing::warn!(?err, "running: failed to stockpile presignatures"); } drop(triple_manager); - for (p, msg) in presignature_manager.poke() { + for (p, msg) in presignature_manager.poke().await { let info = self.fetch_participant(&p)?; messages.push(info.clone(), MpcMessage::Presignature(msg)); } crate::metrics::NUM_PRESIGNATURES_MINE .with_label_values(&[my_account_id.as_str()]) - .set(presignature_manager.my_len() as i64); + .set(presignature_manager.count_mine().await as i64); crate::metrics::NUM_PRESIGNATURES_TOTAL .with_label_values(&[my_account_id.as_str()]) - .set(presignature_manager.len() as i64); + .set(presignature_manager.count_all().await as i64); crate::metrics::NUM_PRESIGNATURE_GENERATORS_TOTAL .with_label_values(&[my_account_id.as_str()]) - .set(presignature_manager.potential_len() as i64 - presignature_manager.len() as i64); + .set( + presignature_manager.potential_len().await as i64 + - presignature_manager.count_all().await as i64, + ); // NOTE: signatures should only use stable and not active participants. The difference here is that // stable participants utilizes more than the online status of a node, such as whether or not their diff --git a/chain-signatures/node/src/protocol/message.rs b/chain-signatures/node/src/protocol/message.rs index 77ba0b2cb..0ff9d0945 100644 --- a/chain-signatures/node/src/protocol/message.rs +++ b/chain-signatures/node/src/protocol/message.rs @@ -309,7 +309,7 @@ impl MessageHandler for RunningState { } let protocol = match presignature_manager - .get_or_generate( + .get_or_start_protocol( participants, *id, *triple0, @@ -412,17 +412,20 @@ impl MessageHandler for RunningState { // continue; // }; // TODO: Validate that the message matches our sign_queue - let protocol = match signature_manager.get_or_generate( - participants, - *receipt_id, - *proposer, - *presignature_id, - request, - *epsilon, - *entropy, - &mut presignature_manager, - protocol_cfg, - ) { + let protocol = match signature_manager + .get_or_start_protocol( + participants, + *receipt_id, + *proposer, + *presignature_id, + request, + *epsilon, + *entropy, + &mut presignature_manager, + protocol_cfg, + ) + .await + { Ok(protocol) => protocol, Err(GenerationError::PresignatureIsGenerating(_)) => { // We will revisit this this signature request later when the presignature has been generated. diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 941ec1898..3e2d3f652 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -13,7 +13,7 @@ use k256::Secp256k1; use mpc_contract::config::ProtocolConfig; use sha3::{Digest, Sha3_256}; use std::collections::hash_map::Entry; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashMap, HashSet}; use std::time::{Duration, Instant}; use near_account_id::AccountId; @@ -103,12 +103,9 @@ pub enum GenerationError { /// Abstracts how triples are generated by providing a way to request a new triple that will be /// complete some time in the future and a way to take an already generated triple. pub struct PresignatureManager { - /// Completed unspent presignatures. - presignatures: LockPresignatureStorageBox, + presignature_storage: LockPresignatureStorageBox, /// Ongoing presignature generation protocols. generators: HashMap, - /// List of presignature ids generation of which was initiated by the current node. - mine: VecDeque, /// The set of presignatures that were introduced to the system by the current node. introduced: HashSet, /// Garbage collection for presignatures that have either been taken or failed. This @@ -130,10 +127,8 @@ impl PresignatureManager { presignature_storage: LockPresignatureStorageBox, ) -> Self { Self { - //TODO: rename to presignature_storage - presignatures: presignature_storage, + presignature_storage, generators: HashMap::new(), - mine: VecDeque::new(), introduced: HashSet::new(), gc: HashMap::new(), me, @@ -143,25 +138,132 @@ impl PresignatureManager { } } + // TODO: add logs and better error handling in all functions + pub async fn insert(&mut self, presignature: Presignature) { + tracing::trace!(id = ?presignature.id, "inserting presignature"); + self.presignature_storage + .write() + .await + .insert(presignature) + .map_err(|e| { + tracing::error!(?e, "failed to insert presignature"); + }); + } + + pub async fn insert_mine(&mut self, presignature: Presignature) { + tracing::trace!(id = ?presignature.id, "inserting mine presignature"); + // Remove from taken list if it was there + self.gc.remove(&presignature.id); + self.presignature_storage + .write() + .await + .insert_mine(presignature) + .map_err(|e| { + tracing::error!(?e, "failed to insert mine presignature"); + }); + } + + /// Returns true if the presignature with the given id is already generated + pub async fn contains(&self, id: &PresignatureId) -> bool { + self.presignature_storage + .write() + .await + .contains(id) + .map_err(|e| { + tracing::error!(?e, "failed to check if presignature exist"); + }) + .unwrap_or(false) + } + + /// Returns true if the mine presignature with the given id is already generated + pub async fn contains_mine(&self, id: &PresignatureId) -> bool { + self.presignature_storage + .write() + .await + .contains_mine(id) + .map_err(|e| { + tracing::error!(?e, "failed to check if mine presignature exist"); + }) + .unwrap_or(false) + } + + pub async fn take(&mut self, id: PresignatureId) -> Result { + if let Some(presignature) = + self.presignature_storage + .write() + .await + .take(&id) + .map_err(|e| { + tracing::error!(?e, "failed to look for presignature"); + GenerationError::PresignatureIsMissing(id) + })? + { + self.gc.insert(id, Instant::now()); + tracing::trace!(id, "took presignature"); + return Ok(presignature); + }; + + if self.generators.contains_key(&id) { + tracing::warn!(id, "presignature is still generating"); + return Err(GenerationError::PresignatureIsGenerating(id)); + } + if self.gc.contains_key(&id) { + tracing::warn!(id, "presignature was garbage collected"); + return Err(GenerationError::PresignatureIsGarbageCollected(id)); + } + tracing::warn!(id, "presignature is missing"); + Err(GenerationError::PresignatureIsMissing(id)) + } + + pub async fn take_mine(&mut self) -> Option { + let presignature = self + .presignature_storage + .write() + .await + .take_mine() + .map_err(|e| { + tracing::error!(?e, "failed to look for mine presignature"); + }) + .ok()??; + tracing::debug!(id = ?presignature.id, "take presignature of mine"); + Some(presignature) + } + /// Returns the number of unspent presignatures available in the manager. - pub fn len(&self) -> usize { - self.presignatures.len() + pub async fn count_all(&self) -> usize { + self.presignature_storage + .write() + .await + .count_all() + .map_err(|e| { + tracing::error!(?e, "failed to count all presignatures"); + }) + .unwrap_or(0) } /// Returns the number of unspent presignatures assigned to this node. - pub fn my_len(&self) -> usize { - self.mine.len() + pub async fn count_mine(&self) -> usize { + self.presignature_storage + .write() + .await + .count_mine() + .map_err(|e| { + tracing::error!(?e, "failed to count mine presignatures"); + }) + .unwrap_or(0) } - /// Returns the number of unspent presignatures we will have in the manager once - /// all ongoing generation protocols complete. - pub fn potential_len(&self) -> usize { - self.presignatures.len() + self.generators.len() + /// Returns if there are unspent presignatures available in the manager. + pub async fn is_empty(&self) -> bool { + self.count_all().await == 0 } - /// Returns if there are unspent presignatures available in the manager. - pub fn is_empty(&self) -> bool { - self.len() == 0 + /// Returns the number of unspent presignatures we will have in the manager once + /// all ongoing generation protocols complete. + pub async fn potential_len(&self) -> usize { + let complete_presignatures = self.count_all().await; + let ongoing_generators = self.generators.len(); + complete_presignatures + ongoing_generators } pub fn garbage_collect(&mut self, cfg: &ProtocolConfig) { @@ -220,7 +322,7 @@ impl PresignatureManager { } /// Starts a new presignature generation protocol. - pub fn generate( + pub async fn generate( &mut self, participants: &Participants, triple0: Triple, @@ -233,7 +335,7 @@ impl PresignatureManager { // Check if the `id` is already in the system. Error out and have the next cycle try again. if self.generators.contains_key(&id) - || self.presignatures.contains_key(&id) + || self.contains(&id).await || self.gc.contains_key(&id) { tracing::warn!(id, "presignature id collision"); @@ -277,11 +379,11 @@ impl PresignatureManager { // Stopgap to prevent too many presignatures in the system. This should be around min_presig*nodes*2 // for good measure so that we have enough presignatures to do sig generation while also maintain // the minimum number of presignature where a single node can't flood the system. - if self.potential_len() >= cfg.presignature.max_presignatures as usize { + if self.potential_len().await >= cfg.presignature.max_presignatures as usize { false } else { // We will always try to generate a new triple if we have less than the minimum - self.my_len() < cfg.presignature.min_presignatures as usize + self.count_mine().await < cfg.presignature.min_presignatures as usize && self.introduced.len() < cfg.max_concurrent_introduction as usize } }; @@ -312,7 +414,8 @@ impl PresignatureManager { pk, sk_share, cfg.presignature.generation_timeout, - )?; + ) + .await?; } } else { tracing::debug!("running: we don't have enough triples to generate a presignature"); @@ -329,7 +432,7 @@ impl PresignatureManager { /// 4) Depends on triples (`triple0`/`triple1`) that are unknown to the node // TODO: What if the presignature completed generation and is already spent? #[allow(clippy::too_many_arguments)] - pub async fn get_or_generate( + pub async fn get_or_start_protocol( &mut self, participants: &Participants, id: PresignatureId, @@ -340,7 +443,17 @@ impl PresignatureManager { private_share: &SecretKeyShare, cfg: &ProtocolConfig, ) -> Result<&mut PresignatureProtocol, GenerationError> { - if self.presignatures.contains_key(&id) { + // TODO: why do we need to pass the id here? Double check. + let expected_id = hash_as_id(triple0, triple1); + if id != expected_id { + tracing::warn!( + id, + expected_id, + "presignature id does not match the hash of the triples" + ); + return Err(GenerationError::PresignatureIsMissing(id)); + } + if self.contains(&id).await { tracing::debug!(id, "presignature already generated"); Err(GenerationError::AlreadyGenerated) } else if self.gc.contains_key(&id) { @@ -411,48 +524,15 @@ impl PresignatureManager { } } - pub fn take_mine(&mut self) -> Option { - let my_presignature_id = self.mine.pop_front()?; - tracing::debug!(my_presignature_id, "take presignature of mine"); - // SAFETY: This unwrap is safe because taking mine will always succeed since it is only - // present when generation completes where the determination of ownership is made. - Some(self.take(my_presignature_id).unwrap()) - } - - pub fn take(&mut self, id: PresignatureId) -> Result { - if let Some(presignature) = self.presignatures.remove(&id) { - self.gc.insert(id, Instant::now()); - tracing::trace!(id, "took presignature"); - return Ok(presignature); - } - - if self.generators.contains_key(&id) { - tracing::warn!(id, "presignature is still generating"); - return Err(GenerationError::PresignatureIsGenerating(id)); - } - if self.gc.contains_key(&id) { - tracing::warn!(id, "presignature was garbage collected"); - return Err(GenerationError::PresignatureIsGarbageCollected(id)); - } - tracing::warn!(id, "presignature is missing"); - Err(GenerationError::PresignatureIsMissing(id)) - } - - pub fn insert_mine(&mut self, presig: Presignature) { - tracing::trace!(id = ?presig.id, "inserting presignature"); - // Remove from taken list if it was there - self.gc.remove(&presig.id); - self.mine.push_back(presig.id); - self.presignatures.insert(presig.id, presig); - } - /// Pokes all of the ongoing generation protocols and returns a vector of /// messages to be sent to the respective participant. /// /// An empty vector means we cannot progress until we receive a new message. - pub fn poke(&mut self) -> Vec<(Participant, PresignatureMessage)> { + pub async fn poke(&mut self) -> Vec<(Participant, PresignatureMessage)> { let mut messages = Vec::new(); let mut errors = Vec::new(); + let mut new_presignatures = Vec::new(); + let mut new_mine_presignatures = Vec::new(); self.generators.retain(|id, generator| { loop { let action = match generator.poke() { @@ -508,20 +588,19 @@ impl PresignatureManager { big_r = ?output.big_r.to_base58(), "completed presignature generation" ); - self.presignatures.insert( - *id, - Presignature { - id: *id, - output, - participants: generator.participants.clone(), - }, - ); + let presignature = Presignature { + id: *id, + output, + participants: generator.participants.clone(), + }; if generator.mine { tracing::info!(id, "assigning presignature to myself"); - self.mine.push_back(*id); + new_mine_presignatures.push(presignature); crate::metrics::NUM_TOTAL_HISTORICAL_PRESIGNATURE_GENERATORS_MINE_SUCCESS .with_label_values(&[self.my_account_id.as_str()]) .inc(); + } else { + new_presignatures.push(presignature); } self.introduced.remove(id); @@ -538,6 +617,14 @@ impl PresignatureManager { } }); + for presignature in new_presignatures { + self.insert(presignature).await; + } + + for presignature in new_mine_presignatures { + self.insert_mine(presignature).await; + } + if !errors.is_empty() { tracing::warn!(?errors, "failed to generate some presignatures"); } diff --git a/chain-signatures/node/src/protocol/signature.rs b/chain-signatures/node/src/protocol/signature.rs index 19d2e4f7e..5337e7392 100644 --- a/chain-signatures/node/src/protocol/signature.rs +++ b/chain-signatures/node/src/protocol/signature.rs @@ -428,7 +428,7 @@ impl SignatureManager { /// 4) Depends on triples (`triple0`/`triple1`) that are unknown to the node // TODO: What if the presignature completed generation and is already spent? #[allow(clippy::too_many_arguments)] - pub fn get_or_generate( + pub async fn get_or_start_protocol( &mut self, participants: &Participants, receipt_id: ReceiptId, @@ -447,7 +447,7 @@ impl SignatureManager { match self.generators.entry(receipt_id) { Entry::Vacant(entry) => { tracing::info!(%receipt_id, me = ?self.me, presignature_id, "joining protocol to generate a new signature"); - let presignature = match presignature_manager.take(presignature_id) { + let presignature = match presignature_manager.take(presignature_id).await { Ok(presignature) => presignature, Err(err @ GenerationError::PresignatureIsGenerating(_)) => { tracing::warn!(me = ?self.me, presignature_id, "presignature is generating, can't join signature generation protocol"); @@ -604,7 +604,7 @@ impl SignatureManager { messages } - pub fn handle_requests( + pub async fn handle_requests( &mut self, threshold: usize, stable: &Participants, @@ -626,7 +626,7 @@ impl SignatureManager { if self.failed.is_empty() && my_requests.is_empty() { None } else { - presignature_manager.take_mine() + presignature_manager.take_mine().await } } { let sig_participants = stable.intersection(&[&presignature.participants]); @@ -659,7 +659,7 @@ impl SignatureManager { continue; } - if let Some(another_presignature) = presignature_manager.take_mine() { + if let Some(another_presignature) = presignature_manager.take_mine().await { presignature = another_presignature; } else { break; diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index c01cf29b0..ef5c30470 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -8,13 +8,12 @@ use url::Url; use crate::protocol::presignature::{Presignature, PresignatureId}; -// TODO: organize errors, get rid of connection with GCP -type PresignatureResult = std::result::Result; +type PresigResult = std::result::Result; pub type PresignatureStorageBox = Box; pub type LockPresignatureStorageBox = Arc>; -const FOREIGN_MAP_NAME: &'static str = "presignatures_foreign"; -const MINE_MAP_NAME: &'static str = "presignatures_mine"; +const PRESIGNATURES_MAP_NAME: &'static str = "presignatures"; +const MINE_SET_NAME: &'static str = "presignatures_mine"; pub fn init(redis_url: Url) -> PresignatureStorageBox { Box::new(RedisPresignatureStorage::new(redis_url)) as PresignatureStorageBox @@ -22,18 +21,14 @@ pub fn init(redis_url: Url) -> PresignatureStorageBox { #[async_trait] pub trait PresignatureStorage { - async fn insert_foreign(&mut self, presignature: Presignature) -> PresignatureResult<()>; - async fn insert_mine(&mut self, presignature: Presignature) -> PresignatureResult<()>; - async fn contains_foreign(&mut self, id: PresignatureId) -> PresignatureResult; - async fn contains_mine(&mut self, id: PresignatureId) -> PresignatureResult; - async fn remove_foreign( - &mut self, - id: PresignatureId, - ) -> PresignatureResult>; - async fn remove_mine(&mut self, id: PresignatureId) - -> PresignatureResult>; - async fn count_all(&mut self) -> PresignatureResult; - async fn count_mine(&mut self) -> PresignatureResult; + fn insert(&mut self, presignature: Presignature) -> PresigResult<()>; + fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()>; + fn contains(&mut self, id: &PresignatureId) -> PresigResult; + fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult; + fn take(&mut self, id: &PresignatureId) -> PresigResult>; + fn take_mine(&mut self) -> PresigResult>; + fn count_all(&mut self) -> PresigResult; + fn count_mine(&mut self) -> PresigResult; } struct RedisPresignatureStorage { @@ -46,79 +41,65 @@ impl RedisPresignatureStorage { redis_connection: redis::Client::open(redis_url.as_str()) .expect("Failed to connect to Redis") .get_connection() - .expect("Failed to get connection"), + .expect("Failed to get Redis connection"), } } - - // This function is using a Lua script to read and remove - // a presignature in a single atomic operation - async fn remove_presignature( - &mut self, - hash_map_name: &str, - id: PresignatureId, - ) -> PresignatureResult> { - let script = redis::Script::new( - r" - local value = redis.call('HGET', KEYS[1], ARGV[1]) - redis.call('HDEL', KEYS[1], ARGV[1]) - return value - ", - ); - let presignature: Option = redis::pipe() - .invoke_script(script.key(hash_map_name).arg(id)) - .query(&mut self.redis_connection)?; - Ok(presignature) as redis::RedisResult - } } +// Note: it is possible to use a Lua script to make all operations atomic +// TODO: add logs and better error handling #[async_trait] impl PresignatureStorage for RedisPresignatureStorage { - async fn insert_foreign(&mut self, presignature: Presignature) -> PresignatureResult<()> { + fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { self.redis_connection - .hset(FOREIGN_MAP_NAME, presignature.id, presignature)?; + .hset(PRESIGNATURES_MAP_NAME, presignature.id, presignature)?; Ok(()) } - async fn insert_mine(&mut self, presignature: Presignature) -> PresignatureResult<()> { - self.redis_connection - .hset(MINE_MAP_NAME, presignature.id, presignature)?; + fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()> { + self.redis_connection.sadd(MINE_SET_NAME, presignature.id)?; + self.insert(presignature)?; Ok(()) } - async fn contains_foreign(&mut self, id: PresignatureId) -> PresignatureResult { - let result: bool = self.redis_connection.hexists(FOREIGN_MAP_NAME, id)?; + fn contains(&mut self, id: &PresignatureId) -> PresigResult { + let result: bool = self.redis_connection.hexists(PRESIGNATURES_MAP_NAME, id)?; Ok(result) } - async fn contains_mine(&mut self, id: PresignatureId) -> PresignatureResult { - let result: bool = self.redis_connection.hexists(MINE_MAP_NAME, id)?; + fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult { + let result: bool = self.redis_connection.sismember(MINE_SET_NAME, id)?; Ok(result) } - async fn remove_foreign( - &mut self, - id: PresignatureId, - ) -> PresignatureResult> { - let result: Option = self.remove_presignature(FOREIGN_MAP_NAME, id).await?; - Ok(result) + fn take(&mut self, id: &PresignatureId) -> PresigResult> { + let result: Option = + self.redis_connection.hget(PRESIGNATURES_MAP_NAME, id)?; + match result { + Some(presignature) => { + self.redis_connection.hdel(PRESIGNATURES_MAP_NAME, id)?; + Ok(Some(presignature)) + } + None => Ok(None), + } } - async fn remove_mine( - &mut self, - id: PresignatureId, - ) -> PresignatureResult> { - let result: Option = self.remove_presignature(MINE_MAP_NAME, id).await?; - Ok(result) + fn take_mine(&mut self) -> PresigResult> { + let id: Option = self.redis_connection.spop(MINE_SET_NAME)?; + match id { + Some(id) => self.take(&id), + None => Ok(None), + } } - async fn count_all(&mut self) -> PresignatureResult { - let count: usize = self.redis_connection.hlen(FOREIGN_MAP_NAME)?; - Ok(count) + fn count_all(&mut self) -> PresigResult { + let result: usize = self.redis_connection.hlen(PRESIGNATURES_MAP_NAME)?; + Ok(result) } - async fn count_mine(&mut self) -> PresignatureResult { - let count: usize = self.redis_connection.hlen(MINE_MAP_NAME)?; - Ok(count) + fn count_mine(&mut self) -> PresigResult { + let result: usize = self.redis_connection.scard(MINE_SET_NAME)?; + Ok(result) } } diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index c38e2b4c6..2763b1840 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -141,9 +141,9 @@ async fn state(Extension(state): Extension>) -> Result Date: Fri, 11 Oct 2024 21:14:43 +0300 Subject: [PATCH 07/64] serialization for presignature --- .../node/src/protocol/presignature.rs | 106 ++++++++++++++++++ .../node/src/storage/presignature_storage.rs | 19 ++-- 2 files changed, 118 insertions(+), 7 deletions(-) diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 2f9987997..a271b0a43 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -11,6 +11,8 @@ use chrono::Utc; use crypto_shared::PublicKey; use k256::Secp256k1; use mpc_contract::config::ProtocolConfig; +use serde::ser::SerializeStruct; +use serde::{Deserialize, Serialize}; use sha3::{Digest, Sha3_256}; use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet}; @@ -30,6 +32,73 @@ pub struct Presignature { pub participants: Vec, } +impl Serialize for Presignature { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut state = serializer.serialize_struct("Presignature", 3)?; + state.serialize_field("id", &self.id)?; + + let mut output_map = serde_json::Map::new(); + output_map.insert( + "big_r".to_string(), + serde_json::to_value(&self.output.big_r).map_err(serde::ser::Error::custom)?, + ); + output_map.insert( + "k".to_string(), + serde_json::to_value(&self.output.k).map_err(serde::ser::Error::custom)?, + ); + output_map.insert( + "sigma".to_string(), + serde_json::to_value(&self.output.sigma).map_err(serde::ser::Error::custom)?, + ); + + state.serialize_field("output", &output_map)?; + state.serialize_field("participants", &self.participants)?; + state.end() + } +} + +impl<'de> Deserialize<'de> for Presignature { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + struct PresignatureFields { + id: PresignatureId, + output: serde_json::Value, + participants: Vec, + } + + let fields = PresignatureFields::deserialize(deserializer)?; + + let big_r = fields + .output + .get("big_r") + .ok_or_else(|| serde::de::Error::missing_field("big_r"))?; + let k = fields + .output + .get("k") + .ok_or_else(|| serde::de::Error::missing_field("k"))?; + let sigma = fields + .output + .get("sigma") + .ok_or_else(|| serde::de::Error::missing_field("sigma"))?; + + Ok(Self { + id: fields.id, + output: PresignOutput { + big_r: serde_json::from_value(big_r.clone()).map_err(serde::de::Error::custom)?, + k: serde_json::from_value(k.clone()).map_err(serde::de::Error::custom)?, + sigma: serde_json::from_value(sigma.clone()).map_err(serde::de::Error::custom)?, + }, + participants: fields.participants, + }) + } +} + /// An ongoing presignature generator. pub struct PresignatureGenerator { pub participants: Vec, @@ -652,3 +721,40 @@ const fn first_8_bytes(input: [u8; 32]) -> [u8; 8] { } output } + +// test presignature serialization and deserialization +#[cfg(test)] +mod tests { + use cait_sith::{protocol::Participant, PresignOutput}; + use k256::{elliptic_curve::CurveArithmetic, Secp256k1}; + + use crate::protocol::presignature::Presignature; + + #[tokio::test] + async fn test_presignature_serialize_deserialize() { + let presignature = Presignature { + id: 1, + output: PresignOutput { + big_r: ::AffinePoint::default(), + k: ::Scalar::ZERO, + sigma: ::Scalar::ONE, + }, + participants: vec![Participant::from(1), Participant::from(2)], + }; + + // Serialize Presignature to JSON + let serialized = + serde_json::to_string(&presignature).expect("Failed to serialize Presignature"); + + // Deserialize JSON back to Presignature + let deserialized: Presignature = + serde_json::from_str(&serialized).expect("Failed to deserialize Presignature"); + + // Assert that the original and deserialized Presignature are equal + assert_eq!(presignature.id, deserialized.id); + assert_eq!(presignature.output.big_r, deserialized.output.big_r); + assert_eq!(presignature.output.k, deserialized.output.k); + assert_eq!(presignature.output.sigma, deserialized.output.sigma); + assert_eq!(presignature.participants, deserialized.participants); + } +} diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index ef5c30470..822cfe814 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -108,21 +108,26 @@ impl ToRedisArgs for Presignature { where W: ?Sized + RedisWrite, { - let json = serde_json::to_string(self).expect("Failed to serialize Presignature"); - out.write_arg(json.as_bytes()); + match serde_json::to_string(self) { + std::result::Result::Ok(json) => out.write_arg(json.as_bytes()), + Err(e) => { + tracing::error!("Failed to serialize Presignature: {}", e); + out.write_arg("failed_to_serialize".as_bytes()) + } + } } } impl FromRedisValue for Presignature { fn from_redis_value(v: &redis::Value) -> redis::RedisResult { - let json = String::from_redis_value(v)?; - let presignature: Presignature = serde_json::from_str(&json).map_err(|e| { + let json: String = String::from_redis_value(v)?; + + serde_json::from_str(&json).map_err(|e| { redis::RedisError::from(( redis::ErrorKind::TypeError, - "Failed to deserialize presignature", + "Failed to deserialize Presignature", e.to_string(), )) - })?; - Ok(presignature) + }) } } From 0102d1f22fce5ffcce0064d39b4298170c4de97d Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 15 Oct 2024 12:41:48 +0300 Subject: [PATCH 08/64] warnings fixed --- .../node/src/protocol/cryptography.rs | 16 +++++---- .../node/src/protocol/presignature.rs | 35 +++++++++---------- .../node/src/protocol/signature.rs | 4 +-- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/chain-signatures/node/src/protocol/cryptography.rs b/chain-signatures/node/src/protocol/cryptography.rs index 35ea9f19e..ace7a9802 100644 --- a/chain-signatures/node/src/protocol/cryptography.rs +++ b/chain-signatures/node/src/protocol/cryptography.rs @@ -445,13 +445,15 @@ impl CryptographicProtocol for RunningState { .set(my_requests.len() as i64); let mut signature_manager = self.signature_manager.write().await; - signature_manager.handle_requests( - self.threshold, - &stable, - my_requests, - &mut presignature_manager, - protocol_cfg, - ); + signature_manager + .handle_requests( + self.threshold, + &stable, + my_requests, + &mut presignature_manager, + protocol_cfg, + ) + .await; drop(sign_queue); drop(presignature_manager); diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index a271b0a43..0f3493e59 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -207,29 +207,25 @@ impl PresignatureManager { } } - // TODO: add logs and better error handling in all functions pub async fn insert(&mut self, presignature: Presignature) { tracing::info!(id = ?presignature.id, "inserting presignature"); - self.presignature_storage - .write() - .await - .insert(presignature) - .map_err(|e| { - tracing::error!(?e, "failed to insert presignature"); - }); + if let Err(e) = self.presignature_storage.write().await.insert(presignature) { + tracing::error!(?e, "failed to insert presignature"); + } } pub async fn insert_mine(&mut self, presignature: Presignature) { tracing::info!(id = ?presignature.id, "inserting mine presignature"); // Remove from taken list if it was there self.gc.remove(&presignature.id); - self.presignature_storage + if let Err(e) = self + .presignature_storage .write() .await .insert_mine(presignature) - .map_err(|e| { - tracing::error!(?e, "failed to insert mine presignature"); - }); + { + tracing::error!(?e, "failed to insert mine presignature"); + } } /// Returns true if the presignature with the given id is already generated @@ -239,7 +235,7 @@ impl PresignatureManager { .await .contains(id) .map_err(|e| { - tracing::error!(?e, "failed to check if presignature exist"); + tracing::warn!(?e, "failed to check if presignature exist"); }) .unwrap_or(false) } @@ -251,7 +247,7 @@ impl PresignatureManager { .await .contains_mine(id) .map_err(|e| { - tracing::error!(?e, "failed to check if mine presignature exist"); + tracing::warn!(?e, "failed to check if mine presignature exist"); }) .unwrap_or(false) } @@ -285,7 +281,7 @@ impl PresignatureManager { } pub async fn take_mine(&mut self) -> Option { - let presignature = self + if let Some(presignature) = self .presignature_storage .write() .await @@ -293,9 +289,12 @@ impl PresignatureManager { .map_err(|e| { tracing::error!(?e, "failed to look for mine presignature"); }) - .ok()??; - tracing::info!(id = ?presignature.id, "take presignature of mine"); - Some(presignature) + .ok()? + { + tracing::info!(id = ?presignature.id, "took presignature of mine"); + return Some(presignature); + } + None } /// Returns the number of unspent presignatures available in the manager. diff --git a/chain-signatures/node/src/protocol/signature.rs b/chain-signatures/node/src/protocol/signature.rs index c1c98f7f9..8b42e54be 100644 --- a/chain-signatures/node/src/protocol/signature.rs +++ b/chain-signatures/node/src/protocol/signature.rs @@ -481,7 +481,7 @@ impl SignatureManager { ) { Ok(generator) => generator, Err((presignature, err @ InitializationError::BadParameters(_))) => { - presignature_manager.insert_mine(presignature); + presignature_manager.insert_mine(presignature).await; tracing::warn!(%receipt_id, presignature_id, ?err, "failed to start signature generation"); return Err(GenerationError::CaitSithInitializationError(err)); } @@ -689,7 +689,7 @@ impl SignatureManager { // add back the failed presignatures that were incompatible to be made into // signatures due to failures or lack of participants. for presignature in failed_presigs { - presignature_manager.insert_mine(presignature); + presignature_manager.insert_mine(presignature).await; } } From 3d5796b68f6709208cddeaea7e9b1a82e623d6c2 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 15 Oct 2024 13:08:42 +0300 Subject: [PATCH 09/64] presignature bad parameters error check --- .../node/src/protocol/presignature.rs | 17 ++++++----------- .../node/src/storage/presignature_storage.rs | 2 -- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 0f3493e59..6b741d6fc 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -167,6 +167,8 @@ pub enum GenerationError { PresignatureIsMissing(PresignatureId), #[error("presignature {0} is in garbage collection")] PresignatureIsGarbageCollected(TripleId), + #[error("presignature bad parameters")] + PresignatureBadParameters, } /// Abstracts how triples are generated by providing a way to request a new triple that will be @@ -511,17 +513,10 @@ impl PresignatureManager { private_share: &SecretKeyShare, cfg: &ProtocolConfig, ) -> Result<&mut PresignatureProtocol, GenerationError> { - // TODO: why do we need to pass the id here? Double check. - let expected_id = hash_as_id(triple0, triple1); - if id != expected_id { - tracing::warn!( - id, - expected_id, - "presignature id does not match the hash of the triples" - ); - return Err(GenerationError::PresignatureIsMissing(id)); - } - if self.contains(&id).await { + if id != hash_as_id(triple0, triple1) { + tracing::error!(id, "presignature id does not match the expected hash"); + return Err(GenerationError::PresignatureBadParameters); + } else if self.contains(&id).await { tracing::debug!(id, "presignature already generated"); Err(GenerationError::AlreadyGenerated) } else if self.gc.contains_key(&id) { diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index 822cfe814..dbafa1e79 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -46,8 +46,6 @@ impl RedisPresignatureStorage { } } -// Note: it is possible to use a Lua script to make all operations atomic -// TODO: add logs and better error handling #[async_trait] impl PresignatureStorage for RedisPresignatureStorage { fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { From 91d25dd54014a77aeb8814c50bc5b7c2a53dfb42 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 15 Oct 2024 15:34:02 +0300 Subject: [PATCH 10/64] min refactoring --- chain-signatures/node/src/protocol/cryptography.rs | 2 +- chain-signatures/node/src/protocol/presignature.rs | 13 ++++++------- .../node/src/storage/presignature_storage.rs | 5 ++--- chain-signatures/node/src/web/mod.rs | 2 +- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/chain-signatures/node/src/protocol/cryptography.rs b/chain-signatures/node/src/protocol/cryptography.rs index ace7a9802..8f67670d6 100644 --- a/chain-signatures/node/src/protocol/cryptography.rs +++ b/chain-signatures/node/src/protocol/cryptography.rs @@ -421,7 +421,7 @@ impl CryptographicProtocol for RunningState { crate::metrics::NUM_PRESIGNATURE_GENERATORS_TOTAL .with_label_values(&[my_account_id.as_str()]) .set( - presignature_manager.potential_len().await as i64 + presignature_manager.count_potential().await as i64 - presignature_manager.count_all().await as i64, ); diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 6b741d6fc..faa459c2d 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -43,15 +43,15 @@ impl Serialize for Presignature { let mut output_map = serde_json::Map::new(); output_map.insert( "big_r".to_string(), - serde_json::to_value(&self.output.big_r).map_err(serde::ser::Error::custom)?, + serde_json::to_value(self.output.big_r).map_err(serde::ser::Error::custom)?, ); output_map.insert( "k".to_string(), - serde_json::to_value(&self.output.k).map_err(serde::ser::Error::custom)?, + serde_json::to_value(self.output.k).map_err(serde::ser::Error::custom)?, ); output_map.insert( "sigma".to_string(), - serde_json::to_value(&self.output.sigma).map_err(serde::ser::Error::custom)?, + serde_json::to_value(self.output.sigma).map_err(serde::ser::Error::custom)?, ); state.serialize_field("output", &output_map)?; @@ -330,7 +330,7 @@ impl PresignatureManager { /// Returns the number of unspent presignatures we will have in the manager once /// all ongoing generation protocols complete. - pub async fn potential_len(&self) -> usize { + pub async fn count_potential(&self) -> usize { let complete_presignatures = self.count_all().await; let ongoing_generators = self.generators.len(); complete_presignatures + ongoing_generators @@ -449,7 +449,7 @@ impl PresignatureManager { // Stopgap to prevent too many presignatures in the system. This should be around min_presig*nodes*2 // for good measure so that we have enough presignatures to do sig generation while also maintain // the minimum number of presignature where a single node can't flood the system. - if self.potential_len().await >= cfg.presignature.max_presignatures as usize { + if self.count_potential().await >= cfg.presignature.max_presignatures as usize { false } else { // We will always try to generate a new triple if we have less than the minimum @@ -515,7 +515,7 @@ impl PresignatureManager { ) -> Result<&mut PresignatureProtocol, GenerationError> { if id != hash_as_id(triple0, triple1) { tracing::error!(id, "presignature id does not match the expected hash"); - return Err(GenerationError::PresignatureBadParameters); + Err(GenerationError::PresignatureBadParameters) } else if self.contains(&id).await { tracing::debug!(id, "presignature already generated"); Err(GenerationError::AlreadyGenerated) @@ -716,7 +716,6 @@ const fn first_8_bytes(input: [u8; 32]) -> [u8; 8] { output } -// test presignature serialization and deserialization #[cfg(test)] mod tests { use cait_sith::{protocol::Participant, PresignOutput}; diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index dbafa1e79..fe418e016 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -12,14 +12,13 @@ type PresigResult = std::result::Result; pub type PresignatureStorageBox = Box; pub type LockPresignatureStorageBox = Arc>; -const PRESIGNATURES_MAP_NAME: &'static str = "presignatures"; -const MINE_SET_NAME: &'static str = "presignatures_mine"; +const PRESIGNATURES_MAP_NAME: &str = "presignatures"; +const MINE_SET_NAME: &str = "presignatures_mine"; pub fn init(redis_url: Url) -> PresignatureStorageBox { Box::new(RedisPresignatureStorage::new(redis_url)) as PresignatureStorageBox } -#[async_trait] pub trait PresignatureStorage { fn insert(&mut self, presignature: Presignature) -> PresigResult<()>; fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()>; diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index 4456f27a8..c1128686d 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -143,7 +143,7 @@ async fn state(Extension(state): Extension>) -> Result Date: Tue, 15 Oct 2024 12:30:48 -0600 Subject: [PATCH 11/64] added redis config file path to dockerfile, added tf to mount /data volume --- Dockerfile.multichain | 2 +- infra/multichain-dev/main.tf | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Dockerfile.multichain b/Dockerfile.multichain index c6588809e..396760bb9 100644 --- a/Dockerfile.multichain +++ b/Dockerfile.multichain @@ -25,7 +25,7 @@ RUN update-ca-certificates COPY --from=builder /usr/src/app/target/release/mpc-node /usr/local/bin/mpc-node # Create a script to start both Redis and the Rust app -RUN echo "#!/bin/bash\nservice redis-server start\nexec mpc-node" > /start.sh \ +RUN echo "#!/bin/bash\nservice redis-server start ./redis.conf\nexec mpc-node" > /start.sh \ && chmod +x /start.sh WORKDIR /usr/local/bin diff --git a/infra/multichain-dev/main.tf b/infra/multichain-dev/main.tf index b864fa427..1655d378a 100644 --- a/infra/multichain-dev/main.tf +++ b/infra/multichain-dev/main.tf @@ -14,6 +14,14 @@ module "gce-container" { args = ["start"] port = "3000" + volumeMounts = [ + { + mountPath = "/data" + name = "host-path" + readOnly = false + } + ] + env = concat(var.static_env, [ { name = "MPC_NODE_ID" @@ -61,6 +69,15 @@ module "gce-container" { } ]) } + + volumes = [ + { + name = "host-path" + hostPath = { + path = "/etc/redis" + } + } + ] } resource "google_compute_address" "internal_ips" { From 9d28c3da4968af83832c503a748eb3c673533484 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 16 Oct 2024 00:46:15 +0300 Subject: [PATCH 12/64] it fix --- chain-signatures/node/src/cli.rs | 9 ++------- chain-signatures/node/src/storage/mod.rs | 2 ++ chain-signatures/node/src/test_utils.rs | 1 + integration-tests/chain-signatures/src/containers.rs | 1 - integration-tests/chain-signatures/src/lib.rs | 4 +--- integration-tests/chain-signatures/src/local.rs | 1 - 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index ff3389bb2..836636f09 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -58,9 +58,6 @@ pub enum Cli { /// Storage options #[clap(flatten)] storage_options: storage::Options, - /// Redis URL - #[arg(long, env("MPC_REDIS_URL"))] - redis_url: Url, /// The set of configurations that we will use to override contract configurations. #[arg(long, env("MPC_OVERRIDE_CONFIG"), value_parser = clap::value_parser!(OverrideConfig))] override_config: Option, @@ -85,7 +82,6 @@ impl Cli { indexer_options, my_address, storage_options, - redis_url, override_config, client_header_referer, } => { @@ -106,7 +102,7 @@ impl Cli { "--cipher-sk".to_string(), cipher_sk, "--redis-url".to_string(), - redis_url.to_string(), + storage_options.redis_url.to_string(), ]; if let Some(sign_sk) = sign_sk { args.extend(["--sign-sk".to_string(), sign_sk.to_string()]); @@ -181,7 +177,6 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { indexer_options, my_address, storage_options, - redis_url, override_config, client_header_referer, } => { @@ -206,7 +201,7 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { storage::triple_storage::init(Some(&gcp_service), &account_id), )); - let redis_url: Url = Url::parse(redis_url.as_str())?; + let redis_url: Url = Url::parse(storage_options.redis_url.as_str())?; let presignature_storage: LockPresignatureStorageBox = Arc::new(RwLock::new(storage::presignature_storage::init(redis_url))); diff --git a/chain-signatures/node/src/storage/mod.rs b/chain-signatures/node/src/storage/mod.rs index 03214ad62..550fe2378 100644 --- a/chain-signatures/node/src/storage/mod.rs +++ b/chain-signatures/node/src/storage/mod.rs @@ -21,6 +21,8 @@ pub struct Options { pub gcp_datastore_url: Option, #[arg(long, env("MPC_SK_SHARE_LOCAL_PATH"))] pub sk_share_local_path: Option, + #[arg(long, env("MPC_REDIS_URL"))] + pub redis_url: String, } impl Options { diff --git a/chain-signatures/node/src/test_utils.rs b/chain-signatures/node/src/test_utils.rs index 4771441e9..5af109fdf 100644 --- a/chain-signatures/node/src/test_utils.rs +++ b/chain-signatures/node/src/test_utils.rs @@ -41,6 +41,7 @@ impl TestTripleManagers { gcp_datastore_url: Some(url.clone()), env: "triple-test".to_string(), sk_share_local_path: None, + redis_url: "redis://localhost".to_string(), // not used }; Some( GcpService::init(&account_id, &storage_options) diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 2e6342ed1..97eec7fd7 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -112,7 +112,6 @@ impl<'a> Node<'a> { indexer_options: indexer_options.clone(), my_address: None, storage_options: ctx.storage_options.clone(), - redis_url: ctx.redis_url.clone(), sign_sk: Some(config.sign_sk.clone()), override_config: Some(OverrideConfig::new(serde_json::to_value( config.cfg.protocol.clone(), diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index c1807379c..aa6e74f0f 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -23,7 +23,6 @@ use near_workspaces::types::{KeyType, SecretKey}; use near_workspaces::{Account, AccountId, Contract, Worker}; use serde_json::json; use testcontainers::{Container, GenericImage}; -use url::Url; const NETWORK: &str = "mpc_it_network"; @@ -207,7 +206,6 @@ pub struct Context<'a> { pub mpc_contract: Contract, pub datastore: crate::containers::Datastore<'a>, pub storage_options: storage::Options, - pub redis_url: Url, } pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> { @@ -241,6 +239,7 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> sk_share_secret_id: None, gcp_datastore_url: Some(datastore.local_address.clone()), sk_share_local_path: Some(sk_share_local_path), + redis_url: "redis://localhost".to_string(), // TODO:pass real redis URL }; Ok(Context { docker_client, @@ -252,7 +251,6 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> mpc_contract, datastore, storage_options, - redis_url: Url::parse("redis://localhost")?, // TODO:pass real URL }) } diff --git a/integration-tests/chain-signatures/src/local.rs b/integration-tests/chain-signatures/src/local.rs index 58e046761..a3051b6b4 100644 --- a/integration-tests/chain-signatures/src/local.rs +++ b/integration-tests/chain-signatures/src/local.rs @@ -161,7 +161,6 @@ impl Node { indexer_options, my_address: None, storage_options: ctx.storage_options.clone(), - redis_url: ctx.redis_url.clone(), override_config: Some(OverrideConfig::new(serde_json::to_value( config.cfg.protocol.clone(), )?)), From 7ca6a5d9c12066b28c25296114d144d21636236f Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 16 Oct 2024 01:21:15 +0300 Subject: [PATCH 13/64] rust 2024 requirements --- .../node/src/storage/presignature_storage.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index fe418e016..211d14ee0 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -1,7 +1,6 @@ use std::sync::Arc; use anyhow::Ok; -use axum::async_trait; use redis::{Commands, Connection, FromRedisValue, RedisWrite, ToRedisArgs}; use tokio::sync::RwLock; use url::Url; @@ -45,16 +44,20 @@ impl RedisPresignatureStorage { } } -#[async_trait] impl PresignatureStorage for RedisPresignatureStorage { fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { self.redis_connection - .hset(PRESIGNATURES_MAP_NAME, presignature.id, presignature)?; + .hset::<&str, PresignatureId, Presignature, ()>( + PRESIGNATURES_MAP_NAME, + presignature.id, + presignature, + )?; Ok(()) } fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()> { - self.redis_connection.sadd(MINE_SET_NAME, presignature.id)?; + self.redis_connection + .sadd::<&str, PresignatureId, ()>(MINE_SET_NAME, presignature.id)?; self.insert(presignature)?; Ok(()) } @@ -74,7 +77,8 @@ impl PresignatureStorage for RedisPresignatureStorage { self.redis_connection.hget(PRESIGNATURES_MAP_NAME, id)?; match result { Some(presignature) => { - self.redis_connection.hdel(PRESIGNATURES_MAP_NAME, id)?; + self.redis_connection + .hdel::<&str, PresignatureId, ()>(PRESIGNATURES_MAP_NAME, *id)?; Ok(Some(presignature)) } None => Ok(None), From 6e3b027cf372921f9ea34e0105dd1a1aeb8355dc Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 16 Oct 2024 15:42:38 +0300 Subject: [PATCH 14/64] start redis in it --- integration-tests/chain-signatures/redis.conf | 8 +++ .../chain-signatures/src/containers.rs | 52 +++++++++++++++++++ integration-tests/chain-signatures/src/lib.rs | 7 ++- 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 integration-tests/chain-signatures/redis.conf diff --git a/integration-tests/chain-signatures/redis.conf b/integration-tests/chain-signatures/redis.conf new file mode 100644 index 000000000..85706cb01 --- /dev/null +++ b/integration-tests/chain-signatures/redis.conf @@ -0,0 +1,8 @@ +# Enable Append Only File (AOF) persistence +appendonly yes + +# Set the appendfsync policy to flush the AOF every second +appendfsync everysec + +# Set the directory for persistence +dir /data diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 97eec7fd7..8f058b4b4 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -620,3 +620,55 @@ impl<'a> Datastore<'a> { }) } } + +pub struct Redis<'a> { + pub container: Container<'a, GenericImage>, + pub address: String, + pub local_address: String, +} + +impl<'a> Redis<'a> { + pub const CONTAINER_PORT: u16 = 6379; + pub const HOST_CONFIG_PATH: &'static str = "./redis.conf"; + pub const CONTAINER_CONFIG_PATH: &'static str = "/usr/local/etc/redis/redis.conf"; + + pub async fn run(docker_client: &'a DockerClient, network: &str) -> anyhow::Result> { + tracing::info!("Running Redis container with hardcoded config..."); + + let image = GenericImage::new("redis", "7.2.5") + .with_wait_for(WaitFor::message_on_stdout("Ready to accept connections")) + .with_exposed_port(Self::CONTAINER_PORT) + .with_volume(Self::HOST_CONFIG_PATH, Self::CONTAINER_CONFIG_PATH); + + // Pass the config file to Redis on startup + let image: RunnableImage = ( + image, + vec![ + "redis-server".to_string(), + Self::CONTAINER_CONFIG_PATH.to_string(), + ], + ) + .into(); + + let image = image.with_network(network); + + let container = docker_client.cli.run(image); + let ip_address = docker_client + .get_network_ip_address(&container, network) + .await?; + let host_port = container.get_host_port_ipv4(Self::CONTAINER_PORT); + + let full_address = format!("redis://{}:{}/", ip_address, Self::CONTAINER_PORT); + let local_address = format!("redis://127.0.0.1:{}/", host_port); + tracing::info!( + "Redis container is running with hardcoded config at {}", + full_address + ); + + Ok(Redis { + container, + local_address, + address: full_address, + }) + } +} diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index aa6e74f0f..36dfbc27b 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -232,6 +232,11 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> let datastore = crate::containers::Datastore::run(docker_client, docker_network, gcp_project_id).await?; + let redis_container = crate::containers::Redis::run(docker_client, docker_network).await?; + let redis_url = redis_container.local_address.clone(); + + tracing::info!(redis_url = %redis_url, "started Redis container"); + let sk_share_local_path = "multichain-integration-secret-manager".to_string(); let storage_options = mpc_node::storage::Options { env: "local-test".to_string(), @@ -239,7 +244,7 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> sk_share_secret_id: None, gcp_datastore_url: Some(datastore.local_address.clone()), sk_share_local_path: Some(sk_share_local_path), - redis_url: "redis://localhost".to_string(), // TODO:pass real redis URL + redis_url, }; Ok(Context { docker_client, From 6d6fcbb0af9d1eeab03b85024399b2ce72b03eab Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 16 Oct 2024 15:47:23 +0300 Subject: [PATCH 15/64] pull redis in it --- .github/workflows/multichain-integration.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/multichain-integration.yml b/.github/workflows/multichain-integration.yml index bceab31fa..e0ff4119f 100644 --- a/.github/workflows/multichain-integration.yml +++ b/.github/workflows/multichain-integration.yml @@ -39,11 +39,12 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Pull Relayer & Sandbox Docker Images + - name: Pull Relayer, Sandbox, Redis Docker Images run: | docker pull ghcr.io/near/os-relayer:12ba6e35690df3979fce0b36a41d0ca0db9c0ab4 docker pull ghcr.io/near/near-lake-indexer:node-2.3.0 docker pull localstack/localstack:3.5.0 + docker pull redis:7.2.5 - name: Install stable toolchain uses: actions-rs/toolchain@v1 From 998c8974c70e48f16f3d0ae47fefe48ea056ef6c Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 16 Oct 2024 16:06:30 +0300 Subject: [PATCH 16/64] lock file update --- chain-signatures/Cargo.lock | 56 +++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/chain-signatures/Cargo.lock b/chain-signatures/Cargo.lock index 5df45e303..fecf0a24a 100644 --- a/chain-signatures/Cargo.lock +++ b/chain-signatures/Cargo.lock @@ -182,6 +182,12 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.7.4" @@ -1297,6 +1303,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -2560,7 +2576,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -2959,7 +2975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if 1.0.0", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -3197,6 +3213,7 @@ dependencies = [ "once_cell", "prometheus", "rand", + "redis", "reqwest 0.11.27", "semver", "serde", @@ -4067,6 +4084,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -4089,7 +4116,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" dependencies = [ "autocfg", - "num-bigint", + "num-bigint 0.3.3", "num-integer", "num-traits", "serde", @@ -4668,6 +4695,23 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redis" +version = "0.27.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6baebe319ef5e4b470f248335620098d1c2e9261e995be05f56f719ca4bdb2" +dependencies = [ + "arc-swap", + "combine", + "itoa", + "num-bigint 0.4.6", + "percent-encoding 2.3.1", + "ryu", + "sha1_smol", + "socket2 0.5.7", + "url 2.5.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -5396,6 +5440,12 @@ dependencies = [ "digest", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.10.8" From e449f8cf299a8945da60ddbe2cd1d0b03094f74b Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 16 Oct 2024 19:04:29 +0300 Subject: [PATCH 17/64] redis unit test --- .../node/src/protocol/presignature.rs | 29 +++++--- integration-tests/README.md | 1 + .../chain-signatures/src/containers.rs | 7 +- .../chain-signatures/tests/cases/mod.rs | 73 ++++++++++++++++++- 4 files changed, 92 insertions(+), 18 deletions(-) diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index faa459c2d..093990ecd 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -9,6 +9,7 @@ use cait_sith::protocol::{Action, InitializationError, Participant, ProtocolErro use cait_sith::{KeygenOutput, PresignArguments, PresignOutput}; use chrono::Utc; use crypto_shared::PublicKey; +use k256::elliptic_curve::CurveArithmetic; use k256::Secp256k1; use mpc_contract::config::ProtocolConfig; use serde::ser::SerializeStruct; @@ -26,12 +27,27 @@ use near_account_id::AccountId; pub type PresignatureId = u64; /// A completed presignature. +#[derive(Clone)] pub struct Presignature { pub id: PresignatureId, pub output: PresignOutput, pub participants: Vec, } +impl Default for Presignature { + fn default() -> Self { + Self { + id: 1, + output: PresignOutput { + big_r: ::AffinePoint::default(), + k: ::Scalar::ZERO, + sigma: ::Scalar::ONE, + }, + participants: vec![Participant::from(1), Participant::from(2)], + } + } +} + impl Serialize for Presignature { fn serialize(&self, serializer: S) -> Result where @@ -718,22 +734,11 @@ const fn first_8_bytes(input: [u8; 32]) -> [u8; 8] { #[cfg(test)] mod tests { - use cait_sith::{protocol::Participant, PresignOutput}; - use k256::{elliptic_curve::CurveArithmetic, Secp256k1}; - use crate::protocol::presignature::Presignature; #[tokio::test] async fn test_presignature_serialize_deserialize() { - let presignature = Presignature { - id: 1, - output: PresignOutput { - big_r: ::AffinePoint::default(), - k: ::Scalar::ZERO, - sigma: ::Scalar::ONE, - }, - participants: vec![Participant::from(1), Participant::from(2)], - }; + let presignature = Presignature::default(); // Serialize Presignature to JSON let serialized = diff --git a/integration-tests/README.md b/integration-tests/README.md index c14113225..ff947addb 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -7,6 +7,7 @@ Running integration tests requires you to have relayer and sandbox docker images ```BASH docker pull ghcr.io/near/os-relayer docker pull ghcr.io/near/sandbox +docker pull redis:7.2.5 ``` For M1 you may want to pull the following image instead: diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 8f058b4b4..6275f2c58 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -633,7 +633,7 @@ impl<'a> Redis<'a> { pub const CONTAINER_CONFIG_PATH: &'static str = "/usr/local/etc/redis/redis.conf"; pub async fn run(docker_client: &'a DockerClient, network: &str) -> anyhow::Result> { - tracing::info!("Running Redis container with hardcoded config..."); + tracing::info!("Running Redis container..."); let image = GenericImage::new("redis", "7.2.5") .with_wait_for(WaitFor::message_on_stdout("Ready to accept connections")) @@ -660,10 +660,7 @@ impl<'a> Redis<'a> { let full_address = format!("redis://{}:{}/", ip_address, Self::CONTAINER_PORT); let local_address = format!("redis://127.0.0.1:{}/", host_port); - tracing::info!( - "Redis container is running with hardcoded config at {}", - full_address - ); + tracing::info!("Redis container is running at {}", full_address); Ok(Redis { container, diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 2cb2cad70..ee64a7ed7 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -1,8 +1,10 @@ use std::str::FromStr; +use std::sync::Arc; use crate::actions::{self, add_latency, wait_for}; use crate::with_multichain_nodes; +use cait_sith::protocol::Participant; use crypto_shared::{self, derive_epsilon, derive_key, x_coordinate, ScalarExt}; use integration_tests_chain_signatures::containers::{self, DockerClient}; use integration_tests_chain_signatures::MultichainConfig; @@ -10,10 +12,15 @@ use k256::elliptic_curve::point::AffineCoordinates; use mpc_contract::config::Config; use mpc_contract::update::ProposeUpdateArgs; use mpc_node::kdf::into_eth_sig; -use mpc_node::test_utils; +use mpc_node::protocol::presignature::{Presignature, PresignatureManager}; +use mpc_node::storage::presignature_storage::LockPresignatureStorageBox; use mpc_node::types::LatestBlockHeight; use mpc_node::util::NearPublicKeyExt; +use mpc_node::{storage, test_utils}; +use near_account_id::AccountId; use test_log::test; +use tokio::sync::RwLock; +use url::Url; pub mod nightly; @@ -226,6 +233,70 @@ async fn test_triples_persistence_for_deletion() -> anyhow::Result<()> { Ok(()) } +#[test(tokio::test)] +async fn test_presignature_persistence() -> anyhow::Result<()> { + let docker_client = DockerClient::default(); + let docker_network = "test-presignature-persistence"; + docker_client.create_network(docker_network).await?; + let redis = containers::Redis::run(&docker_client, docker_network).await?; + let redis_url = Url::parse(redis.local_address.as_str())?; + let presignature_storage: LockPresignatureStorageBox = + Arc::new(RwLock::new(storage::presignature_storage::init(redis_url))); + let mut presignature_manager = PresignatureManager::new( + Participant::from(0), + 5, + 123, + &AccountId::from_str("test.near").unwrap(), + presignature_storage, + ); + + let presignature = Presignature::default(); + + // Check that the storage is empty at the start + assert!(!presignature_manager.contains(&presignature.id).await); + assert!(!presignature_manager.contains_mine(&presignature.id).await); + assert_eq!(presignature_manager.count_all().await, 0); + assert_eq!(presignature_manager.count_mine().await, 0); + assert!(presignature_manager.is_empty().await); + assert_eq!(presignature_manager.count_potential().await, 0); + + presignature_manager.insert(presignature.clone()).await; + + // Check that the storage contains the foreign presignature + assert!(presignature_manager.contains(&presignature.id).await); + assert!(!presignature_manager.contains_mine(&presignature.id).await); + assert_eq!(presignature_manager.count_all().await, 1); + assert_eq!(presignature_manager.count_mine().await, 0); + assert_eq!(presignature_manager.count_potential().await, 1); + + // Take presignature and check that it is removed from the storage + presignature_manager.take(presignature.id).await.unwrap(); + assert!(!presignature_manager.contains(&presignature.id).await); + assert!(!presignature_manager.contains_mine(&presignature.id).await); + assert_eq!(presignature_manager.count_all().await, 0); + assert_eq!(presignature_manager.count_mine().await, 0); + assert_eq!(presignature_manager.count_potential().await, 0); + + // Add mine presignature and check that it is in the storage + presignature_manager.insert_mine(presignature.clone()).await; + assert!(presignature_manager.contains(&presignature.id).await); + assert!(presignature_manager.contains_mine(&presignature.id).await); + assert_eq!(presignature_manager.count_all().await, 1); + assert_eq!(presignature_manager.count_mine().await, 1); + assert_eq!(presignature_manager.count_potential().await, 1); + + // Take mine presignature and check that it is removed from the storage + presignature_manager.take_mine().await.unwrap(); + assert!(!presignature_manager.contains(&presignature.id).await); + assert!(!presignature_manager.contains_mine(&presignature.id).await); + assert_eq!(presignature_manager.count_all().await, 0); + assert_eq!(presignature_manager.count_mine().await, 0); + assert!(presignature_manager.is_empty().await); + assert_eq!(presignature_manager.count_potential().await, 0); + + Ok(()) +} + #[test(tokio::test)] async fn test_latest_block_height() -> anyhow::Result<()> { with_multichain_nodes(MultichainConfig::default(), |ctx| { From 4f82d8b64e68996dd8877c0cafbd40e8b16f36d7 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 17 Oct 2024 19:22:15 +0300 Subject: [PATCH 18/64] comments 1 --- .github/workflows/multichain-integration.yml | 1 - chain-signatures/node/src/protocol/message.rs | 2 +- .../node/src/protocol/presignature.rs | 31 ++++++++----------- .../chain-signatures/tests/cases/mod.rs | 17 +++++++++- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/.github/workflows/multichain-integration.yml b/.github/workflows/multichain-integration.yml index e0ff4119f..d0f03e6a9 100644 --- a/.github/workflows/multichain-integration.yml +++ b/.github/workflows/multichain-integration.yml @@ -41,7 +41,6 @@ jobs: - name: Pull Relayer, Sandbox, Redis Docker Images run: | - docker pull ghcr.io/near/os-relayer:12ba6e35690df3979fce0b36a41d0ca0db9c0ab4 docker pull ghcr.io/near/near-lake-indexer:node-2.3.0 docker pull localstack/localstack:3.5.0 docker pull redis:7.2.5 diff --git a/chain-signatures/node/src/protocol/message.rs b/chain-signatures/node/src/protocol/message.rs index 21c502e66..fd4b67791 100644 --- a/chain-signatures/node/src/protocol/message.rs +++ b/chain-signatures/node/src/protocol/message.rs @@ -309,7 +309,7 @@ impl MessageHandler for RunningState { } let protocol = match presignature_manager - .get_or_start_protocol( + .get_or_start_generation( participants, *id, *triple0, diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 093990ecd..d2ebccd87 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -9,7 +9,6 @@ use cait_sith::protocol::{Action, InitializationError, Participant, ProtocolErro use cait_sith::{KeygenOutput, PresignArguments, PresignOutput}; use chrono::Utc; use crypto_shared::PublicKey; -use k256::elliptic_curve::CurveArithmetic; use k256::Secp256k1; use mpc_contract::config::ProtocolConfig; use serde::ser::SerializeStruct; @@ -27,27 +26,12 @@ use near_account_id::AccountId; pub type PresignatureId = u64; /// A completed presignature. -#[derive(Clone)] pub struct Presignature { pub id: PresignatureId, pub output: PresignOutput, pub participants: Vec, } -impl Default for Presignature { - fn default() -> Self { - Self { - id: 1, - output: PresignOutput { - big_r: ::AffinePoint::default(), - k: ::Scalar::ZERO, - sigma: ::Scalar::ONE, - }, - participants: vec![Participant::from(1), Participant::from(2)], - } - } -} - impl Serialize for Presignature { fn serialize(&self, serializer: S) -> Result where @@ -518,7 +502,7 @@ impl PresignatureManager { /// 4) Depends on triples (`triple0`/`triple1`) that are unknown to the node // TODO: What if the presignature completed generation and is already spent? #[allow(clippy::too_many_arguments)] - pub async fn get_or_start_protocol( + pub async fn get_or_start_generation( &mut self, participants: &Participants, id: PresignatureId, @@ -734,11 +718,22 @@ const fn first_8_bytes(input: [u8; 32]) -> [u8; 8] { #[cfg(test)] mod tests { + use cait_sith::{protocol::Participant, PresignOutput}; + use k256::{elliptic_curve::CurveArithmetic, Secp256k1}; + use crate::protocol::presignature::Presignature; #[tokio::test] async fn test_presignature_serialize_deserialize() { - let presignature = Presignature::default(); + let presignature = Presignature { + id: 1, + output: PresignOutput { + big_r: ::AffinePoint::default(), + k: ::Scalar::ZERO, + sigma: ::Scalar::ONE, + }, + participants: vec![Participant::from(1), Participant::from(2)], + }; // Serialize Presignature to JSON let serialized = diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index ee64a7ed7..8433b0447 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -5,10 +5,13 @@ use crate::actions::{self, add_latency, wait_for}; use crate::with_multichain_nodes; use cait_sith::protocol::Participant; +use cait_sith::PresignOutput; use crypto_shared::{self, derive_epsilon, derive_key, x_coordinate, ScalarExt}; +use elliptic_curve::CurveArithmetic; use integration_tests_chain_signatures::containers::{self, DockerClient}; use integration_tests_chain_signatures::MultichainConfig; use k256::elliptic_curve::point::AffineCoordinates; +use k256::Secp256k1; use mpc_contract::config::Config; use mpc_contract::update::ProposeUpdateArgs; use mpc_node::kdf::into_eth_sig; @@ -250,7 +253,7 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { presignature_storage, ); - let presignature = Presignature::default(); + let presignature = dummy_presignature(); // Check that the storage is empty at the start assert!(!presignature_manager.contains(&presignature.id).await); @@ -297,6 +300,18 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { Ok(()) } +fn dummy_presignature() -> Presignature { + Presignature { + id: 1, + output: PresignOutput { + big_r: ::AffinePoint::default(), + k: ::Scalar::ZERO, + sigma: ::Scalar::ONE, + }, + participants: vec![Participant::from(1), Participant::from(2)], + } +} + #[test(tokio::test)] async fn test_latest_block_height() -> anyhow::Result<()> { with_multichain_nodes(MultichainConfig::default(), |ctx| { From 90d6d8e7e8e00fcd947263581d56216bce16f4d5 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 17 Oct 2024 20:48:59 +0300 Subject: [PATCH 19/64] comments 2 --- chain-signatures/node/src/cli.rs | 4 +- .../node/src/protocol/consensus.rs | 4 +- chain-signatures/node/src/protocol/mod.rs | 8 ++-- .../node/src/protocol/presignature.rs | 6 +-- .../node/src/storage/presignature_storage.rs | 38 +++++++------------ .../chain-signatures/tests/cases/mod.rs | 36 ++++++++++-------- 6 files changed, 44 insertions(+), 52 deletions(-) diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 83a71c0bd..ea22943ea 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -1,7 +1,7 @@ use crate::config::{Config, LocalConfig, NetworkConfig, OverrideConfig}; use crate::gcp::GcpService; use crate::protocol::{MpcSignProtocol, SignQueue}; -use crate::storage::presignature_storage::LockPresignatureStorageBox; +use crate::storage::presignature_storage::LockRedisPresignatureStorage; use crate::storage::triple_storage::LockTripleNodeStorageBox; use crate::{http_client, indexer, mesh, storage, web}; use clap::Parser; @@ -212,7 +212,7 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { )); let redis_url: Url = Url::parse(storage_options.redis_url.as_str())?; - let presignature_storage: LockPresignatureStorageBox = + let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new(storage::presignature_storage::init(redis_url))); let sign_sk = sign_sk.unwrap_or_else(|| account_sk.clone()); diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index 528efd111..50cf67020 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -13,7 +13,7 @@ use crate::protocol::presignature::PresignatureManager; use crate::protocol::signature::SignatureManager; use crate::protocol::state::{GeneratingState, ResharingState}; use crate::protocol::triple::TripleManager; -use crate::storage::presignature_storage::LockPresignatureStorageBox; +use crate::storage::presignature_storage::LockRedisPresignatureStorage; use crate::storage::secret_storage::SecretNodeStorageBox; use crate::storage::triple_storage::LockTripleNodeStorageBox; use crate::storage::triple_storage::TripleData; @@ -43,7 +43,7 @@ pub trait ConsensusCtx { fn sign_queue(&self) -> Arc>; fn secret_storage(&self) -> &SecretNodeStorageBox; fn triple_storage(&self) -> LockTripleNodeStorageBox; - fn presignature_storage(&self) -> LockPresignatureStorageBox; + fn presignature_storage(&self) -> LockRedisPresignatureStorage; fn cfg(&self) -> &Config; fn message_options(&self) -> http_client::Options; } diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 34c2805cb..6d407fef8 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -30,7 +30,7 @@ use crate::protocol::consensus::ConsensusProtocol; use crate::protocol::cryptography::CryptographicProtocol; use crate::protocol::message::{MessageHandler, MpcMessageQueue}; use crate::rpc_client; -use crate::storage::presignature_storage::LockPresignatureStorageBox; +use crate::storage::presignature_storage::LockRedisPresignatureStorage; use crate::storage::secret_storage::SecretNodeStorageBox; use crate::storage::triple_storage::LockTripleNodeStorageBox; @@ -55,7 +55,7 @@ struct Ctx { sign_queue: Arc>, secret_storage: SecretNodeStorageBox, triple_storage: LockTripleNodeStorageBox, - presignature_storage: LockPresignatureStorageBox, + presignature_storage: LockRedisPresignatureStorage, cfg: Config, mesh: Mesh, message_options: http_client::Options, @@ -102,7 +102,7 @@ impl ConsensusCtx for &mut MpcSignProtocol { self.ctx.triple_storage.clone() } - fn presignature_storage(&self) -> LockPresignatureStorageBox { + fn presignature_storage(&self) -> LockRedisPresignatureStorage { self.ctx.presignature_storage.clone() } @@ -179,7 +179,7 @@ impl MpcSignProtocol { sign_queue: Arc>, secret_storage: SecretNodeStorageBox, triple_storage: LockTripleNodeStorageBox, - presignature_storage: LockPresignatureStorageBox, + presignature_storage: LockRedisPresignatureStorage, cfg: Config, mesh_options: mesh::Options, message_options: http_client::Options, diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index d2ebccd87..8171fed43 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -1,7 +1,7 @@ use super::message::PresignatureMessage; use super::triple::{Triple, TripleId, TripleManager}; use crate::protocol::contract::primitives::Participants; -use crate::storage::presignature_storage::LockPresignatureStorageBox; +use crate::storage::presignature_storage::LockRedisPresignatureStorage; use crate::types::{PresignatureProtocol, SecretKeyShare}; use crate::util::AffinePointExt; @@ -174,7 +174,7 @@ pub enum GenerationError { /// Abstracts how triples are generated by providing a way to request a new triple that will be /// complete some time in the future and a way to take an already generated triple. pub struct PresignatureManager { - presignature_storage: LockPresignatureStorageBox, + presignature_storage: LockRedisPresignatureStorage, /// Ongoing presignature generation protocols. generators: HashMap, /// The set of presignatures that were introduced to the system by the current node. @@ -195,7 +195,7 @@ impl PresignatureManager { threshold: usize, epoch: u64, my_account_id: &AccountId, - presignature_storage: LockPresignatureStorageBox, + presignature_storage: LockRedisPresignatureStorage, ) -> Self { Self { presignature_storage, diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index 211d14ee0..075d3d7f2 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -8,28 +8,16 @@ use url::Url; use crate::protocol::presignature::{Presignature, PresignatureId}; type PresigResult = std::result::Result; -pub type PresignatureStorageBox = Box; -pub type LockPresignatureStorageBox = Arc>; +pub type LockRedisPresignatureStorage = Arc>; const PRESIGNATURES_MAP_NAME: &str = "presignatures"; const MINE_SET_NAME: &str = "presignatures_mine"; -pub fn init(redis_url: Url) -> PresignatureStorageBox { - Box::new(RedisPresignatureStorage::new(redis_url)) as PresignatureStorageBox +pub fn init(redis_url: Url) -> RedisPresignatureStorage { + RedisPresignatureStorage::new(redis_url) } -pub trait PresignatureStorage { - fn insert(&mut self, presignature: Presignature) -> PresigResult<()>; - fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()>; - fn contains(&mut self, id: &PresignatureId) -> PresigResult; - fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult; - fn take(&mut self, id: &PresignatureId) -> PresigResult>; - fn take_mine(&mut self) -> PresigResult>; - fn count_all(&mut self) -> PresigResult; - fn count_mine(&mut self) -> PresigResult; -} - -struct RedisPresignatureStorage { +pub struct RedisPresignatureStorage { redis_connection: Connection, } @@ -44,8 +32,8 @@ impl RedisPresignatureStorage { } } -impl PresignatureStorage for RedisPresignatureStorage { - fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { +impl RedisPresignatureStorage { + pub fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { self.redis_connection .hset::<&str, PresignatureId, Presignature, ()>( PRESIGNATURES_MAP_NAME, @@ -55,24 +43,24 @@ impl PresignatureStorage for RedisPresignatureStorage { Ok(()) } - fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()> { + pub fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()> { self.redis_connection .sadd::<&str, PresignatureId, ()>(MINE_SET_NAME, presignature.id)?; self.insert(presignature)?; Ok(()) } - fn contains(&mut self, id: &PresignatureId) -> PresigResult { + pub fn contains(&mut self, id: &PresignatureId) -> PresigResult { let result: bool = self.redis_connection.hexists(PRESIGNATURES_MAP_NAME, id)?; Ok(result) } - fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult { + pub fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult { let result: bool = self.redis_connection.sismember(MINE_SET_NAME, id)?; Ok(result) } - fn take(&mut self, id: &PresignatureId) -> PresigResult> { + pub fn take(&mut self, id: &PresignatureId) -> PresigResult> { let result: Option = self.redis_connection.hget(PRESIGNATURES_MAP_NAME, id)?; match result { @@ -85,7 +73,7 @@ impl PresignatureStorage for RedisPresignatureStorage { } } - fn take_mine(&mut self) -> PresigResult> { + pub fn take_mine(&mut self) -> PresigResult> { let id: Option = self.redis_connection.spop(MINE_SET_NAME)?; match id { Some(id) => self.take(&id), @@ -93,12 +81,12 @@ impl PresignatureStorage for RedisPresignatureStorage { } } - fn count_all(&mut self) -> PresigResult { + pub fn count_all(&mut self) -> PresigResult { let result: usize = self.redis_connection.hlen(PRESIGNATURES_MAP_NAME)?; Ok(result) } - fn count_mine(&mut self) -> PresigResult { + pub fn count_mine(&mut self) -> PresigResult { let result: usize = self.redis_connection.scard(MINE_SET_NAME)?; Ok(result) } diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 8433b0447..c3afb860a 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -15,8 +15,8 @@ use k256::Secp256k1; use mpc_contract::config::Config; use mpc_contract::update::ProposeUpdateArgs; use mpc_node::kdf::into_eth_sig; -use mpc_node::protocol::presignature::{Presignature, PresignatureManager}; -use mpc_node::storage::presignature_storage::LockPresignatureStorageBox; +use mpc_node::protocol::presignature::{Presignature, PresignatureId, PresignatureManager}; +use mpc_node::storage::presignature_storage::LockRedisPresignatureStorage; use mpc_node::types::LatestBlockHeight; use mpc_node::util::NearPublicKeyExt; use mpc_node::{storage, test_utils}; @@ -243,7 +243,7 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { docker_client.create_network(docker_network).await?; let redis = containers::Redis::run(&docker_client, docker_network).await?; let redis_url = Url::parse(redis.local_address.as_str())?; - let presignature_storage: LockPresignatureStorageBox = + let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new(storage::presignature_storage::init(redis_url))); let mut presignature_manager = PresignatureManager::new( Participant::from(0), @@ -254,44 +254,48 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { ); let presignature = dummy_presignature(); + let presignature_id: PresignatureId = presignature.id; // Check that the storage is empty at the start - assert!(!presignature_manager.contains(&presignature.id).await); - assert!(!presignature_manager.contains_mine(&presignature.id).await); + assert!(!presignature_manager.contains(&presignature_id).await); + assert!(!presignature_manager.contains_mine(&presignature_id).await); assert_eq!(presignature_manager.count_all().await, 0); assert_eq!(presignature_manager.count_mine().await, 0); assert!(presignature_manager.is_empty().await); assert_eq!(presignature_manager.count_potential().await, 0); - presignature_manager.insert(presignature.clone()).await; + presignature_manager.insert(presignature).await; // Check that the storage contains the foreign presignature - assert!(presignature_manager.contains(&presignature.id).await); - assert!(!presignature_manager.contains_mine(&presignature.id).await); + assert!(presignature_manager.contains(&presignature_id).await); + assert!(!presignature_manager.contains_mine(&presignature_id).await); assert_eq!(presignature_manager.count_all().await, 1); assert_eq!(presignature_manager.count_mine().await, 0); assert_eq!(presignature_manager.count_potential().await, 1); // Take presignature and check that it is removed from the storage - presignature_manager.take(presignature.id).await.unwrap(); - assert!(!presignature_manager.contains(&presignature.id).await); - assert!(!presignature_manager.contains_mine(&presignature.id).await); + presignature_manager.take(presignature_id).await.unwrap(); + assert!(!presignature_manager.contains(&presignature_id).await); + assert!(!presignature_manager.contains_mine(&presignature_id).await); assert_eq!(presignature_manager.count_all().await, 0); assert_eq!(presignature_manager.count_mine().await, 0); assert_eq!(presignature_manager.count_potential().await, 0); + let mine_presignature = dummy_presignature(); + let mine_presig_id: PresignatureId = mine_presignature.id; + // Add mine presignature and check that it is in the storage - presignature_manager.insert_mine(presignature.clone()).await; - assert!(presignature_manager.contains(&presignature.id).await); - assert!(presignature_manager.contains_mine(&presignature.id).await); + presignature_manager.insert_mine(mine_presignature).await; + assert!(presignature_manager.contains(&mine_presig_id).await); + assert!(presignature_manager.contains_mine(&mine_presig_id).await); assert_eq!(presignature_manager.count_all().await, 1); assert_eq!(presignature_manager.count_mine().await, 1); assert_eq!(presignature_manager.count_potential().await, 1); // Take mine presignature and check that it is removed from the storage presignature_manager.take_mine().await.unwrap(); - assert!(!presignature_manager.contains(&presignature.id).await); - assert!(!presignature_manager.contains_mine(&presignature.id).await); + assert!(!presignature_manager.contains(&mine_presig_id).await); + assert!(!presignature_manager.contains_mine(&mine_presig_id).await); assert_eq!(presignature_manager.count_all().await, 0); assert_eq!(presignature_manager.count_mine().await, 0); assert!(presignature_manager.is_empty().await); From 3bce87b8923964b9fbb8729640267e6b21bce0e2 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 17 Oct 2024 21:16:56 +0300 Subject: [PATCH 20/64] triple manager functions renamed to match presiganture manager --- chain-signatures/node/src/protocol/triple.rs | 18 +++++++++--------- chain-signatures/node/src/test_utils.rs | 4 ++-- chain-signatures/node/src/web/mod.rs | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index 2bcca581b..13c294181 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -164,28 +164,28 @@ impl TripleManager { } /// Returns the number of unspent triples available in the manager. - pub fn len(&self) -> usize { + pub fn count(&self) -> usize { self.triples.len() } /// Returns if there's any unspent triple in the manager. pub fn is_empty(&self) -> bool { - self.len() == 0 + self.count() == 0 } /// Returns the number of unspent triples assigned to this node. - pub fn my_len(&self) -> usize { + pub fn count_mine(&self) -> usize { self.mine.len() } /// Returns the number of unspent triples we will have in the manager once /// all ongoing generation protocols complete. - pub fn potential_len(&self) -> usize { - self.len() + self.generators.len() + pub fn count_potential(&self) -> usize { + self.count() + self.generators.len() } pub fn has_min_triples(&self, cfg: &ProtocolConfig) -> bool { - self.my_len() >= cfg.triple.min_triples as usize + self.count_mine() >= cfg.triple.min_triples as usize } /// Clears an entry from failed triples if that triple protocol was created more than 2 hrs ago @@ -256,11 +256,11 @@ impl TripleManager { // Stopgap to prevent too many triples in the system. This should be around min_triple*nodes*2 // for good measure so that we have enough triples to do presig generation while also maintain // the minimum number of triples where a single node can't flood the system. - if self.potential_len() >= cfg.triple.max_triples as usize { + if self.count_potential() >= cfg.triple.max_triples as usize { false } else { // We will always try to generate a new triple if we have less than the minimum - self.my_len() < cfg.triple.min_triples as usize + self.count_mine() < cfg.triple.min_triples as usize && self.introduced.len() < cfg.max_concurrent_introduction as usize && self.generators.len() < cfg.max_concurrent_generation as usize } @@ -412,7 +412,7 @@ impl TripleManager { if self.triples.contains_key(&id) || self.gc.contains_key(&id) { Ok(None) } else { - let potential_len = self.potential_len(); + let potential_len = self.count_potential(); match self.generators.entry(id) { Entry::Vacant(e) => { if potential_len >= cfg.triple.max_triples as usize { diff --git a/chain-signatures/node/src/test_utils.rs b/chain-signatures/node/src/test_utils.rs index 5af109fdf..8027295f5 100644 --- a/chain-signatures/node/src/test_utils.rs +++ b/chain-signatures/node/src/test_utils.rs @@ -187,8 +187,8 @@ pub async fn test_triple_generation(datastore_url: Option) { let inputs = tm.managers.into_iter().map(|m| { ( - m.my_len(), - m.len(), + m.count_mine(), + m.count(), m.generators, m.triples, m.triple_storage, diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index c1128686d..33b9e96f7 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -137,9 +137,9 @@ async fn state(Extension(state): Extension>) -> Result { let triple_manager_read = state.triple_manager.read().await; - let triple_potential_count = triple_manager_read.potential_len(); - let triple_count = triple_manager_read.len(); - let triple_mine_count = triple_manager_read.my_len(); + let triple_potential_count = triple_manager_read.count_potential(); + let triple_count = triple_manager_read.count(); + let triple_mine_count = triple_manager_read.count_mine(); let presignature_read = state.presignature_manager.read().await; let presignature_count = presignature_read.count_all().await; let presignature_mine_count = presignature_read.count_mine().await; From fde93fbc452da3135770bd25681b37f9f798f5ce Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 17 Oct 2024 21:48:57 +0300 Subject: [PATCH 21/64] serialization simlified --- .../node/src/protocol/presignature.rs | 46 +++++-------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 8171fed43..71f830e08 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -9,7 +9,7 @@ use cait_sith::protocol::{Action, InitializationError, Participant, ProtocolErro use cait_sith::{KeygenOutput, PresignArguments, PresignOutput}; use chrono::Utc; use crypto_shared::PublicKey; -use k256::Secp256k1; +use k256::{AffinePoint, Scalar, Secp256k1}; use mpc_contract::config::ProtocolConfig; use serde::ser::SerializeStruct; use serde::{Deserialize, Serialize}; @@ -37,24 +37,11 @@ impl Serialize for Presignature { where S: serde::Serializer, { - let mut state = serializer.serialize_struct("Presignature", 3)?; + let mut state = serializer.serialize_struct("Presignature", 5)?; state.serialize_field("id", &self.id)?; - - let mut output_map = serde_json::Map::new(); - output_map.insert( - "big_r".to_string(), - serde_json::to_value(self.output.big_r).map_err(serde::ser::Error::custom)?, - ); - output_map.insert( - "k".to_string(), - serde_json::to_value(self.output.k).map_err(serde::ser::Error::custom)?, - ); - output_map.insert( - "sigma".to_string(), - serde_json::to_value(self.output.sigma).map_err(serde::ser::Error::custom)?, - ); - - state.serialize_field("output", &output_map)?; + state.serialize_field("output_big_r", &self.output.big_r)?; + state.serialize_field("output_k", &self.output.k)?; + state.serialize_field("output_sigma", &self.output.sigma)?; state.serialize_field("participants", &self.participants)?; state.end() } @@ -68,31 +55,20 @@ impl<'de> Deserialize<'de> for Presignature { #[derive(Deserialize)] struct PresignatureFields { id: PresignatureId, - output: serde_json::Value, + output_big_r: AffinePoint, + output_k: Scalar, + output_sigma: Scalar, participants: Vec, } let fields = PresignatureFields::deserialize(deserializer)?; - let big_r = fields - .output - .get("big_r") - .ok_or_else(|| serde::de::Error::missing_field("big_r"))?; - let k = fields - .output - .get("k") - .ok_or_else(|| serde::de::Error::missing_field("k"))?; - let sigma = fields - .output - .get("sigma") - .ok_or_else(|| serde::de::Error::missing_field("sigma"))?; - Ok(Self { id: fields.id, output: PresignOutput { - big_r: serde_json::from_value(big_r.clone()).map_err(serde::de::Error::custom)?, - k: serde_json::from_value(k.clone()).map_err(serde::de::Error::custom)?, - sigma: serde_json::from_value(sigma.clone()).map_err(serde::de::Error::custom)?, + big_r: fields.output_big_r, + k: fields.output_k, + sigma: fields.output_sigma, }, participants: fields.participants, }) From 9fa82ca7a206b43703d9022d6b18f5994f11f12c Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 17 Oct 2024 21:57:18 +0300 Subject: [PATCH 22/64] comments 3 --- integration-tests/chain-signatures/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 94b383844..ce4171f75 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -239,7 +239,7 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> let redis_container = crate::containers::Redis::run(docker_client, docker_network).await?; let redis_url = redis_container.local_address.clone(); - tracing::info!(redis_url = %redis_url, "started Redis container"); + tracing::info!(%redis_url, "started Redis container"); let sk_share_local_path = "multichain-integration-secret-manager".to_string(); let storage_options = mpc_node::storage::Options { From 1edc9b361d5b81e7562e3f87763b9d0a15372df8 Mon Sep 17 00:00:00 2001 From: kmaus-near Date: Thu, 17 Oct 2024 12:57:23 -0600 Subject: [PATCH 23/64] added start command to mpc-node and added redis URL format --- Dockerfile.multichain | 2 +- infra/multichain-dev/main.tf | 5 ++++- infra/multichain-dev/variables.tf | 7 ++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Dockerfile.multichain b/Dockerfile.multichain index 396760bb9..dc89badac 100644 --- a/Dockerfile.multichain +++ b/Dockerfile.multichain @@ -25,7 +25,7 @@ RUN update-ca-certificates COPY --from=builder /usr/src/app/target/release/mpc-node /usr/local/bin/mpc-node # Create a script to start both Redis and the Rust app -RUN echo "#!/bin/bash\nservice redis-server start ./redis.conf\nexec mpc-node" > /start.sh \ +RUN echo "#!/bin/bash\nservice redis-server start ./redis.conf\nexec mpc-node start" > /start.sh \ && chmod +x /start.sh WORKDIR /usr/local/bin diff --git a/infra/multichain-dev/main.tf b/infra/multichain-dev/main.tf index 1655d378a..81379e84e 100644 --- a/infra/multichain-dev/main.tf +++ b/infra/multichain-dev/main.tf @@ -11,7 +11,6 @@ module "gce-container" { container = { image = "us-east1-docker.pkg.dev/pagoda-discovery-platform-dev/multichain-public/multichain-dev:latest" - args = ["start"] port = "3000" volumeMounts = [ @@ -66,6 +65,10 @@ module "gce-container" { { name = "MPC_ENV", value = var.env + }, + { + name = "MPC_REDIS_URL", + value = var.redis_url } ]) } diff --git a/infra/multichain-dev/variables.tf b/infra/multichain-dev/variables.tf index 37426e8dc..d712fc960 100644 --- a/infra/multichain-dev/variables.tf +++ b/infra/multichain-dev/variables.tf @@ -79,6 +79,11 @@ variable "env" { default = "dev" } +variable "redis_url" { + type = string + default = "redis://127.0.0.1:6379" +} + variable "static_env" { type = list(object({ name = string @@ -99,7 +104,7 @@ variable "static_env" { }, { name = "MPC_INDEXER_START_BLOCK_HEIGHT" - value = 175970237 + value = 177069137 }, { name = "AWS_DEFAULT_REGION" From 077466deace1546391f3ec63d2a51783d769da78 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 17 Oct 2024 23:23:20 +0300 Subject: [PATCH 24/64] use account id as a part of redis storage key --- chain-signatures/node/src/cli.rs | 5 ++- .../node/src/storage/presignature_storage.rs | 42 ++++++++++++------- .../chain-signatures/tests/cases/mod.rs | 5 ++- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index ea22943ea..f08c6c644 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -212,8 +212,9 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { )); let redis_url: Url = Url::parse(storage_options.redis_url.as_str())?; - let presignature_storage: LockRedisPresignatureStorage = - Arc::new(RwLock::new(storage::presignature_storage::init(redis_url))); + let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new( + storage::presignature_storage::init(redis_url, &account_id), + )); let sign_sk = sign_sk.unwrap_or_else(|| account_sk.clone()); let my_address = my_address diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index 075d3d7f2..d1d523eb9 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use anyhow::Ok; +use near_sdk::AccountId; use redis::{Commands, Connection, FromRedisValue, RedisWrite, ToRedisArgs}; use tokio::sync::RwLock; use url::Url; @@ -10,24 +11,26 @@ use crate::protocol::presignature::{Presignature, PresignatureId}; type PresigResult = std::result::Result; pub type LockRedisPresignatureStorage = Arc>; -const PRESIGNATURES_MAP_NAME: &str = "presignatures"; -const MINE_SET_NAME: &str = "presignatures_mine"; +// Can be used to "clear" redis storage in case of a breaking change +const STORAGE_VERSION: &str = "v1"; -pub fn init(redis_url: Url) -> RedisPresignatureStorage { - RedisPresignatureStorage::new(redis_url) +pub fn init(redis_url: Url, node_account_id: &AccountId) -> RedisPresignatureStorage { + RedisPresignatureStorage::new(redis_url, node_account_id) } pub struct RedisPresignatureStorage { redis_connection: Connection, + node_account_id: AccountId, } impl RedisPresignatureStorage { - fn new(redis_url: Url) -> Self { + fn new(redis_url: Url, node_account_id: &AccountId) -> Self { Self { redis_connection: redis::Client::open(redis_url.as_str()) .expect("Failed to connect to Redis") .get_connection() .expect("Failed to get Redis connection"), + node_account_id: node_account_id.clone(), } } } @@ -36,7 +39,7 @@ impl RedisPresignatureStorage { pub fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { self.redis_connection .hset::<&str, PresignatureId, Presignature, ()>( - PRESIGNATURES_MAP_NAME, + &self.presignature_key(), presignature.id, presignature, )?; @@ -45,28 +48,28 @@ impl RedisPresignatureStorage { pub fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()> { self.redis_connection - .sadd::<&str, PresignatureId, ()>(MINE_SET_NAME, presignature.id)?; + .sadd::<&str, PresignatureId, ()>(&self.mine_key(), presignature.id)?; self.insert(presignature)?; Ok(()) } pub fn contains(&mut self, id: &PresignatureId) -> PresigResult { - let result: bool = self.redis_connection.hexists(PRESIGNATURES_MAP_NAME, id)?; + let result: bool = self.redis_connection.hexists(self.presignature_key(), id)?; Ok(result) } pub fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult { - let result: bool = self.redis_connection.sismember(MINE_SET_NAME, id)?; + let result: bool = self.redis_connection.sismember(self.mine_key(), id)?; Ok(result) } pub fn take(&mut self, id: &PresignatureId) -> PresigResult> { let result: Option = - self.redis_connection.hget(PRESIGNATURES_MAP_NAME, id)?; + self.redis_connection.hget(self.presignature_key(), id)?; match result { Some(presignature) => { self.redis_connection - .hdel::<&str, PresignatureId, ()>(PRESIGNATURES_MAP_NAME, *id)?; + .hdel::<&str, PresignatureId, ()>(&self.presignature_key(), *id)?; Ok(Some(presignature)) } None => Ok(None), @@ -74,7 +77,7 @@ impl RedisPresignatureStorage { } pub fn take_mine(&mut self) -> PresigResult> { - let id: Option = self.redis_connection.spop(MINE_SET_NAME)?; + let id: Option = self.redis_connection.spop(self.mine_key())?; match id { Some(id) => self.take(&id), None => Ok(None), @@ -82,14 +85,25 @@ impl RedisPresignatureStorage { } pub fn count_all(&mut self) -> PresigResult { - let result: usize = self.redis_connection.hlen(PRESIGNATURES_MAP_NAME)?; + let result: usize = self.redis_connection.hlen(self.presignature_key())?; Ok(result) } pub fn count_mine(&mut self) -> PresigResult { - let result: usize = self.redis_connection.scard(MINE_SET_NAME)?; + let result: usize = self.redis_connection.scard(self.mine_key())?; Ok(result) } + + fn presignature_key(&self) -> String { + format!("presignatures:{}:{}", STORAGE_VERSION, self.node_account_id) + } + + fn mine_key(&self) -> String { + format!( + "presignatures_mine:{}:{}", + STORAGE_VERSION, self.node_account_id + ) + } } impl ToRedisArgs for Presignature { diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index c3afb860a..9507a4845 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -243,8 +243,9 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { docker_client.create_network(docker_network).await?; let redis = containers::Redis::run(&docker_client, docker_network).await?; let redis_url = Url::parse(redis.local_address.as_str())?; - let presignature_storage: LockRedisPresignatureStorage = - Arc::new(RwLock::new(storage::presignature_storage::init(redis_url))); + let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new( + storage::presignature_storage::init(redis_url, &AccountId::from_str("test.near").unwrap()), + )); let mut presignature_manager = PresignatureManager::new( Participant::from(0), 5, From 99e8f751ba667502af65db802a9447f47c3328df Mon Sep 17 00:00:00 2001 From: kmaus-near Date: Thu, 17 Oct 2024 15:16:35 -0600 Subject: [PATCH 25/64] added full redis config, modified dockerfile to use it --- Dockerfile.multichain | 7 +- chain-signatures/node/redis.conf | 1316 +++++++++++++++++++++++++++++- 2 files changed, 1317 insertions(+), 6 deletions(-) diff --git a/Dockerfile.multichain b/Dockerfile.multichain index dc89badac..fb24613b5 100644 --- a/Dockerfile.multichain +++ b/Dockerfile.multichain @@ -21,11 +21,14 @@ RUN cargo build --release --package mpc-node FROM debian:stable-slim as runtime RUN apt-get update && apt-get install --assume-yes libssl-dev ca-certificates curl redis-server -RUN update-ca-certificates +RUN update-ca-certificates \ + chown redis:redis /data + COPY --from=builder /usr/src/app/target/release/mpc-node /usr/local/bin/mpc-node +COPY chain-signatures/node/redis.conf /etc/redis/redis.conf # Create a script to start both Redis and the Rust app -RUN echo "#!/bin/bash\nservice redis-server start ./redis.conf\nexec mpc-node start" > /start.sh \ +RUN echo "#!/bin/bash\nservice redis-server start &\nexec mpc-node start" > /start.sh \ && chmod +x /start.sh WORKDIR /usr/local/bin diff --git a/chain-signatures/node/redis.conf b/chain-signatures/node/redis.conf index 85706cb01..4c98a8708 100644 --- a/chain-signatures/node/redis.conf +++ b/chain-signatures/node/redis.conf @@ -1,8 +1,1316 @@ -# Enable Append Only File (AOF) persistence +# Redis configuration file example. +# +# Note that in order to read the configuration file, Redis must be +# started with the file path as first argument: +# +# ./redis-server /path/to/redis.conf + +# Note on units: when memory size is needed, it is possible to specify +# it in the usual form of 1k 5GB 4M and so forth: +# +# 1k => 1000 bytes +# 1kb => 1024 bytes +# 1m => 1000000 bytes +# 1mb => 1024*1024 bytes +# 1g => 1000000000 bytes +# 1gb => 1024*1024*1024 bytes +# +# units are case insensitive so 1GB 1Gb 1gB are all the same. + +################################## INCLUDES ################################### + +# Include one or more other config files here. This is useful if you +# have a standard template that goes to all Redis servers but also need +# to customize a few per-server settings. Include files can include +# other files, so use this wisely. +# +# Notice option "include" won't be rewritten by command "CONFIG REWRITE" +# from admin or Redis Sentinel. Since Redis always uses the last processed +# line as value of a configuration directive, you'd better put includes +# at the beginning of this file to avoid overwriting config change at runtime. +# +# If instead you are interested in using includes to override configuration +# options, it is better to use include as the last line. +# +# include /path/to/local.conf +# include /path/to/other.conf + +################################## MODULES ##################################### + +# Load modules at startup. If the server is not able to load modules +# it will abort. It is possible to use multiple loadmodule directives. +# +# loadmodule /path/to/my_module.so +# loadmodule /path/to/other_module.so + +################################## NETWORK ##################################### + +# By default, if no "bind" configuration directive is specified, Redis listens +# for connections from all the network interfaces available on the server. +# It is possible to listen to just one or multiple selected interfaces using +# the "bind" configuration directive, followed by one or more IP addresses. +# +# Examples: +# +# bind 192.168.1.100 10.0.0.1 +# bind 127.0.0.1 ::1 +# +# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the +# internet, binding to all the interfaces is dangerous and will expose the +# instance to everybody on the internet. So by default we uncomment the +# following bind directive, that will force Redis to listen only into +# the IPv4 lookback interface address (this means Redis will be able to +# accept connections only from clients running into the same computer it +# is running). +# +# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES +# JUST COMMENT THE FOLLOWING LINE. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bind 127.0.0.1 + +# Protected mode is a layer of security protection, in order to avoid that +# Redis instances left open on the internet are accessed and exploited. +# +# When protected mode is on and if: +# +# 1) The server is not binding explicitly to a set of addresses using the +# "bind" directive. +# 2) No password is configured. +# +# The server only accepts connections from clients connecting from the +# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain +# sockets. +# +# By default protected mode is enabled. You should disable it only if +# you are sure you want clients from other hosts to connect to Redis +# even if no authentication is configured, nor a specific set of interfaces +# are explicitly listed using the "bind" directive. +protected-mode yes + +# Accept connections on the specified port, default is 6379 (IANA #815344). +# If port 0 is specified Redis will not listen on a TCP socket. +port 6379 + +# TCP listen() backlog. +# +# In high requests-per-second environments you need an high backlog in order +# to avoid slow clients connections issues. Note that the Linux kernel +# will silently truncate it to the value of /proc/sys/net/core/somaxconn so +# make sure to raise both the value of somaxconn and tcp_max_syn_backlog +# in order to get the desired effect. +tcp-backlog 511 + +# Unix socket. +# +# Specify the path for the Unix socket that will be used to listen for +# incoming connections. There is no default, so Redis will not listen +# on a unix socket when not specified. +# +# unixsocket /tmp/redis.sock +# unixsocketperm 700 + +# Close the connection after a client is idle for N seconds (0 to disable) +timeout 0 + +# TCP keepalive. +# +# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence +# of communication. This is useful for two reasons: +# +# 1) Detect dead peers. +# 2) Take the connection alive from the point of view of network +# equipment in the middle. +# +# On Linux, the specified value (in seconds) is the period used to send ACKs. +# Note that to close the connection the double of the time is needed. +# On other kernels the period depends on the kernel configuration. +# +# A reasonable value for this option is 300 seconds, which is the new +# Redis default starting with Redis 3.2.1. +tcp-keepalive 300 + +################################# GENERAL ##################################### + +# By default Redis does not run as a daemon. Use 'yes' if you need it. +# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. +daemonize no + +# If you run Redis from upstart or systemd, Redis can interact with your +# supervision tree. Options: +# supervised no - no supervision interaction +# supervised upstart - signal upstart by putting Redis into SIGSTOP mode +# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET +# supervised auto - detect upstart or systemd method based on +# UPSTART_JOB or NOTIFY_SOCKET environment variables +# Note: these supervision methods only signal "process is ready." +# They do not enable continuous liveness pings back to your supervisor. +supervised no + +# If a pid file is specified, Redis writes it where specified at startup +# and removes it at exit. +# +# When the server runs non daemonized, no pid file is created if none is +# specified in the configuration. When the server is daemonized, the pid file +# is used even if not specified, defaulting to "/var/run/redis.pid". +# +# Creating a pid file is best effort: if Redis is not able to create it +# nothing bad happens, the server will start and run normally. +pidfile /var/run/redis_6379.pid + +# Specify the server verbosity level. +# This can be one of: +# debug (a lot of information, useful for development/testing) +# verbose (many rarely useful info, but not a mess like the debug level) +# notice (moderately verbose, what you want in production probably) +# warning (only very important / critical messages are logged) +loglevel notice + +# Specify the log file name. Also the empty string can be used to force +# Redis to log on the standard output. Note that if you use standard +# output for logging but daemonize, logs will be sent to /dev/null +logfile "" + +# To enable logging to the system logger, just set 'syslog-enabled' to yes, +# and optionally update the other syslog parameters to suit your needs. +# syslog-enabled no + +# Specify the syslog identity. +# syslog-ident redis + +# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. +# syslog-facility local0 + +# Set the number of databases. The default database is DB 0, you can select +# a different one on a per-connection basis using SELECT where +# dbid is a number between 0 and 'databases'-1 +databases 16 + +# By default Redis shows an ASCII art logo only when started to log to the +# standard output and if the standard output is a TTY. Basically this means +# that normally a logo is displayed only in interactive sessions. +# +# However it is possible to force the pre-4.0 behavior and always show a +# ASCII art logo in startup logs by setting the following option to yes. +always-show-logo yes + +################################ SNAPSHOTTING ################################ +# +# Save the DB on disk: +# +# save +# +# Will save the DB if both the given number of seconds and the given +# number of write operations against the DB occurred. +# +# In the example below the behaviour will be to save: +# after 900 sec (15 min) if at least 1 key changed +# after 300 sec (5 min) if at least 10 keys changed +# after 60 sec if at least 10000 keys changed +# +# Note: you can disable saving completely by commenting out all "save" lines. +# +# It is also possible to remove all the previously configured save +# points by adding a save directive with a single empty string argument +# like in the following example: +# +# save "" + +save 900 1 +save 300 10 +save 60 10000 + +# By default Redis will stop accepting writes if RDB snapshots are enabled +# (at least one save point) and the latest background save failed. +# This will make the user aware (in a hard way) that data is not persisting +# on disk properly, otherwise chances are that no one will notice and some +# disaster will happen. +# +# If the background saving process will start working again Redis will +# automatically allow writes again. +# +# However if you have setup your proper monitoring of the Redis server +# and persistence, you may want to disable this feature so that Redis will +# continue to work as usual even if there are problems with disk, +# permissions, and so forth. +stop-writes-on-bgsave-error yes + +# Compress string objects using LZF when dump .rdb databases? +# For default that's set to 'yes' as it's almost always a win. +# If you want to save some CPU in the saving child set it to 'no' but +# the dataset will likely be bigger if you have compressible values or keys. +rdbcompression yes + +# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. +# This makes the format more resistant to corruption but there is a performance +# hit to pay (around 10%) when saving and loading RDB files, so you can disable it +# for maximum performances. +# +# RDB files created with checksum disabled have a checksum of zero that will +# tell the loading code to skip the check. +rdbchecksum yes + +# The filename where to dump the DB +dbfilename dump.rdb + +# The working directory. +# +# The DB will be written inside this directory, with the filename specified +# above using the 'dbfilename' configuration directive. +# +# The Append Only File will also be created inside this directory. +# +# Note that you must specify a directory here, not a file name. +dir /data + +################################# REPLICATION ################################# + +# Master-Slave replication. Use slaveof to make a Redis instance a copy of +# another Redis server. A few things to understand ASAP about Redis replication. +# +# 1) Redis replication is asynchronous, but you can configure a master to +# stop accepting writes if it appears to be not connected with at least +# a given number of slaves. +# 2) Redis slaves are able to perform a partial resynchronization with the +# master if the replication link is lost for a relatively small amount of +# time. You may want to configure the replication backlog size (see the next +# sections of this file) with a sensible value depending on your needs. +# 3) Replication is automatic and does not need user intervention. After a +# network partition slaves automatically try to reconnect to masters +# and resynchronize with them. +# +# slaveof + +# If the master is password protected (using the "requirepass" configuration +# directive below) it is possible to tell the slave to authenticate before +# starting the replication synchronization process, otherwise the master will +# refuse the slave request. +# +# masterauth + +# When a slave loses its connection with the master, or when the replication +# is still in progress, the slave can act in two different ways: +# +# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will +# still reply to client requests, possibly with out of date data, or the +# data set may just be empty if this is the first synchronization. +# +# 2) if slave-serve-stale-data is set to 'no' the slave will reply with +# an error "SYNC with master in progress" to all the kind of commands +# but to INFO and SLAVEOF. +# +slave-serve-stale-data yes + +# You can configure a slave instance to accept writes or not. Writing against +# a slave instance may be useful to store some ephemeral data (because data +# written on a slave will be easily deleted after resync with the master) but +# may also cause problems if clients are writing to it because of a +# misconfiguration. +# +# Since Redis 2.6 by default slaves are read-only. +# +# Note: read only slaves are not designed to be exposed to untrusted clients +# on the internet. It's just a protection layer against misuse of the instance. +# Still a read only slave exports by default all the administrative commands +# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve +# security of read only slaves using 'rename-command' to shadow all the +# administrative / dangerous commands. +slave-read-only yes + +# Replication SYNC strategy: disk or socket. +# +# ------------------------------------------------------- +# WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY +# ------------------------------------------------------- +# +# New slaves and reconnecting slaves that are not able to continue the replication +# process just receiving differences, need to do what is called a "full +# synchronization". An RDB file is transmitted from the master to the slaves. +# The transmission can happen in two different ways: +# +# 1) Disk-backed: The Redis master creates a new process that writes the RDB +# file on disk. Later the file is transferred by the parent +# process to the slaves incrementally. +# 2) Diskless: The Redis master creates a new process that directly writes the +# RDB file to slave sockets, without touching the disk at all. +# +# With disk-backed replication, while the RDB file is generated, more slaves +# can be queued and served with the RDB file as soon as the current child producing +# the RDB file finishes its work. With diskless replication instead once +# the transfer starts, new slaves arriving will be queued and a new transfer +# will start when the current one terminates. +# +# When diskless replication is used, the master waits a configurable amount of +# time (in seconds) before starting the transfer in the hope that multiple slaves +# will arrive and the transfer can be parallelized. +# +# With slow disks and fast (large bandwidth) networks, diskless replication +# works better. +repl-diskless-sync no + +# When diskless replication is enabled, it is possible to configure the delay +# the server waits in order to spawn the child that transfers the RDB via socket +# to the slaves. +# +# This is important since once the transfer starts, it is not possible to serve +# new slaves arriving, that will be queued for the next RDB transfer, so the server +# waits a delay in order to let more slaves arrive. +# +# The delay is specified in seconds, and by default is 5 seconds. To disable +# it entirely just set it to 0 seconds and the transfer will start ASAP. +repl-diskless-sync-delay 5 + +# Slaves send PINGs to server in a predefined interval. It's possible to change +# this interval with the repl_ping_slave_period option. The default value is 10 +# seconds. +# +# repl-ping-slave-period 10 + +# The following option sets the replication timeout for: +# +# 1) Bulk transfer I/O during SYNC, from the point of view of slave. +# 2) Master timeout from the point of view of slaves (data, pings). +# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings). +# +# It is important to make sure that this value is greater than the value +# specified for repl-ping-slave-period otherwise a timeout will be detected +# every time there is low traffic between the master and the slave. +# +# repl-timeout 60 + +# Disable TCP_NODELAY on the slave socket after SYNC? +# +# If you select "yes" Redis will use a smaller number of TCP packets and +# less bandwidth to send data to slaves. But this can add a delay for +# the data to appear on the slave side, up to 40 milliseconds with +# Linux kernels using a default configuration. +# +# If you select "no" the delay for data to appear on the slave side will +# be reduced but more bandwidth will be used for replication. +# +# By default we optimize for low latency, but in very high traffic conditions +# or when the master and slaves are many hops away, turning this to "yes" may +# be a good idea. +repl-disable-tcp-nodelay no + +# Set the replication backlog size. The backlog is a buffer that accumulates +# slave data when slaves are disconnected for some time, so that when a slave +# wants to reconnect again, often a full resync is not needed, but a partial +# resync is enough, just passing the portion of data the slave missed while +# disconnected. +# +# The bigger the replication backlog, the longer the time the slave can be +# disconnected and later be able to perform a partial resynchronization. +# +# The backlog is only allocated once there is at least a slave connected. +# +# repl-backlog-size 1mb + +# After a master has no longer connected slaves for some time, the backlog +# will be freed. The following option configures the amount of seconds that +# need to elapse, starting from the time the last slave disconnected, for +# the backlog buffer to be freed. +# +# Note that slaves never free the backlog for timeout, since they may be +# promoted to masters later, and should be able to correctly "partially +# resynchronize" with the slaves: hence they should always accumulate backlog. +# +# A value of 0 means to never release the backlog. +# +# repl-backlog-ttl 3600 + +# The slave priority is an integer number published by Redis in the INFO output. +# It is used by Redis Sentinel in order to select a slave to promote into a +# master if the master is no longer working correctly. +# +# A slave with a low priority number is considered better for promotion, so +# for instance if there are three slaves with priority 10, 100, 25 Sentinel will +# pick the one with priority 10, that is the lowest. +# +# However a special priority of 0 marks the slave as not able to perform the +# role of master, so a slave with priority of 0 will never be selected by +# Redis Sentinel for promotion. +# +# By default the priority is 100. +slave-priority 100 + +# It is possible for a master to stop accepting writes if there are less than +# N slaves connected, having a lag less or equal than M seconds. +# +# The N slaves need to be in "online" state. +# +# The lag in seconds, that must be <= the specified value, is calculated from +# the last ping received from the slave, that is usually sent every second. +# +# This option does not GUARANTEE that N replicas will accept the write, but +# will limit the window of exposure for lost writes in case not enough slaves +# are available, to the specified number of seconds. +# +# For example to require at least 3 slaves with a lag <= 10 seconds use: +# +# min-slaves-to-write 3 +# min-slaves-max-lag 10 +# +# Setting one or the other to 0 disables the feature. +# +# By default min-slaves-to-write is set to 0 (feature disabled) and +# min-slaves-max-lag is set to 10. + +# A Redis master is able to list the address and port of the attached +# slaves in different ways. For example the "INFO replication" section +# offers this information, which is used, among other tools, by +# Redis Sentinel in order to discover slave instances. +# Another place where this info is available is in the output of the +# "ROLE" command of a master. +# +# The listed IP and address normally reported by a slave is obtained +# in the following way: +# +# IP: The address is auto detected by checking the peer address +# of the socket used by the slave to connect with the master. +# +# Port: The port is communicated by the slave during the replication +# handshake, and is normally the port that the slave is using to +# list for connections. +# +# However when port forwarding or Network Address Translation (NAT) is +# used, the slave may be actually reachable via different IP and port +# pairs. The following two options can be used by a slave in order to +# report to its master a specific set of IP and port, so that both INFO +# and ROLE will report those values. +# +# There is no need to use both the options if you need to override just +# the port or the IP address. +# +# slave-announce-ip 5.5.5.5 +# slave-announce-port 1234 + +################################## SECURITY ################################### + +# Require clients to issue AUTH before processing any other +# commands. This might be useful in environments in which you do not trust +# others with access to the host running redis-server. +# +# This should stay commented out for backward compatibility and because most +# people do not need auth (e.g. they run their own servers). +# +# Warning: since Redis is pretty fast an outside user can try up to +# 150k passwords per second against a good box. This means that you should +# use a very strong password otherwise it will be very easy to break. +# +# requirepass foobared + +# Command renaming. +# +# It is possible to change the name of dangerous commands in a shared +# environment. For instance the CONFIG command may be renamed into something +# hard to guess so that it will still be available for internal-use tools +# but not available for general clients. +# +# Example: +# +# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 +# +# It is also possible to completely kill a command by renaming it into +# an empty string: +# +# rename-command CONFIG "" +# +# Please note that changing the name of commands that are logged into the +# AOF file or transmitted to slaves may cause problems. + +################################### CLIENTS #################################### + +# Set the max number of connected clients at the same time. By default +# this limit is set to 10000 clients, however if the Redis server is not +# able to configure the process file limit to allow for the specified limit +# the max number of allowed clients is set to the current file limit +# minus 32 (as Redis reserves a few file descriptors for internal uses). +# +# Once the limit is reached Redis will close all the new connections sending +# an error 'max number of clients reached'. +# +# maxclients 10000 + +############################## MEMORY MANAGEMENT ################################ + +# Set a memory usage limit to the specified amount of bytes. +# When the memory limit is reached Redis will try to remove keys +# according to the eviction policy selected (see maxmemory-policy). +# +# If Redis can't remove keys according to the policy, or if the policy is +# set to 'noeviction', Redis will start to reply with errors to commands +# that would use more memory, like SET, LPUSH, and so on, and will continue +# to reply to read-only commands like GET. +# +# This option is usually useful when using Redis as an LRU or LFU cache, or to +# set a hard memory limit for an instance (using the 'noeviction' policy). +# +# WARNING: If you have slaves attached to an instance with maxmemory on, +# the size of the output buffers needed to feed the slaves are subtracted +# from the used memory count, so that network problems / resyncs will +# not trigger a loop where keys are evicted, and in turn the output +# buffer of slaves is full with DELs of keys evicted triggering the deletion +# of more keys, and so forth until the database is completely emptied. +# +# In short... if you have slaves attached it is suggested that you set a lower +# limit for maxmemory so that there is some free RAM on the system for slave +# output buffers (but this is not needed if the policy is 'noeviction'). +# +# maxmemory + +# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory +# is reached. You can select among five behaviors: +# +# volatile-lru -> Evict using approximated LRU among the keys with an expire set. +# allkeys-lru -> Evict any key using approximated LRU. +# volatile-lfu -> Evict using approximated LFU among the keys with an expire set. +# allkeys-lfu -> Evict any key using approximated LFU. +# volatile-random -> Remove a random key among the ones with an expire set. +# allkeys-random -> Remove a random key, any key. +# volatile-ttl -> Remove the key with the nearest expire time (minor TTL) +# noeviction -> Don't evict anything, just return an error on write operations. +# +# LRU means Least Recently Used +# LFU means Least Frequently Used +# +# Both LRU, LFU and volatile-ttl are implemented using approximated +# randomized algorithms. +# +# Note: with any of the above policies, Redis will return an error on write +# operations, when there are no suitable keys for eviction. +# +# At the date of writing these commands are: set setnx setex append +# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd +# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby +# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby +# getset mset msetnx exec sort +# +# The default is: +# +# maxmemory-policy noeviction + +# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated +# algorithms (in order to save memory), so you can tune it for speed or +# accuracy. For default Redis will check five keys and pick the one that was +# used less recently, you can change the sample size using the following +# configuration directive. +# +# The default of 5 produces good enough results. 10 Approximates very closely +# true LRU but costs more CPU. 3 is faster but not very accurate. +# +# maxmemory-samples 5 + +############################# LAZY FREEING #################################### + +# Redis has two primitives to delete keys. One is called DEL and is a blocking +# deletion of the object. It means that the server stops processing new commands +# in order to reclaim all the memory associated with an object in a synchronous +# way. If the key deleted is associated with a small object, the time needed +# in order to execute the DEL command is very small and comparable to most other +# O(1) or O(log_N) commands in Redis. However if the key is associated with an +# aggregated value containing millions of elements, the server can block for +# a long time (even seconds) in order to complete the operation. +# +# For the above reasons Redis also offers non blocking deletion primitives +# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and +# FLUSHDB commands, in order to reclaim memory in background. Those commands +# are executed in constant time. Another thread will incrementally free the +# object in the background as fast as possible. +# +# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled. +# It's up to the design of the application to understand when it is a good +# idea to use one or the other. However the Redis server sometimes has to +# delete keys or flush the whole database as a side effect of other operations. +# Specifically Redis deletes objects independently of a user call in the +# following scenarios: +# +# 1) On eviction, because of the maxmemory and maxmemory policy configurations, +# in order to make room for new data, without going over the specified +# memory limit. +# 2) Because of expire: when a key with an associated time to live (see the +# EXPIRE command) must be deleted from memory. +# 3) Because of a side effect of a command that stores data on a key that may +# already exist. For example the RENAME command may delete the old key +# content when it is replaced with another one. Similarly SUNIONSTORE +# or SORT with STORE option may delete existing keys. The SET command +# itself removes any old content of the specified key in order to replace +# it with the specified string. +# 4) During replication, when a slave performs a full resynchronization with +# its master, the content of the whole database is removed in order to +# load the RDB file just transfered. +# +# In all the above cases the default is to delete objects in a blocking way, +# like if DEL was called. However you can configure each case specifically +# in order to instead release memory in a non-blocking way like if UNLINK +# was called, using the following configuration directives: + +lazyfree-lazy-eviction no +lazyfree-lazy-expire no +lazyfree-lazy-server-del no +slave-lazy-flush no + +############################## APPEND ONLY MODE ############################### + +# By default Redis asynchronously dumps the dataset on disk. This mode is +# good enough in many applications, but an issue with the Redis process or +# a power outage may result into a few minutes of writes lost (depending on +# the configured save points). +# +# The Append Only File is an alternative persistence mode that provides +# much better durability. For instance using the default data fsync policy +# (see later in the config file) Redis can lose just one second of writes in a +# dramatic event like a server power outage, or a single write if something +# wrong with the Redis process itself happens, but the operating system is +# still running correctly. +# +# AOF and RDB persistence can be enabled at the same time without problems. +# If the AOF is enabled on startup Redis will load the AOF, that is the file +# with the better durability guarantees. +# +# Please check http://redis.io/topics/persistence for more information. + appendonly yes -# Set the appendfsync policy to flush the AOF every second +# The name of the append only file (default: "appendonly.aof") + +appendfilename "appendonly.aof" + +# The fsync() call tells the Operating System to actually write data on disk +# instead of waiting for more data in the output buffer. Some OS will really flush +# data on disk, some other OS will just try to do it ASAP. +# +# Redis supports three different modes: +# +# no: don't fsync, just let the OS flush the data when it wants. Faster. +# always: fsync after every write to the append only log. Slow, Safest. +# everysec: fsync only one time every second. Compromise. +# +# The default is "everysec", as that's usually the right compromise between +# speed and data safety. It's up to you to understand if you can relax this to +# "no" that will let the operating system flush the output buffer when +# it wants, for better performances (but if you can live with the idea of +# some data loss consider the default persistence mode that's snapshotting), +# or on the contrary, use "always" that's very slow but a bit safer than +# everysec. +# +# More details please check the following article: +# http://antirez.com/post/redis-persistence-demystified.html +# +# If unsure, use "everysec". + +# appendfsync always appendfsync everysec +# appendfsync no -# Set the directory for persistence -dir /data +# When the AOF fsync policy is set to always or everysec, and a background +# saving process (a background save or AOF log background rewriting) is +# performing a lot of I/O against the disk, in some Linux configurations +# Redis may block too long on the fsync() call. Note that there is no fix for +# this currently, as even performing fsync in a different thread will block +# our synchronous write(2) call. +# +# In order to mitigate this problem it's possible to use the following option +# that will prevent fsync() from being called in the main process while a +# BGSAVE or BGREWRITEAOF is in progress. +# +# This means that while another child is saving, the durability of Redis is +# the same as "appendfsync none". In practical terms, this means that it is +# possible to lose up to 30 seconds of log in the worst scenario (with the +# default Linux settings). +# +# If you have latency problems turn this to "yes". Otherwise leave it as +# "no" that is the safest pick from the point of view of durability. + +no-appendfsync-on-rewrite no + +# Automatic rewrite of the append only file. +# Redis is able to automatically rewrite the log file implicitly calling +# BGREWRITEAOF when the AOF log size grows by the specified percentage. +# +# This is how it works: Redis remembers the size of the AOF file after the +# latest rewrite (if no rewrite has happened since the restart, the size of +# the AOF at startup is used). +# +# This base size is compared to the current size. If the current size is +# bigger than the specified percentage, the rewrite is triggered. Also +# you need to specify a minimal size for the AOF file to be rewritten, this +# is useful to avoid rewriting the AOF file even if the percentage increase +# is reached but it is still pretty small. +# +# Specify a percentage of zero in order to disable the automatic AOF +# rewrite feature. + +auto-aof-rewrite-percentage 100 +auto-aof-rewrite-min-size 64mb + +# An AOF file may be found to be truncated at the end during the Redis +# startup process, when the AOF data gets loaded back into memory. +# This may happen when the system where Redis is running +# crashes, especially when an ext4 filesystem is mounted without the +# data=ordered option (however this can't happen when Redis itself +# crashes or aborts but the operating system still works correctly). +# +# Redis can either exit with an error when this happens, or load as much +# data as possible (the default now) and start if the AOF file is found +# to be truncated at the end. The following option controls this behavior. +# +# If aof-load-truncated is set to yes, a truncated AOF file is loaded and +# the Redis server starts emitting a log to inform the user of the event. +# Otherwise if the option is set to no, the server aborts with an error +# and refuses to start. When the option is set to no, the user requires +# to fix the AOF file using the "redis-check-aof" utility before to restart +# the server. +# +# Note that if the AOF file will be found to be corrupted in the middle +# the server will still exit with an error. This option only applies when +# Redis will try to read more data from the AOF file but not enough bytes +# will be found. +aof-load-truncated yes + +# When rewriting the AOF file, Redis is able to use an RDB preamble in the +# AOF file for faster rewrites and recoveries. When this option is turned +# on the rewritten AOF file is composed of two different stanzas: +# +# [RDB file][AOF tail] +# +# When loading Redis recognizes that the AOF file starts with the "REDIS" +# string and loads the prefixed RDB file, and continues loading the AOF +# tail. +# +# This is currently turned off by default in order to avoid the surprise +# of a format change, but will at some point be used as the default. +aof-use-rdb-preamble no + +################################ LUA SCRIPTING ############################### + +# Max execution time of a Lua script in milliseconds. +# +# If the maximum execution time is reached Redis will log that a script is +# still in execution after the maximum allowed time and will start to +# reply to queries with an error. +# +# When a long running script exceeds the maximum execution time only the +# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be +# used to stop a script that did not yet called write commands. The second +# is the only way to shut down the server in the case a write command was +# already issued by the script but the user doesn't want to wait for the natural +# termination of the script. +# +# Set it to 0 or a negative value for unlimited execution without warnings. +lua-time-limit 5000 + +################################ REDIS CLUSTER ############################### +# +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however +# in order to mark it as "mature" we need to wait for a non trivial percentage +# of users to deploy it in production. +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# Normal Redis instances can't be part of a Redis Cluster; only nodes that are +# started as cluster nodes can. In order to start a Redis instance as a +# cluster node enable the cluster support uncommenting the following: +# +# cluster-enabled yes + +# Every cluster node has a cluster configuration file. This file is not +# intended to be edited by hand. It is created and updated by Redis nodes. +# Every Redis Cluster node requires a different cluster configuration file. +# Make sure that instances running in the same system do not have +# overlapping cluster configuration file names. +# +# cluster-config-file nodes-6379.conf + +# Cluster node timeout is the amount of milliseconds a node must be unreachable +# for it to be considered in failure state. +# Most other internal time limits are multiple of the node timeout. +# +# cluster-node-timeout 15000 + +# A slave of a failing master will avoid to start a failover if its data +# looks too old. +# +# There is no simple way for a slave to actually have an exact measure of +# its "data age", so the following two checks are performed: +# +# 1) If there are multiple slaves able to failover, they exchange messages +# in order to try to give an advantage to the slave with the best +# replication offset (more data from the master processed). +# Slaves will try to get their rank by offset, and apply to the start +# of the failover a delay proportional to their rank. +# +# 2) Every single slave computes the time of the last interaction with +# its master. This can be the last ping or command received (if the master +# is still in the "connected" state), or the time that elapsed since the +# disconnection with the master (if the replication link is currently down). +# If the last interaction is too old, the slave will not try to failover +# at all. +# +# The point "2" can be tuned by user. Specifically a slave will not perform +# the failover if, since the last interaction with the master, the time +# elapsed is greater than: +# +# (node-timeout * slave-validity-factor) + repl-ping-slave-period +# +# So for example if node-timeout is 30 seconds, and the slave-validity-factor +# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the +# slave will not try to failover if it was not able to talk with the master +# for longer than 310 seconds. +# +# A large slave-validity-factor may allow slaves with too old data to failover +# a master, while a too small value may prevent the cluster from being able to +# elect a slave at all. +# +# For maximum availability, it is possible to set the slave-validity-factor +# to a value of 0, which means, that slaves will always try to failover the +# master regardless of the last time they interacted with the master. +# (However they'll always try to apply a delay proportional to their +# offset rank). +# +# Zero is the only value able to guarantee that when all the partitions heal +# the cluster will always be able to continue. +# +# cluster-slave-validity-factor 10 + +# Cluster slaves are able to migrate to orphaned masters, that are masters +# that are left without working slaves. This improves the cluster ability +# to resist to failures as otherwise an orphaned master can't be failed over +# in case of failure if it has no working slaves. +# +# Slaves migrate to orphaned masters only if there are still at least a +# given number of other working slaves for their old master. This number +# is the "migration barrier". A migration barrier of 1 means that a slave +# will migrate only if there is at least 1 other working slave for its master +# and so forth. It usually reflects the number of slaves you want for every +# master in your cluster. +# +# Default is 1 (slaves migrate only if their masters remain with at least +# one slave). To disable migration just set it to a very large value. +# A value of 0 can be set but is useful only for debugging and dangerous +# in production. +# +# cluster-migration-barrier 1 + +# By default Redis Cluster nodes stop accepting queries if they detect there +# is at least an hash slot uncovered (no available node is serving it). +# This way if the cluster is partially down (for example a range of hash slots +# are no longer covered) all the cluster becomes, eventually, unavailable. +# It automatically returns available as soon as all the slots are covered again. +# +# However sometimes you want the subset of the cluster which is working, +# to continue to accept queries for the part of the key space that is still +# covered. In order to do so, just set the cluster-require-full-coverage +# option to no. +# +# cluster-require-full-coverage yes + +# This option, when set to yes, prevents slaves from trying to failover its +# master during master failures. However the master can still perform a +# manual failover, if forced to do so. +# +# This is useful in different scenarios, especially in the case of multiple +# data center operations, where we want one side to never be promoted if not +# in the case of a total DC failure. +# +# cluster-slave-no-failover no + +# In order to setup your cluster make sure to read the documentation +# available at http://redis.io web site. + +########################## CLUSTER DOCKER/NAT support ######################## + +# In certain deployments, Redis Cluster nodes address discovery fails, because +# addresses are NAT-ted or because ports are forwarded (the typical case is +# Docker and other containers). +# +# In order to make Redis Cluster working in such environments, a static +# configuration where each node knows its public address is needed. The +# following two options are used for this scope, and are: +# +# * cluster-announce-ip +# * cluster-announce-port +# * cluster-announce-bus-port +# +# Each instruct the node about its address, client port, and cluster message +# bus port. The information is then published in the header of the bus packets +# so that other nodes will be able to correctly map the address of the node +# publishing the information. +# +# If the above options are not used, the normal Redis Cluster auto-detection +# will be used instead. +# +# Note that when remapped, the bus port may not be at the fixed offset of +# clients port + 10000, so you can specify any port and bus-port depending +# on how they get remapped. If the bus-port is not set, a fixed offset of +# 10000 will be used as usually. +# +# Example: +# +# cluster-announce-ip 10.1.1.5 +# cluster-announce-port 6379 +# cluster-announce-bus-port 6380 + +################################## SLOW LOG ################################### + +# The Redis Slow Log is a system to log queries that exceeded a specified +# execution time. The execution time does not include the I/O operations +# like talking with the client, sending the reply and so forth, +# but just the time needed to actually execute the command (this is the only +# stage of command execution where the thread is blocked and can not serve +# other requests in the meantime). +# +# You can configure the slow log with two parameters: one tells Redis +# what is the execution time, in microseconds, to exceed in order for the +# command to get logged, and the other parameter is the length of the +# slow log. When a new command is logged the oldest one is removed from the +# queue of logged commands. + +# The following time is expressed in microseconds, so 1000000 is equivalent +# to one second. Note that a negative number disables the slow log, while +# a value of zero forces the logging of every command. +slowlog-log-slower-than 10000 + +# There is no limit to this length. Just be aware that it will consume memory. +# You can reclaim memory used by the slow log with SLOWLOG RESET. +slowlog-max-len 128 + +################################ LATENCY MONITOR ############################## + +# The Redis latency monitoring subsystem samples different operations +# at runtime in order to collect data related to possible sources of +# latency of a Redis instance. +# +# Via the LATENCY command this information is available to the user that can +# print graphs and obtain reports. +# +# The system only logs operations that were performed in a time equal or +# greater than the amount of milliseconds specified via the +# latency-monitor-threshold configuration directive. When its value is set +# to zero, the latency monitor is turned off. +# +# By default latency monitoring is disabled since it is mostly not needed +# if you don't have latency issues, and collecting data has a performance +# impact, that while very small, can be measured under big load. Latency +# monitoring can easily be enabled at runtime using the command +# "CONFIG SET latency-monitor-threshold " if needed. +latency-monitor-threshold 0 + +############################# EVENT NOTIFICATION ############################## + +# Redis can notify Pub/Sub clients about events happening in the key space. +# This feature is documented at http://redis.io/topics/notifications +# +# For instance if keyspace events notification is enabled, and a client +# performs a DEL operation on key "foo" stored in the Database 0, two +# messages will be published via Pub/Sub: +# +# PUBLISH __keyspace@0__:foo del +# PUBLISH __keyevent@0__:del foo +# +# It is possible to select the events that Redis will notify among a set +# of classes. Every class is identified by a single character: +# +# K Keyspace events, published with __keyspace@__ prefix. +# E Keyevent events, published with __keyevent@__ prefix. +# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... +# $ String commands +# l List commands +# s Set commands +# h Hash commands +# z Sorted set commands +# x Expired events (events generated every time a key expires) +# e Evicted events (events generated when a key is evicted for maxmemory) +# A Alias for g$lshzxe, so that the "AKE" string means all the events. +# +# The "notify-keyspace-events" takes as argument a string that is composed +# of zero or multiple characters. The empty string means that notifications +# are disabled. +# +# Example: to enable list and generic events, from the point of view of the +# event name, use: +# +# notify-keyspace-events Elg +# +# Example 2: to get the stream of the expired keys subscribing to channel +# name __keyevent@0__:expired use: +# +# notify-keyspace-events Ex +# +# By default all notifications are disabled because most users don't need +# this feature and the feature has some overhead. Note that if you don't +# specify at least one of K or E, no events will be delivered. +notify-keyspace-events "" + +############################### ADVANCED CONFIG ############################### + +# Hashes are encoded using a memory efficient data structure when they have a +# small number of entries, and the biggest entry does not exceed a given +# threshold. These thresholds can be configured using the following directives. +hash-max-ziplist-entries 512 +hash-max-ziplist-value 64 + +# Lists are also encoded in a special way to save a lot of space. +# The number of entries allowed per internal list node can be specified +# as a fixed maximum size or a maximum number of elements. +# For a fixed maximum size, use -5 through -1, meaning: +# -5: max size: 64 Kb <-- not recommended for normal workloads +# -4: max size: 32 Kb <-- not recommended +# -3: max size: 16 Kb <-- probably not recommended +# -2: max size: 8 Kb <-- good +# -1: max size: 4 Kb <-- good +# Positive numbers mean store up to _exactly_ that number of elements +# per list node. +# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), +# but if your use case is unique, adjust the settings as necessary. +list-max-ziplist-size -2 + +# Lists may also be compressed. +# Compress depth is the number of quicklist ziplist nodes from *each* side of +# the list to *exclude* from compression. The head and tail of the list +# are always uncompressed for fast push/pop operations. Settings are: +# 0: disable all list compression +# 1: depth 1 means "don't start compressing until after 1 node into the list, +# going from either the head or tail" +# So: [head]->node->node->...->node->[tail] +# [head], [tail] will always be uncompressed; inner nodes will compress. +# 2: [head]->[next]->node->node->...->node->[prev]->[tail] +# 2 here means: don't compress head or head->next or tail->prev or tail, +# but compress all nodes between them. +# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] +# etc. +list-compress-depth 0 + +# Sets have a special encoding in just one case: when a set is composed +# of just strings that happen to be integers in radix 10 in the range +# of 64 bit signed integers. +# The following configuration setting sets the limit in the size of the +# set in order to use this special memory saving encoding. +set-max-intset-entries 512 + +# Similarly to hashes and lists, sorted sets are also specially encoded in +# order to save a lot of space. This encoding is only used when the length and +# elements of a sorted set are below the following limits: +zset-max-ziplist-entries 128 +zset-max-ziplist-value 64 + +# HyperLogLog sparse representation bytes limit. The limit includes the +# 16 bytes header. When an HyperLogLog using the sparse representation crosses +# this limit, it is converted into the dense representation. +# +# A value greater than 16000 is totally useless, since at that point the +# dense representation is more memory efficient. +# +# The suggested value is ~ 3000 in order to have the benefits of +# the space efficient encoding without slowing down too much PFADD, +# which is O(N) with the sparse encoding. The value can be raised to +# ~ 10000 when CPU is not a concern, but space is, and the data set is +# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. +hll-sparse-max-bytes 3000 + +# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in +# order to help rehashing the main Redis hash table (the one mapping top-level +# keys to values). The hash table implementation Redis uses (see dict.c) +# performs a lazy rehashing: the more operation you run into a hash table +# that is rehashing, the more rehashing "steps" are performed, so if the +# server is idle the rehashing is never complete and some more memory is used +# by the hash table. +# +# The default is to use this millisecond 10 times every second in order to +# actively rehash the main dictionaries, freeing memory when possible. +# +# If unsure: +# use "activerehashing no" if you have hard latency requirements and it is +# not a good thing in your environment that Redis can reply from time to time +# to queries with 2 milliseconds delay. +# +# use "activerehashing yes" if you don't have such hard requirements but +# want to free memory asap when possible. +activerehashing yes + +# The client output buffer limits can be used to force disconnection of clients +# that are not reading data from the server fast enough for some reason (a +# common reason is that a Pub/Sub client can't consume messages as fast as the +# publisher can produce them). +# +# The limit can be set differently for the three different classes of clients: +# +# normal -> normal clients including MONITOR clients +# slave -> slave clients +# pubsub -> clients subscribed to at least one pubsub channel or pattern +# +# The syntax of every client-output-buffer-limit directive is the following: +# +# client-output-buffer-limit +# +# A client is immediately disconnected once the hard limit is reached, or if +# the soft limit is reached and remains reached for the specified number of +# seconds (continuously). +# So for instance if the hard limit is 32 megabytes and the soft limit is +# 16 megabytes / 10 seconds, the client will get disconnected immediately +# if the size of the output buffers reach 32 megabytes, but will also get +# disconnected if the client reaches 16 megabytes and continuously overcomes +# the limit for 10 seconds. +# +# By default normal clients are not limited because they don't receive data +# without asking (in a push way), but just after a request, so only +# asynchronous clients may create a scenario where data is requested faster +# than it can read. +# +# Instead there is a default limit for pubsub and slave clients, since +# subscribers and slaves receive data in a push fashion. +# +# Both the hard or the soft limit can be disabled by setting them to zero. +client-output-buffer-limit normal 0 0 0 +client-output-buffer-limit slave 256mb 64mb 60 +client-output-buffer-limit pubsub 32mb 8mb 60 + +# Client query buffers accumulate new commands. They are limited to a fixed +# amount by default in order to avoid that a protocol desynchronization (for +# instance due to a bug in the client) will lead to unbound memory usage in +# the query buffer. However you can configure it here if you have very special +# needs, such us huge multi/exec requests or alike. +# +# client-query-buffer-limit 1gb + +# In the Redis protocol, bulk requests, that are, elements representing single +# strings, are normally limited ot 512 mb. However you can change this limit +# here. +# +# proto-max-bulk-len 512mb + +# Redis calls an internal function to perform many background tasks, like +# closing connections of clients in timeout, purging expired keys that are +# never requested, and so forth. +# +# Not all tasks are performed with the same frequency, but Redis checks for +# tasks to perform according to the specified "hz" value. +# +# By default "hz" is set to 10. Raising the value will use more CPU when +# Redis is idle, but at the same time will make Redis more responsive when +# there are many keys expiring at the same time, and timeouts may be +# handled with more precision. +# +# The range is between 1 and 500, however a value over 100 is usually not +# a good idea. Most users should use the default of 10 and raise this up to +# 100 only in environments where very low latency is required. +hz 10 + +# When a child rewrites the AOF file, if the following option is enabled +# the file will be fsync-ed every 32 MB of data generated. This is useful +# in order to commit the file to the disk more incrementally and avoid +# big latency spikes. +aof-rewrite-incremental-fsync yes + +# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good +# idea to start with the default settings and only change them after investigating +# how to improve the performances and how the keys LFU change over time, which +# is possible to inspect via the OBJECT FREQ command. +# +# There are two tunable parameters in the Redis LFU implementation: the +# counter logarithm factor and the counter decay time. It is important to +# understand what the two parameters mean before changing them. +# +# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis +# uses a probabilistic increment with logarithmic behavior. Given the value +# of the old counter, when a key is accessed, the counter is incremented in +# this way: +# +# 1. A random number R between 0 and 1 is extracted. +# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1). +# 3. The counter is incremented only if R < P. +# +# The default lfu-log-factor is 10. This is a table of how the frequency +# counter changes with a different number of accesses with different +# logarithmic factors: +# +# +--------+------------+------------+------------+------------+------------+ +# | factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits | +# +--------+------------+------------+------------+------------+------------+ +# | 0 | 104 | 255 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 1 | 18 | 49 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 10 | 10 | 18 | 142 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 100 | 8 | 11 | 49 | 143 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# +# NOTE: The above table was obtained by running the following commands: +# +# redis-benchmark -n 1000000 incr foo +# redis-cli object freq foo +# +# NOTE 2: The counter initial value is 5 in order to give new objects a chance +# to accumulate hits. +# +# The counter decay time is the time, in minutes, that must elapse in order +# for the key counter to be divided by two (or decremented if it has a value +# less <= 10). +# +# The default value for the lfu-decay-time is 1. A Special value of 0 means to +# decay the counter every time it happens to be scanned. +# +# lfu-log-factor 10 +# lfu-decay-time 1 + +########################### ACTIVE DEFRAGMENTATION ####################### +# +# WARNING THIS FEATURE IS EXPERIMENTAL. However it was stress tested +# even in production and manually tested by multiple engineers for some +# time. +# +# What is active defragmentation? +# ------------------------------- +# +# Active (online) defragmentation allows a Redis server to compact the +# spaces left between small allocations and deallocations of data in memory, +# thus allowing to reclaim back memory. +# +# Fragmentation is a natural process that happens with every allocator (but +# less so with Jemalloc, fortunately) and certain workloads. Normally a server +# restart is needed in order to lower the fragmentation, or at least to flush +# away all the data and create it again. However thanks to this feature +# implemented by Oran Agra for Redis 4.0 this process can happen at runtime +# in an "hot" way, while the server is running. +# +# Basically when the fragmentation is over a certain level (see the +# configuration options below) Redis will start to create new copies of the +# values in contiguous memory regions by exploiting certain specific Jemalloc +# features (in order to understand if an allocation is causing fragmentation +# and to allocate it in a better place), and at the same time, will release the +# old copies of the data. This process, repeated incrementally for all the keys +# will cause the fragmentation to drop back to normal values. +# +# Important things to understand: +# +# 1. This feature is disabled by default, and only works if you compiled Redis +# to use the copy of Jemalloc we ship with the source code of Redis. +# This is the default with Linux builds. +# +# 2. You never need to enable this feature if you don't have fragmentation +# issues. +# +# 3. Once you experience fragmentation, you can enable this feature when +# needed with the command "CONFIG SET activedefrag yes". +# +# The configuration parameters are able to fine tune the behavior of the +# defragmentation process. If you are not sure about what they mean it is +# a good idea to leave the defaults untouched. + +# Enabled active defragmentation +# activedefrag yes + +# Minimum amount of fragmentation waste to start active defrag +# active-defrag-ignore-bytes 100mb + +# Minimum percentage of fragmentation to start active defrag +# active-defrag-threshold-lower 10 + +# Maximum percentage of fragmentation at which we use maximum effort +# active-defrag-threshold-upper 100 + +# Minimal effort for defrag in CPU percentage +# active-defrag-cycle-min 25 + +# Maximal effort for defrag in CPU percentage +# active-defrag-cycle-max 75 From 596f13bab401fabab8c3c3842b4093fc72d55643 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 18 Oct 2024 13:36:31 +0300 Subject: [PATCH 26/64] unnecessary port expose removed --- Dockerfile.multichain | 3 --- integration-tests/chain-signatures/redis.conf | 8 -------- 2 files changed, 11 deletions(-) delete mode 100644 integration-tests/chain-signatures/redis.conf diff --git a/Dockerfile.multichain b/Dockerfile.multichain index fb24613b5..47aa197c5 100644 --- a/Dockerfile.multichain +++ b/Dockerfile.multichain @@ -33,8 +33,5 @@ RUN echo "#!/bin/bash\nservice redis-server start &\nexec mpc-node start" > /sta WORKDIR /usr/local/bin -# Expose Redis port (6379) and mpc node's port -EXPOSE 6379 8080 - # Start Redis and the Rust application ENTRYPOINT [ "/start.sh" ] diff --git a/integration-tests/chain-signatures/redis.conf b/integration-tests/chain-signatures/redis.conf deleted file mode 100644 index 85706cb01..000000000 --- a/integration-tests/chain-signatures/redis.conf +++ /dev/null @@ -1,8 +0,0 @@ -# Enable Append Only File (AOF) persistence -appendonly yes - -# Set the appendfsync policy to flush the AOF every second -appendfsync everysec - -# Set the directory for persistence -dir /data From 99126b5a6c5341f0faf2d432d99e54577ea41e82 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 18 Oct 2024 15:26:57 +0300 Subject: [PATCH 27/64] remove local redis config --- .github/workflows/multichain-integration.yml | 2 +- integration-tests/README.md | 2 +- .../chain-signatures/src/containers.rs | 17 +++-------------- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/.github/workflows/multichain-integration.yml b/.github/workflows/multichain-integration.yml index d0f03e6a9..20ba6457c 100644 --- a/.github/workflows/multichain-integration.yml +++ b/.github/workflows/multichain-integration.yml @@ -43,7 +43,7 @@ jobs: run: | docker pull ghcr.io/near/near-lake-indexer:node-2.3.0 docker pull localstack/localstack:3.5.0 - docker pull redis:7.2.5 + docker pull redis:7.0.15 - name: Install stable toolchain uses: actions-rs/toolchain@v1 diff --git a/integration-tests/README.md b/integration-tests/README.md index ff947addb..03a9db88d 100644 --- a/integration-tests/README.md +++ b/integration-tests/README.md @@ -7,7 +7,7 @@ Running integration tests requires you to have relayer and sandbox docker images ```BASH docker pull ghcr.io/near/os-relayer docker pull ghcr.io/near/sandbox -docker pull redis:7.2.5 +docker pull redis:7.0.15 ``` For M1 you may want to pull the following image instead: diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 610f71d18..04233da0a 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -631,26 +631,15 @@ pub struct Redis<'a> { impl<'a> Redis<'a> { pub const CONTAINER_PORT: u16 = 6379; - pub const HOST_CONFIG_PATH: &'static str = "./redis.conf"; - pub const CONTAINER_CONFIG_PATH: &'static str = "/usr/local/etc/redis/redis.conf"; pub async fn run(docker_client: &'a DockerClient, network: &str) -> anyhow::Result> { tracing::info!("Running Redis container..."); - let image = GenericImage::new("redis", "7.2.5") + let image = GenericImage::new("redis", "7.0.15") .with_wait_for(WaitFor::message_on_stdout("Ready to accept connections")) - .with_exposed_port(Self::CONTAINER_PORT) - .with_volume(Self::HOST_CONFIG_PATH, Self::CONTAINER_CONFIG_PATH); + .with_exposed_port(Self::CONTAINER_PORT); - // Pass the config file to Redis on startup - let image: RunnableImage = ( - image, - vec![ - "redis-server".to_string(), - Self::CONTAINER_CONFIG_PATH.to_string(), - ], - ) - .into(); + let image: RunnableImage = (image).into(); let image = image.with_network(network); From d46025316368f413a0514ccdd9c84153dc7354f8 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 18 Oct 2024 16:51:59 +0300 Subject: [PATCH 28/64] redis config update --- .../chain-signatures/src/containers.rs | 28 +++++++++---------- integration-tests/chain-signatures/src/lib.rs | 4 +-- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 04233da0a..70d327711 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -626,37 +626,35 @@ impl<'a> Datastore<'a> { pub struct Redis<'a> { pub container: Container<'a, GenericImage>, pub address: String, + pub full_address: String, pub local_address: String, } impl<'a> Redis<'a> { - pub const CONTAINER_PORT: u16 = 6379; + const CONTAINER_PORT: u16 = 3000; pub async fn run(docker_client: &'a DockerClient, network: &str) -> anyhow::Result> { tracing::info!("Running Redis container..."); - - let image = GenericImage::new("redis", "7.0.15") - .with_wait_for(WaitFor::message_on_stdout("Ready to accept connections")) - .with_exposed_port(Self::CONTAINER_PORT); - - let image: RunnableImage = (image).into(); - + let image = GenericImage::new("redis", "latest") + .with_exposed_port(Self::CONTAINER_PORT) + .with_wait_for(WaitFor::message_on_stdout("Ready to accept connections")); + let image: RunnableImage = image.into(); let image = image.with_network(network); - let container = docker_client.cli.run(image); - let ip_address = docker_client + let address = docker_client .get_network_ip_address(&container, network) .await?; + + // Note: this port is hardcoded in the Redis image + let full_address = format!("redis://{}:{}", address, 6379); let host_port = container.get_host_port_ipv4(Self::CONTAINER_PORT); - let full_address = format!("redis://{}:{}/", ip_address, Self::CONTAINER_PORT); - let local_address = format!("redis://127.0.0.1:{}/", host_port); tracing::info!("Redis container is running at {}", full_address); - Ok(Redis { container, - local_address, - address: full_address, + address, + full_address, + local_address: format!("http://127.0.0.1:{host_port}"), }) } } diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index ce4171f75..d124ac443 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -237,9 +237,7 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> crate::containers::Datastore::run(docker_client, docker_network, gcp_project_id).await?; let redis_container = crate::containers::Redis::run(docker_client, docker_network).await?; - let redis_url = redis_container.local_address.clone(); - - tracing::info!(%redis_url, "started Redis container"); + let redis_url = redis_container.full_address.clone(); let sk_share_local_path = "multichain-integration-secret-manager".to_string(); let storage_options = mpc_node::storage::Options { From 4a2c5a1a6da0862c6ebafedc27f27db77a7a5d83 Mon Sep 17 00:00:00 2001 From: kmaus-near Date: Fri, 18 Oct 2024 09:49:11 -0600 Subject: [PATCH 29/64] redis file ownership change --- Dockerfile.multichain | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Dockerfile.multichain b/Dockerfile.multichain index fb24613b5..5ae65777d 100644 --- a/Dockerfile.multichain +++ b/Dockerfile.multichain @@ -21,14 +21,13 @@ RUN cargo build --release --package mpc-node FROM debian:stable-slim as runtime RUN apt-get update && apt-get install --assume-yes libssl-dev ca-certificates curl redis-server -RUN update-ca-certificates \ - chown redis:redis /data +RUN update-ca-certificates COPY --from=builder /usr/src/app/target/release/mpc-node /usr/local/bin/mpc-node COPY chain-signatures/node/redis.conf /etc/redis/redis.conf # Create a script to start both Redis and the Rust app -RUN echo "#!/bin/bash\nservice redis-server start &\nexec mpc-node start" > /start.sh \ +RUN echo "#!/bin/bash\nchown redis:redis /data\nservice redis-server start &\nexec mpc-node start" > /start.sh \ && chmod +x /start.sh WORKDIR /usr/local/bin From 8e310a7b96709fa70fb938ac6b02438c928d395a Mon Sep 17 00:00:00 2001 From: kmaus-near Date: Fri, 18 Oct 2024 20:58:21 -0600 Subject: [PATCH 30/64] fix persistent data issue --- infra/multichain-dev/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/multichain-dev/main.tf b/infra/multichain-dev/main.tf index 81379e84e..72b579fe4 100644 --- a/infra/multichain-dev/main.tf +++ b/infra/multichain-dev/main.tf @@ -77,7 +77,7 @@ module "gce-container" { { name = "host-path" hostPath = { - path = "/etc/redis" + path = "/var/redis" } } ] From 701a4a57f59e88d521f03a6618d3b532ed1b4fa5 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Mon, 21 Oct 2024 18:35:52 +0300 Subject: [PATCH 31/64] fix redis unit test --- .../chain-signatures/src/containers.rs | 32 +++++++++++-------- integration-tests/chain-signatures/src/lib.rs | 2 +- .../chain-signatures/tests/cases/mod.rs | 2 +- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 70d327711..460d51d23 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -625,36 +625,40 @@ impl<'a> Datastore<'a> { pub struct Redis<'a> { pub container: Container<'a, GenericImage>, - pub address: String, - pub full_address: String, - pub local_address: String, + pub internal_address: String, + pub external_address: String, } impl<'a> Redis<'a> { - const CONTAINER_PORT: u16 = 3000; + const DEFAULT_REDIS_PORT: u16 = 6379; pub async fn run(docker_client: &'a DockerClient, network: &str) -> anyhow::Result> { tracing::info!("Running Redis container..."); - let image = GenericImage::new("redis", "latest") - .with_exposed_port(Self::CONTAINER_PORT) + let image = GenericImage::new("redis", "7.0.15") + .with_exposed_port(Self::DEFAULT_REDIS_PORT) .with_wait_for(WaitFor::message_on_stdout("Ready to accept connections")); let image: RunnableImage = image.into(); let image = image.with_network(network); let container = docker_client.cli.run(image); - let address = docker_client + let network_ip = docker_client .get_network_ip_address(&container, network) .await?; - // Note: this port is hardcoded in the Redis image - let full_address = format!("redis://{}:{}", address, 6379); - let host_port = container.get_host_port_ipv4(Self::CONTAINER_PORT); + let external_address = format!("redis://{}:{}", network_ip, Self::DEFAULT_REDIS_PORT); + + let host_port = container.get_host_port_ipv4(Self::DEFAULT_REDIS_PORT); + let internal_address = format!("redis://127.0.0.1:{host_port}"); + + tracing::info!( + "Redis container is running. External address: {}. Internal address: {}", + external_address, + internal_address + ); - tracing::info!("Redis container is running at {}", full_address); Ok(Redis { container, - address, - full_address, - local_address: format!("http://127.0.0.1:{host_port}"), + internal_address, + external_address, }) } } diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index d124ac443..6bc2ad5b6 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -237,7 +237,7 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> crate::containers::Datastore::run(docker_client, docker_network, gcp_project_id).await?; let redis_container = crate::containers::Redis::run(docker_client, docker_network).await?; - let redis_url = redis_container.full_address.clone(); + let redis_url = redis_container.internal_address.clone(); let sk_share_local_path = "multichain-integration-secret-manager".to_string(); let storage_options = mpc_node::storage::Options { diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 9507a4845..4a79177e7 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -242,7 +242,7 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { let docker_network = "test-presignature-persistence"; docker_client.create_network(docker_network).await?; let redis = containers::Redis::run(&docker_client, docker_network).await?; - let redis_url = Url::parse(redis.local_address.as_str())?; + let redis_url = Url::parse(&&redis.internal_address.as_str())?; let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new( storage::presignature_storage::init(redis_url, &AccountId::from_str("test.near").unwrap()), )); From 9aacb9ad6d1f4cb844188a19b74bac1e7ebf5429 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 22 Oct 2024 01:36:32 +0300 Subject: [PATCH 32/64] extend redis lifecycle --- integration-tests/chain-signatures/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 6bc2ad5b6..6b5da2ffa 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -207,6 +207,7 @@ pub struct Context<'a> { pub worker: Worker, pub mpc_contract: Contract, pub datastore: crate::containers::Datastore<'a>, + pub redis: crate::containers::Redis<'a>, pub storage_options: storage::Options, pub mesh_options: mesh::Options, pub message_options: http_client::Options, @@ -236,8 +237,8 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> let datastore = crate::containers::Datastore::run(docker_client, docker_network, gcp_project_id).await?; - let redis_container = crate::containers::Redis::run(docker_client, docker_network).await?; - let redis_url = redis_container.internal_address.clone(); + let redis = crate::containers::Redis::run(docker_client, docker_network).await?; + let redis_url = redis.internal_address.clone(); let sk_share_local_path = "multichain-integration-secret-manager".to_string(); let storage_options = mpc_node::storage::Options { @@ -265,6 +266,7 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> worker, mpc_contract, datastore, + redis, storage_options, mesh_options, message_options, From 01e678e28a025f23528332d2c25a079f52746d6e Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 22 Oct 2024 02:33:53 +0300 Subject: [PATCH 33/64] clippy --- integration-tests/chain-signatures/tests/cases/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 4a79177e7..fba7e4b7c 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -242,7 +242,7 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { let docker_network = "test-presignature-persistence"; docker_client.create_network(docker_network).await?; let redis = containers::Redis::run(&docker_client, docker_network).await?; - let redis_url = Url::parse(&&redis.internal_address.as_str())?; + let redis_url = Url::parse(redis.internal_address.as_str())?; let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new( storage::presignature_storage::init(redis_url, &AccountId::from_str("test.near").unwrap()), )); From 93c296a2352a49fe51afd5292059fe3c78130b9d Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 22 Oct 2024 19:31:36 +0300 Subject: [PATCH 34/64] datastore triple storage removed --- chain-signatures/node/src/cli.rs | 7 +- chain-signatures/node/src/lib.rs | 1 - .../node/src/protocol/consensus.rs | 4 +- chain-signatures/node/src/protocol/mod.rs | 8 +- chain-signatures/node/src/protocol/triple.rs | 21 +- .../node/src/storage/triple_storage.rs | 286 +------------ chain-signatures/node/src/test_utils.rs | 388 ------------------ integration-tests/chain-signatures/src/lib.rs | 13 +- .../chain-signatures/tests/cases/mod.rs | 28 +- 9 files changed, 35 insertions(+), 721 deletions(-) delete mode 100644 chain-signatures/node/src/test_utils.rs diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index f08c6c644..b081e4660 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -2,7 +2,7 @@ use crate::config::{Config, LocalConfig, NetworkConfig, OverrideConfig}; use crate::gcp::GcpService; use crate::protocol::{MpcSignProtocol, SignQueue}; use crate::storage::presignature_storage::LockRedisPresignatureStorage; -use crate::storage::triple_storage::LockTripleNodeStorageBox; +use crate::storage::triple_storage::LockMemoryTripleStorage; use crate::{http_client, indexer, mesh, storage, web}; use clap::Parser; use local_ip_address::local_ip; @@ -207,9 +207,8 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let key_storage = storage::secret_storage::init(Some(&gcp_service), &storage_options, &account_id); - let triple_storage: LockTripleNodeStorageBox = Arc::new(RwLock::new( - storage::triple_storage::init(Some(&gcp_service), &account_id), - )); + let triple_storage: LockMemoryTripleStorage = + Arc::new(RwLock::new(storage::triple_storage::init(&account_id))); let redis_url: Url = Url::parse(storage_options.redis_url.as_str())?; let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new( diff --git a/chain-signatures/node/src/lib.rs b/chain-signatures/node/src/lib.rs index 676e8a22a..5d1d7d058 100644 --- a/chain-signatures/node/src/lib.rs +++ b/chain-signatures/node/src/lib.rs @@ -9,7 +9,6 @@ pub mod metrics; pub mod protocol; pub mod rpc_client; pub mod storage; -pub mod test_utils; pub mod types; pub mod util; pub mod web; diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index 50cf67020..05452065c 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -15,7 +15,7 @@ use crate::protocol::state::{GeneratingState, ResharingState}; use crate::protocol::triple::TripleManager; use crate::storage::presignature_storage::LockRedisPresignatureStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::LockTripleNodeStorageBox; +use crate::storage::triple_storage::LockMemoryTripleStorage; use crate::storage::triple_storage::TripleData; use crate::types::{KeygenProtocol, ReshareProtocol, SecretKeyShare}; use crate::util::AffinePointExt; @@ -42,7 +42,7 @@ pub trait ConsensusCtx { fn my_address(&self) -> &Url; fn sign_queue(&self) -> Arc>; fn secret_storage(&self) -> &SecretNodeStorageBox; - fn triple_storage(&self) -> LockTripleNodeStorageBox; + fn triple_storage(&self) -> LockMemoryTripleStorage; fn presignature_storage(&self) -> LockRedisPresignatureStorage; fn cfg(&self) -> &Config; fn message_options(&self) -> http_client::Options; diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 6d407fef8..786973bcd 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -32,7 +32,7 @@ use crate::protocol::message::{MessageHandler, MpcMessageQueue}; use crate::rpc_client; use crate::storage::presignature_storage::LockRedisPresignatureStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::LockTripleNodeStorageBox; +use crate::storage::triple_storage::LockMemoryTripleStorage; use cait_sith::protocol::Participant; use near_account_id::AccountId; @@ -54,7 +54,7 @@ struct Ctx { http_client: reqwest::Client, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: LockTripleNodeStorageBox, + triple_storage: LockMemoryTripleStorage, presignature_storage: LockRedisPresignatureStorage, cfg: Config, mesh: Mesh, @@ -98,7 +98,7 @@ impl ConsensusCtx for &mut MpcSignProtocol { &self.ctx.cfg } - fn triple_storage(&self) -> LockTripleNodeStorageBox { + fn triple_storage(&self) -> LockMemoryTripleStorage { self.ctx.triple_storage.clone() } @@ -178,7 +178,7 @@ impl MpcSignProtocol { receiver: mpsc::Receiver, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: LockTripleNodeStorageBox, + triple_storage: LockMemoryTripleStorage, presignature_storage: LockRedisPresignatureStorage, cfg: Config, mesh_options: mesh::Options, diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index 13c294181..f899b2dfc 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -3,7 +3,7 @@ use super::cryptography::CryptographicError; use super::message::TripleMessage; use super::presignature::GenerationError; use crate::gcp::error; -use crate::storage::triple_storage::{LockTripleNodeStorageBox, TripleData}; +use crate::storage::triple_storage::{LockMemoryTripleStorage, TripleData}; use crate::types::TripleProtocol; use crate::util::AffinePointExt; @@ -106,7 +106,7 @@ pub struct TripleManager { pub me: Participant, pub threshold: usize, pub epoch: u64, - pub triple_storage: LockTripleNodeStorageBox, + pub triple_storage: LockMemoryTripleStorage, pub my_account_id: AccountId, } @@ -134,7 +134,7 @@ impl TripleManager { threshold: usize, epoch: u64, triple_data: Vec, - triple_storage: LockTripleNodeStorageBox, + triple_storage: LockMemoryTripleStorage, my_account_id: &AccountId, ) -> Self { let mut mine: VecDeque = VecDeque::new(); @@ -609,18 +609,3 @@ impl TripleManager { } } } - -#[cfg(test)] -mod test { - // TODO: This test currently takes 22 seconds on my machine, which is much slower than it should be - // Improve this before we make more similar tests - #[tokio::test] - async fn test_happy_triple_generation_locally() { - crate::test_utils::test_triple_generation(None).await - } - - #[tokio::test] - async fn test_triple_deletion_locally() { - crate::test_utils::test_triple_deletion(None).await - } -} diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index 4987dde50..73eefd64f 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -1,47 +1,23 @@ +use crate::gcp::error; +use crate::protocol::triple::{Triple, TripleId}; use std::collections::{HashMap, HashSet}; use std::sync::Arc; -use crate::gcp::{error, Keyable}; -use crate::gcp::{ - error::ConvertError, - value::{FromValue, IntoValue, Value}, - KeyKind, -}; -use crate::gcp::{DatastoreService, GcpService}; -use crate::protocol::triple::{Triple, TripleId}; - -use async_trait::async_trait; -use google_datastore1::api::{ - Filter, Key, PathElement, PropertyFilter, PropertyReference, Value as DatastoreValue, -}; use tokio::sync::RwLock; use near_account_id::AccountId; -pub struct TripleKey<'a> { - pub account_id: &'a str, - pub triple_id: TripleId, -} +pub type LockMemoryTripleStorage = Arc>; -impl KeyKind for TripleKey<'_> { - fn kind() -> String { - "triples".to_string() - } -} - -impl Keyable for TripleKey<'_> { - fn key(&self) -> Key { - Key { - path: Some(vec![PathElement { - kind: None, - name: Some(format!("{}/{}", self.account_id, self.triple_id)), - id: None, - }]), - partition_id: None, - } +pub fn init(account_id: &AccountId) -> TripleMemoryStorage { + TripleMemoryStorage { + triples: HashMap::new(), + mine: HashSet::new(), + account_id: account_id.clone(), } } +// TODO: do we need this stuct? #[derive(Clone, Debug)] pub struct TripleData { pub account_id: AccountId, @@ -49,132 +25,18 @@ pub struct TripleData { pub mine: bool, } -impl KeyKind for TripleData { - fn kind() -> String { - "triples".to_string() - } -} - -impl Keyable for TripleData { - fn key(&self) -> Key { - Key { - path: Some(vec![PathElement { - kind: None, - name: Some(format!("{}/{}", self.account_id, self.triple.id)), - id: None, - }]), - partition_id: None, - } - } -} - -impl IntoValue for TripleData { - fn into_value(self) -> Value { - let triple_key = TripleKey { - account_id: self.account_id.as_str(), - triple_id: self.triple.id, - }; - let mut properties = HashMap::new(); - properties.insert( - "account_id".to_string(), - Value::StringValue(self.account_id.to_string()), - ); - properties.insert( - "triple_id".to_string(), - Value::IntegerValue(self.triple.id as i64), - ); - properties.insert( - "triple_share".to_string(), - Value::StringValue(serde_json::to_string(&self.triple.share).unwrap()), - ); - properties.insert( - "triple_public".to_string(), - Value::StringValue(serde_json::to_string(&self.triple.public).unwrap()), - ); - properties.insert("mine".to_string(), Value::BooleanValue(self.mine)); - Value::EntityValue { - key: triple_key.key(), - properties, - } - } -} - -impl FromValue for TripleData { - fn from_value(value: Value) -> Result { - match value { - Value::EntityValue { mut properties, .. } => { - let (_, triple_id) = properties - .remove_entry("triple_id") - .ok_or_else(|| ConvertError::MissingProperty("triple_id".to_string()))?; - - let triple_id = i64::from_value(triple_id)?; - let (_, account_id) = properties - .remove_entry("account_id") - .ok_or_else(|| ConvertError::MissingProperty("account_id".to_string()))?; - let account_id = String::from_value(account_id)?.parse().map_err(|err| { - ConvertError::MalformedProperty(format!( - "TripleData failed to parse account_id: {err:?}" - )) - })?; - - let (_, triple_share) = properties - .remove_entry("triple_share") - .ok_or_else(|| ConvertError::MissingProperty("triple_share".to_string()))?; - let triple_share = String::from_value(triple_share)?; - let triple_share = serde_json::from_str(&triple_share) - .map_err(|_| ConvertError::MalformedProperty("triple_share".to_string()))?; - - let (_, triple_public) = properties - .remove_entry("triple_public") - .ok_or_else(|| ConvertError::MissingProperty("triple_public".to_string()))?; - let triple_public = String::from_value(triple_public)?; - let triple_public = serde_json::from_str(&triple_public) - .map_err(|_| ConvertError::MalformedProperty("triple_public".to_string()))?; - - let (_, mine) = properties - .remove_entry("mine") - .ok_or_else(|| ConvertError::MissingProperty("mine".to_string()))?; - let mine = bool::from_value(mine)?; - - Ok(Self { - account_id, - triple: Triple { - id: triple_id as u64, - share: triple_share, - public: triple_public, - }, - mine, - }) - } - value => Err(ConvertError::UnexpectedPropertyType { - expected: "entity".to_string(), - got: format!("{:?}", value), - }), - } - } -} - +// TODO: remove or refactor use of DatastoreStorageError type TripleResult = std::result::Result; -#[async_trait] -pub trait TripleNodeStorage { - async fn insert(&mut self, triple: Triple, mine: bool) -> TripleResult<()>; - async fn delete(&mut self, id: TripleId) -> TripleResult<()>; - async fn clear(&mut self) -> TripleResult>; - async fn load(&self) -> TripleResult>; - fn account_id(&self) -> &AccountId; -} - #[derive(Clone)] -struct MemoryTripleNodeStorage { +pub struct TripleMemoryStorage { triples: HashMap, mine: HashSet, account_id: AccountId, } -#[async_trait] -impl TripleNodeStorage for MemoryTripleNodeStorage { - async fn insert(&mut self, triple: Triple, mine: bool) -> TripleResult<()> { +impl TripleMemoryStorage { + pub async fn insert(&mut self, triple: Triple, mine: bool) -> TripleResult<()> { if mine { self.mine.insert(triple.id); } @@ -182,20 +44,20 @@ impl TripleNodeStorage for MemoryTripleNodeStorage { Ok(()) } - async fn delete(&mut self, id: TripleId) -> TripleResult<()> { + pub async fn delete(&mut self, id: TripleId) -> TripleResult<()> { self.triples.remove(&id); self.mine.remove(&id); Ok(()) } - async fn clear(&mut self) -> TripleResult> { + pub async fn clear(&mut self) -> TripleResult> { let res = self.load().await?; self.triples.clear(); self.mine.clear(); Ok(res) } - async fn load(&self) -> TripleResult> { + pub async fn load(&self) -> TripleResult> { let mut res: Vec = vec![]; for (triple_id, triple) in self.triples.clone() { let mine = self.mine.contains(&triple_id); @@ -208,121 +70,7 @@ impl TripleNodeStorage for MemoryTripleNodeStorage { Ok(res) } - fn account_id(&self) -> &AccountId { + pub fn account_id(&self) -> &AccountId { &self.account_id } } - -#[derive(Clone)] -struct DataStoreTripleNodeStorage { - datastore: DatastoreService, - account_id: AccountId, -} - -impl DataStoreTripleNodeStorage { - fn new(datastore: DatastoreService, account_id: &AccountId) -> Self { - Self { - datastore, - account_id: account_id.clone(), - } - } -} - -#[async_trait] -impl TripleNodeStorage for DataStoreTripleNodeStorage { - async fn insert(&mut self, triple: Triple, mine: bool) -> TripleResult<()> { - tracing::debug!(id = triple.id, "inserting triples using datastore"); - self.datastore - .upsert(TripleData { - account_id: self.account_id().clone(), - triple, - mine, - }) - .await?; - Ok(()) - } - - async fn delete(&mut self, id: TripleId) -> TripleResult<()> { - tracing::debug!(id, "deleting triples using datastore"); - self.datastore - .delete(TripleKey { - account_id: self.account_id.as_str(), - triple_id: id, - }) - .await?; - Ok(()) - } - - async fn clear(&mut self) -> TripleResult> { - let triples = self.load().await?; - self.datastore.delete_many(&triples).await?; - Ok(triples) - } - - async fn load(&self) -> TripleResult> { - tracing::debug!("loading triples using datastore"); - let filter = if self.datastore.is_emulator() { - None - } else { - Some(Filter { - composite_filter: None, - property_filter: Some(PropertyFilter { - op: Some("Equal".to_string()), - property: Some(PropertyReference { - name: Some("account_id".to_string()), - }), - value: Some(DatastoreValue::from_value( - self.account_id.as_str().into_value(), - )?), - }), - }) - }; - let response = self.datastore.fetch_entities::(filter).await?; - let mut res: Vec = vec![]; - for entity_result in response { - let entity = entity_result.entity.ok_or_else(|| { - error::DatastoreStorageError::FetchEntitiesError( - "entity was not able to unwrapped".to_string(), - ) - })?; - let triple_data = TripleData::from_value(entity.into_value())?; - if &triple_data.account_id == self.account_id() { - res.push(triple_data); - } - } - tracing::debug!(count = res.len(), "loading triples success"); - Ok(res) - } - - fn account_id(&self) -> &AccountId { - &self.account_id - } -} - -pub type TripleNodeStorageBox = Box; - -pub struct TripleStorage { - pub storage: TripleNodeStorageBox, -} - -pub type LockTripleNodeStorageBox = Arc>; - -pub fn init(gcp_service: Option<&GcpService>, account_id: &AccountId) -> TripleNodeStorageBox { - match gcp_service { - Some(gcp) => { - tracing::info!("using DataStoreTripleNodeStorage"); - Box::new(DataStoreTripleNodeStorage::new( - gcp.datastore.clone(), - account_id, - )) as TripleNodeStorageBox - } - _ => { - tracing::info!("using MemoryTripleNodeStorage"); - Box::new(MemoryTripleNodeStorage { - triples: HashMap::new(), - mine: HashSet::new(), - account_id: account_id.clone(), - }) as TripleNodeStorageBox - } - } -} diff --git a/chain-signatures/node/src/test_utils.rs b/chain-signatures/node/src/test_utils.rs deleted file mode 100644 index 8027295f5..000000000 --- a/chain-signatures/node/src/test_utils.rs +++ /dev/null @@ -1,388 +0,0 @@ -use crate::config::Config; -use crate::protocol::contract::primitives::Participants; -use crate::protocol::presignature::GenerationError; -use crate::protocol::triple::{Triple, TripleId, TripleManager}; -use crate::protocol::ParticipantInfo; -use crate::storage::triple_storage::LockTripleNodeStorageBox; -use crate::{gcp::GcpService, protocol::message::TripleMessage, storage}; - -use cait_sith::protocol::{InitializationError, Participant, ProtocolError}; -use std::io::prelude::*; -use std::{collections::HashMap, fs::OpenOptions, ops::Range}; - -use itertools::multiunzip; -use std::collections::VecDeque; -use std::sync::Arc; -use tokio::sync::RwLock; - -// Constants to be used for testing. -const STARTING_EPOCH: u64 = 0; - -struct TestTripleManagers { - managers: Vec, - participants: Participants, - config: Config, -} - -impl TestTripleManagers { - async fn new(num_managers: u32, datastore_url: Option) -> Self { - let mut participants = Participants::default(); - (0..num_managers) - .map(Participant::from) - .for_each(|p| participants.insert(&p, ParticipantInfo::new(p.into()))); - - let mut services = Vec::with_capacity(num_managers as usize); - for num in 0..num_managers { - let service = if let Some(url) = &datastore_url { - let account_id = format!("account_{num}.testnet").parse().unwrap(); - let storage_options = storage::Options { - gcp_project_id: "triple-test".to_string(), - sk_share_secret_id: None, - gcp_datastore_url: Some(url.clone()), - env: "triple-test".to_string(), - sk_share_local_path: None, - redis_url: "redis://localhost".to_string(), // not used - }; - Some( - GcpService::init(&account_id, &storage_options) - .await - .unwrap(), - ) - } else { - None - }; - services.push(service); - } - - let managers = (0..num_managers) - .map(|num| { - let account_id = format!("account_{num}.testnet").parse().unwrap(); - let triple_storage: LockTripleNodeStorageBox = Arc::new(RwLock::new( - storage::triple_storage::init(services[num as usize].as_ref(), &account_id), - )); - TripleManager::new( - Participant::from(num), - num_managers as usize, - STARTING_EPOCH, - vec![], - triple_storage, - &account_id, - ) - }) - .collect(); - TestTripleManagers { - managers, - participants, - config: Config::default(), - } - } - - fn generate(&mut self, index: usize) -> Result<(), InitializationError> { - self.managers[index].generate( - &self.participants, - self.config.protocol.triple.generation_timeout, - ) - } - - async fn poke(&mut self, index: usize) -> Result { - let mut quiet = true; - let messages = self.managers[index].poke(&self.config.protocol).await; - for ( - participant, - ref tm @ TripleMessage { - id, from, ref data, .. - }, - ) in messages - { - // Self::debug_mailbox(participant.into(), &tm); - quiet = false; - let participant_i: u32 = participant.into(); - let manager = &mut self.managers[participant_i as usize]; - if let Some(protocol) = manager - .get_or_generate(id, &self.participants, &self.config.protocol) - .unwrap() - { - protocol.message(from, data.to_vec()); - } else { - println!("Tried to write to completed mailbox {:?}", tm); - } - } - Ok(quiet) - } - - #[allow(unused)] - fn wipe_mailboxes(mailboxes: Range) { - for m in mailboxes { - let mut file = OpenOptions::new() - .write(true) - .append(false) - .create(true) - .open(format!("{}.csv", m)) - .unwrap(); - write!(file, "").unwrap(); - } - } - // This allows you to see what each node is recieving and when - #[allow(unused)] - fn debug_mailbox(participant: u32, TripleMessage { id, from, data, .. }: &TripleMessage) { - let mut file = OpenOptions::new() - .write(true) - .append(true) - .open(format!("{}.csv", participant)) - .unwrap(); - - writeln!(file, "'{id}, {from:?}, {}", hex::encode(data)).unwrap(); - } - - async fn poke_until_quiet(&mut self) -> Result<(), ProtocolError> { - loop { - let mut quiet = true; - for i in 0..self.managers.len() { - let poke = self.poke(i).await?; - quiet = quiet && poke; - } - if quiet { - return Ok(()); - } - } - } - - async fn take_two( - &mut self, - index: usize, - triple_id0: u64, - triple_id1: u64, - ) -> Result<(Triple, Triple), GenerationError> { - self.managers[index].take_two(triple_id0, triple_id1).await - } - - fn triples(&self, index: usize) -> HashMap { - self.managers[index].triples.clone() - } - - fn mine(&self, index: usize) -> VecDeque { - self.managers[index].mine.clone() - } - - fn triple_storage(&self, index: usize) -> LockTripleNodeStorageBox { - self.managers[index].triple_storage.clone() - } -} - -pub async fn test_triple_generation(datastore_url: Option) { - const M: usize = 2; - const N: usize = M + 3; - // Generate 5 triples - let mut tm = TestTripleManagers::new(5, datastore_url).await; - for _ in 0..M { - tm.generate(0).unwrap(); - } - tm.poke_until_quiet().await.unwrap(); - - tm.generate(1).unwrap(); - tm.generate(2).unwrap(); - tm.generate(4).unwrap(); - - tm.poke_until_quiet().await.unwrap(); - - let inputs = tm.managers.into_iter().map(|m| { - ( - m.count_mine(), - m.count(), - m.generators, - m.triples, - m.triple_storage, - m.mine, - ) - }); - - let (my_lens, lens, generators, mut triples, triple_stores, mines): ( - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - ) = multiunzip(inputs); - - assert_eq!( - my_lens.iter().sum::(), - N, - "There should be {N} owned completed triples in total", - ); - - for l in lens { - assert_eq!(l, N, "All nodes should have {N} completed triples") - } - - // This passes, but we don't have deterministic entropy or enough triples - // to ensure that it will no coincidentally fail - // TODO: deterministic entropy for testing - // assert_ne!( - // my_lens, - // vec![M, 1, 1, 0, 1], - // "The nodes that started the triple don't own it" - // ); - - for g in generators.iter() { - assert!(g.is_empty(), "There are no triples still being generated") - } - - assert_ne!( - triples.len(), - 1, - "The number of triples is not 1 before deduping" - ); - - // validates that the triples loaded from triple_storage is the same as the ones generated - for i in 0..triples.len() { - let local_mine = mines.get(i).unwrap(); - let local_triples = triples.get(i).unwrap(); - let triple_store = triple_stores.get(i).unwrap(); - - let datastore_loaded_triples = { - let triple_store = triple_store.read().await; - let datastore_loaded_triples = triple_store - .load() - .await - .expect("the triple loading result should return Ok"); - assert_eq!( - datastore_loaded_triples.len(), - local_triples.len(), - "the number of triples loaded from datastore and stored locally should match" - ); - datastore_loaded_triples - }; - - for loaded_triple_data in datastore_loaded_triples { - let loaded_triple = loaded_triple_data.triple; - assert!( - local_triples.contains_key(&loaded_triple.id), - "the loaded triple id should exist locally" - ); - let local_triple = local_triples.get(&loaded_triple.id).unwrap(); - assert_eq!( - local_triple.public, loaded_triple.public, - "local and datastore loaded triple should have same public field value." - ); - assert_eq!( - local_triple.share.a, loaded_triple.share.a, - "local and datastore loaded triple should have same share.a value." - ); - assert_eq!( - local_triple.share.b, loaded_triple.share.b, - "local and datastore loaded triple should have same share.b value." - ); - assert_eq!( - local_triple.share.c, loaded_triple.share.c, - "local and datastore loaded triple should have same share.c value." - ); - assert_eq!( - local_mine.contains(&loaded_triple.id), - loaded_triple_data.mine, - "local and datastore loaded triple should have same mine value." - ); - } - } - - triples.dedup_by_key(|kv| { - kv.iter_mut() - .map(|(id, triple)| (*id, (triple.id, triple.public.clone()))) - .collect::>() - }); - - assert_eq!( - triples.len(), - 1, - "All triple IDs and public parts are identical" - ) -} - -pub async fn test_triple_deletion(datastore_url: Option) { - // Generate 3 triples - let mut tm = TestTripleManagers::new(2, datastore_url).await; - for _ in 0..3 { - tm.generate(0).unwrap(); - } - tm.poke_until_quiet().await.unwrap(); - - for i in 0..2 { - let mut mine = tm.mine(i); - if mine.len() < 2 { - continue; - } - let id0 = mine.pop_front().unwrap(); - let id1 = mine.pop_front().unwrap(); - let triples = tm.triples(i); - assert_eq!(triples.len(), 3); - let triple0 = triples.get(&id0).unwrap(); - assert!( - tm.take_two(i, id0, id1).await.is_ok(), - "take_two for participant 0 should succeed for id0 and id1" - ); - - let triple_storage = tm.triple_storage(i); - { - let triple_storage = triple_storage.read().await; - let loaded_triples = triple_storage - .load() - .await - .expect("expected triples to load successfully"); - assert_eq!( - loaded_triples.len(), - 1, - "the triples left in store for participant 0 should be 1" - ); - } - - //verify that if in take_two, one of the triples were accidentally deleted, double deletion will not cause issue - { - let mut triple_storage = triple_storage.write().await; - let del_res_mine_false = triple_storage.delete(triple0.id).await; - let del_res_mine_true = triple_storage.delete(triple0.id).await; - assert!( - del_res_mine_false.is_ok() && del_res_mine_true.is_ok(), - "repeatedly deleting a triple won't err out" - ); - }; - - { - let triple_storage = triple_storage.read().await; - let loaded_triples = triple_storage - .load() - .await - .expect("expected to be able to load recently added triple"); - assert_eq!( - loaded_triples.len(), - 1, - "the triples left in store for participant 0 should still be 1" - ); - } - - //insert triple0 and delete it with the wrong mine value, that does not impact deletion success - { - let mut triple_storage = triple_storage.write().await; - triple_storage - .insert(triple0.clone(), true) - .await - .expect("expected insert to succeed"); - triple_storage - .delete(triple0.id) - .await - .expect("expected delete to succeed"); - } - - { - let triple_storage = triple_storage.read().await; - let loaded = triple_storage - .load() - .await - .expect("expected to be able to load at least one triple"); - assert_eq!( - loaded.len(), - 1, - "the triples left in store for participant 0 should still be 1" - ); - } - } -} diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 6b5da2ffa..84f6583cb 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -18,7 +18,7 @@ use mpc_node::gcp::GcpService; use mpc_node::http_client; use mpc_node::mesh; use mpc_node::storage; -use mpc_node::storage::triple_storage::TripleNodeStorageBox; +use mpc_node::storage::triple_storage::TripleMemoryStorage; use near_crypto::KeyFile; use near_workspaces::network::{Sandbox, ValidatorKey}; use near_workspaces::types::{KeyType, SecretKey}; @@ -155,15 +155,8 @@ impl Nodes<'_> { Ok(()) } - pub async fn triple_storage( - &self, - account_id: &AccountId, - ) -> anyhow::Result { - let gcp_service = GcpService::init(account_id, &self.ctx().storage_options).await?; - Ok(storage::triple_storage::init( - Some(&gcp_service), - account_id, - )) + pub async fn triple_storage(&self, account_id: &AccountId) -> TripleMemoryStorage { + storage::triple_storage::init(account_id) } pub async fn gcp_services(&self) -> anyhow::Result> { diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index fba7e4b7c..4f0d4a0cf 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -16,10 +16,10 @@ use mpc_contract::config::Config; use mpc_contract::update::ProposeUpdateArgs; use mpc_node::kdf::into_eth_sig; use mpc_node::protocol::presignature::{Presignature, PresignatureId, PresignatureManager}; +use mpc_node::storage; use mpc_node::storage::presignature_storage::LockRedisPresignatureStorage; use mpc_node::types::LatestBlockHeight; use mpc_node::util::NearPublicKeyExt; -use mpc_node::{storage, test_utils}; use near_account_id::AccountId; use test_log::test; use tokio::sync::RwLock; @@ -209,30 +209,8 @@ async fn test_key_derivation() -> anyhow::Result<()> { } #[test(tokio::test)] -async fn test_triples_persistence_for_generation() -> anyhow::Result<()> { - let docker_client = DockerClient::default(); - let gcp_project_id = "test-triple-persistence"; - let docker_network = "test-triple-persistence"; - docker_client.create_network(docker_network).await?; - let datastore = - containers::Datastore::run(&docker_client, docker_network, gcp_project_id).await?; - let datastore_url = datastore.local_address.clone(); - // verifies that @triple generation, the datastore triples are in sync with local generated triples - test_utils::test_triple_generation(Some(datastore_url.clone())).await; - Ok(()) -} - -#[test(tokio::test)] -async fn test_triples_persistence_for_deletion() -> anyhow::Result<()> { - let docker_client = DockerClient::default(); - let gcp_project_id = "test-triple-persistence"; - let docker_network = "test-triple-persistence"; - docker_client.create_network(docker_network).await?; - let datastore = - containers::Datastore::run(&docker_client, docker_network, gcp_project_id).await?; - let datastore_url = datastore.local_address.clone(); - // verifies that @triple deletion, the datastore is working as expected - test_utils::test_triple_deletion(Some(datastore_url)).await; +async fn test_triple_persistence() -> anyhow::Result<()> { + // TODO: add triple persistence test Ok(()) } From 2b6ad959411fd36068d4ed4cb48645c8e52b570e Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 23 Oct 2024 13:26:48 +0300 Subject: [PATCH 35/64] refactor triple storage --- chain-signatures/node/src/cli.rs | 4 +- .../node/src/protocol/consensus.rs | 57 +-- .../node/src/protocol/cryptography.rs | 7 +- chain-signatures/node/src/protocol/message.rs | 5 +- chain-signatures/node/src/protocol/mod.rs | 9 +- chain-signatures/node/src/protocol/monitor.rs | 80 ---- .../node/src/protocol/presignature.rs | 2 + chain-signatures/node/src/protocol/state.rs | 4 - chain-signatures/node/src/protocol/triple.rs | 369 +++++++++--------- .../node/src/storage/presignature_storage.rs | 11 + .../node/src/storage/triple_storage.rs | 80 ++-- chain-signatures/node/src/web/mod.rs | 6 +- 12 files changed, 259 insertions(+), 375 deletions(-) delete mode 100644 chain-signatures/node/src/protocol/monitor.rs diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index b081e4660..76ea5471e 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -2,7 +2,7 @@ use crate::config::{Config, LocalConfig, NetworkConfig, OverrideConfig}; use crate::gcp::GcpService; use crate::protocol::{MpcSignProtocol, SignQueue}; use crate::storage::presignature_storage::LockRedisPresignatureStorage; -use crate::storage::triple_storage::LockMemoryTripleStorage; +use crate::storage::triple_storage::LockTripleMemoryStorage; use crate::{http_client, indexer, mesh, storage, web}; use clap::Parser; use local_ip_address::local_ip; @@ -207,7 +207,7 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let key_storage = storage::secret_storage::init(Some(&gcp_service), &storage_options, &account_id); - let triple_storage: LockMemoryTripleStorage = + let triple_storage: LockTripleMemoryStorage = Arc::new(RwLock::new(storage::triple_storage::init(&account_id))); let redis_url: Url = Url::parse(storage_options.redis_url.as_str())?; diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index 05452065c..08405604d 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -8,15 +8,13 @@ use crate::gcp::error::DatastoreStorageError; use crate::gcp::error::SecretStorageError; use crate::http_client::MessageQueue; use crate::protocol::contract::primitives::Participants; -use crate::protocol::monitor::StuckMonitor; use crate::protocol::presignature::PresignatureManager; use crate::protocol::signature::SignatureManager; use crate::protocol::state::{GeneratingState, ResharingState}; use crate::protocol::triple::TripleManager; use crate::storage::presignature_storage::LockRedisPresignatureStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::LockMemoryTripleStorage; -use crate::storage::triple_storage::TripleData; +use crate::storage::triple_storage::LockTripleMemoryStorage; use crate::types::{KeygenProtocol, ReshareProtocol, SecretKeyShare}; use crate::util::AffinePointExt; use crate::{http_client, rpc_client}; @@ -42,7 +40,7 @@ pub trait ConsensusCtx { fn my_address(&self) -> &Url; fn sign_queue(&self) -> Arc>; fn secret_storage(&self) -> &SecretNodeStorageBox; - fn triple_storage(&self) -> LockMemoryTripleStorage; + fn triple_storage(&self) -> LockTripleMemoryStorage; fn presignature_storage(&self) -> LockRedisPresignatureStorage; fn cfg(&self) -> &Config; fn message_options(&self) -> http_client::Options; @@ -140,7 +138,6 @@ impl ConsensusProtocol for StartedState { me, contract_state.threshold, epoch, - self.triple_data, ctx.triple_storage(), ctx.my_account_id(), ))); @@ -162,10 +159,6 @@ impl ConsensusProtocol for StartedState { ctx.my_account_id(), ))); - let stuck_monitor = Arc::new(RwLock::new( - StuckMonitor::new(&triple_manager).await, - )); - Ok(NodeState::Running(RunningState { epoch, participants: contract_state.participants, @@ -173,7 +166,6 @@ impl ConsensusProtocol for StartedState { private_share, public_key, sign_queue, - stuck_monitor, triple_manager, presignature_manager, signature_manager, @@ -369,15 +361,24 @@ impl ConsensusProtocol for WaitingForConsensusState { // Clear triples from storage before starting the new epoch. This is necessary if the node has accumulated // triples from previous epochs. If it was not able to clear the previous triples, we'll leave them as-is - if let Err(err) = ctx.triple_storage().write().await.clear().await { - tracing::warn!(?err, "failed to clear triples from storage"); + if let Err(err) = ctx.triple_storage().write().await.clear() { + tracing::error!( + ?err, + "failed to clear triples from storage on new epoch start" + ); + } + + if let Err(err) = ctx.presignature_storage().write().await.clear() { + tracing::error!( + ?err, + "failed to clear presignatures from storage on new epoch start" + ); } let triple_manager = Arc::new(RwLock::new(TripleManager::new( me, self.threshold, self.epoch, - vec![], ctx.triple_storage(), ctx.my_account_id(), ))); @@ -397,9 +398,6 @@ impl ConsensusProtocol for WaitingForConsensusState { ctx.my_account_id(), ))); - let stuck_monitor = - Arc::new(RwLock::new(StuckMonitor::new(&triple_manager).await)); - Ok(NodeState::Running(RunningState { epoch: self.epoch, participants: self.participants, @@ -407,7 +405,6 @@ impl ConsensusProtocol for WaitingForConsensusState { private_share: self.private_share, public_key: self.public_key, sign_queue: ctx.sign_queue(), - stuck_monitor, triple_manager, presignature_manager, signature_manager, @@ -720,10 +717,8 @@ impl ConsensusProtocol for NodeState { match self { NodeState::Starting => { let persistent_node_data = ctx.secret_storage().load().await?; - let triple_data = load_triples(ctx).await?; Ok(NodeState::Started(StartedState { persistent_node_data, - triple_data, })) } NodeState::Started(state) => state.advance(ctx, contract_state).await, @@ -736,30 +731,6 @@ impl ConsensusProtocol for NodeState { } } -async fn load_triples( - ctx: C, -) -> Result, ConsensusError> { - let triple_storage = ctx.triple_storage(); - let mut retries = 3; - let mut error = None; - while retries > 0 { - match triple_storage.read().await.load().await { - Err(DatastoreStorageError::FetchEntitiesError(_)) => { - tracing::info!("There are no triples persisted."); - return Ok(vec![]); - } - Err(e) => { - retries -= 1; - tracing::warn!(?e, "triple load failed."); - error = Some(e); - tokio::time::sleep(std::time::Duration::from_millis(500)).await; - } - Ok(loaded_triples) => return Ok(loaded_triples), - } - } - Err(ConsensusError::DatastoreStorageError(error.unwrap())) -} - async fn start_resharing( private_share: Option, ctx: C, diff --git a/chain-signatures/node/src/protocol/cryptography.rs b/chain-signatures/node/src/protocol/cryptography.rs index 8f67670d6..85ea6b074 100644 --- a/chain-signatures/node/src/protocol/cryptography.rs +++ b/chain-signatures/node/src/protocol/cryptography.rs @@ -372,7 +372,7 @@ impl CryptographicProtocol for RunningState { crate::metrics::MESSAGE_QUEUE_SIZE .with_label_values(&[my_account_id.as_str()]) .set(messages.len() as i64); - if let Err(err) = triple_manager.stockpile(active, protocol_cfg) { + if let Err(err) = triple_manager.stockpile(active, protocol_cfg).await { tracing::warn!(?err, "running: failed to stockpile triples"); } for (p, msg) in triple_manager.poke(protocol_cfg).await { @@ -382,10 +382,10 @@ impl CryptographicProtocol for RunningState { crate::metrics::NUM_TRIPLES_MINE .with_label_values(&[my_account_id.as_str()]) - .set(triple_manager.mine.len() as i64); + .set(triple_manager.count_mine().await as i64); crate::metrics::NUM_TRIPLES_TOTAL .with_label_values(&[my_account_id.as_str()]) - .set(triple_manager.triples.len() as i64); + .set(triple_manager.count_all().await as i64); crate::metrics::NUM_TRIPLE_GENERATORS_INTRODUCED .with_label_values(&[my_account_id.as_str()]) .set(triple_manager.introduced.len() as i64); @@ -482,7 +482,6 @@ impl CryptographicProtocol for RunningState { } drop(messages); - self.stuck_monitor.write().await.check(protocol_cfg).await; Ok(NodeState::Running(self)) } } diff --git a/chain-signatures/node/src/protocol/message.rs b/chain-signatures/node/src/protocol/message.rs index fd4b67791..91ad7f01f 100644 --- a/chain-signatures/node/src/protocol/message.rs +++ b/chain-signatures/node/src/protocol/message.rs @@ -256,7 +256,10 @@ impl MessageHandler for RunningState { !triple_manager.refresh_gc(id) }); for (id, queue) in triple_messages { - let protocol = match triple_manager.get_or_generate(*id, participants, protocol_cfg) { + let protocol = match triple_manager + .get_or_start_generation(*id, participants, protocol_cfg) + .await + { Ok(protocol) => protocol, Err(err) => { // ignore the message since the generation had bad parameters. Also have the other node who diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 786973bcd..7e18e91a0 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -3,7 +3,6 @@ mod cryptography; pub mod consensus; pub mod contract; pub mod message; -pub mod monitor; pub mod presignature; pub mod signature; pub mod state; @@ -32,7 +31,7 @@ use crate::protocol::message::{MessageHandler, MpcMessageQueue}; use crate::rpc_client; use crate::storage::presignature_storage::LockRedisPresignatureStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::LockMemoryTripleStorage; +use crate::storage::triple_storage::LockTripleMemoryStorage; use cait_sith::protocol::Participant; use near_account_id::AccountId; @@ -54,7 +53,7 @@ struct Ctx { http_client: reqwest::Client, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: LockMemoryTripleStorage, + triple_storage: LockTripleMemoryStorage, presignature_storage: LockRedisPresignatureStorage, cfg: Config, mesh: Mesh, @@ -98,7 +97,7 @@ impl ConsensusCtx for &mut MpcSignProtocol { &self.ctx.cfg } - fn triple_storage(&self) -> LockMemoryTripleStorage { + fn triple_storage(&self) -> LockTripleMemoryStorage { self.ctx.triple_storage.clone() } @@ -178,7 +177,7 @@ impl MpcSignProtocol { receiver: mpsc::Receiver, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: LockMemoryTripleStorage, + triple_storage: LockTripleMemoryStorage, presignature_storage: LockRedisPresignatureStorage, cfg: Config, mesh_options: mesh::Options, diff --git a/chain-signatures/node/src/protocol/monitor.rs b/chain-signatures/node/src/protocol/monitor.rs deleted file mode 100644 index a6096d47f..000000000 --- a/chain-signatures/node/src/protocol/monitor.rs +++ /dev/null @@ -1,80 +0,0 @@ -use mpc_contract::config::ProtocolConfig; -use std::collections::HashSet; -use std::sync::Arc; -use std::time::{Duration, Instant}; -use tokio::sync::RwLock; - -use super::triple::{TripleId, TripleManager}; - -/// Amount of time to wait before we can say that the protocol is stuck. -const STUCK_TIMEOUT_THRESHOLD: Duration = Duration::from_secs(120); - -/// While being stuck, report that the node is stuck every interval. This should not be higher -/// than STUCK_TIMEOUT_THRESHOLD due to how they are currently coupled in the following code. -const STUCK_REPORT_INTERVAL: Duration = Duration::from_secs(90); - -pub struct StuckMonitor { - triple_manager: Arc>, - last_checked_triples: HashSet, - last_changed_timestamp: Instant, - stuck_interval_timestamp: Instant, -} - -impl StuckMonitor { - pub async fn new(triple_manager: &Arc>) -> Self { - Self { - triple_manager: triple_manager.clone(), - last_checked_triples: triple_manager - .read() - .await - .triples - .keys() - .cloned() - .collect(), - last_changed_timestamp: Instant::now(), - stuck_interval_timestamp: Instant::now(), - } - } - - /// Check if the triples has changed or not. If they have not changed for a long time, then we - /// will report that the protocol is stuck. - /// - /// Returns `true` if the protocol is stuck. - pub async fn check(&mut self, cfg: &ProtocolConfig) -> bool { - let triple_manager = self.triple_manager.read().await; - let latest_triples: HashSet<_> = triple_manager.triples.keys().cloned().collect(); - if triple_manager.has_min_triples(cfg) { - drop(triple_manager); - self.reset(latest_triples); - return false; - } - - let diff = latest_triples - .difference(&self.last_checked_triples) - .collect::>(); - if !diff.is_empty() { - drop(triple_manager); - self.reset(latest_triples); - return false; - } - - if self.last_changed_timestamp.elapsed() >= STUCK_TIMEOUT_THRESHOLD - && self.stuck_interval_timestamp.elapsed() >= STUCK_REPORT_INTERVAL - { - self.stuck_interval_timestamp = Instant::now(); - tracing::warn!( - ?triple_manager, - "protocol is stuck for the last {} seconds", - self.last_changed_timestamp.elapsed().as_secs(), - ); - return true; - } - - false - } - - fn reset(&mut self, latest_triples: HashSet) { - self.last_checked_triples = latest_triples; - self.last_changed_timestamp = Instant::now(); - } -} diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 71f830e08..015d37e76 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -187,6 +187,8 @@ impl PresignatureManager { pub async fn insert(&mut self, presignature: Presignature) { tracing::info!(id = ?presignature.id, "inserting presignature"); + // Remove from taken list if it was there + self.gc.remove(&presignature.id); if let Err(e) = self.presignature_storage.write().await.insert(presignature) { tracing::error!(?e, "failed to insert presignature"); } diff --git a/chain-signatures/node/src/protocol/state.rs b/chain-signatures/node/src/protocol/state.rs index 58fd4a506..dcf54f7a5 100644 --- a/chain-signatures/node/src/protocol/state.rs +++ b/chain-signatures/node/src/protocol/state.rs @@ -1,12 +1,10 @@ use super::contract::primitives::{ParticipantInfo, Participants}; use super::cryptography::CryptographicError; -use super::monitor::StuckMonitor; use super::presignature::PresignatureManager; use super::signature::SignatureManager; use super::triple::TripleManager; use super::SignQueue; use crate::http_client::MessageQueue; -use crate::storage::triple_storage::TripleData; use crate::types::{KeygenProtocol, ReshareProtocol, SecretKeyShare}; use cait_sith::protocol::Participant; @@ -37,7 +35,6 @@ impl fmt::Debug for PersistentNodeData { #[derive(Debug, Clone)] pub struct StartedState { pub persistent_node_data: Option, - pub triple_data: Vec, } #[derive(Clone)] @@ -95,7 +92,6 @@ pub struct RunningState { pub private_share: SecretKeyShare, pub public_key: PublicKey, pub sign_queue: Arc>, - pub stuck_monitor: Arc>, pub triple_manager: Arc>, pub presignature_manager: Arc>, pub signature_manager: Arc>, diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index f899b2dfc..328acbd04 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -2,8 +2,7 @@ use super::contract::primitives::Participants; use super::cryptography::CryptographicError; use super::message::TripleMessage; use super::presignature::GenerationError; -use crate::gcp::error; -use crate::storage::triple_storage::{LockMemoryTripleStorage, TripleData}; +use crate::storage::triple_storage::LockTripleMemoryStorage; use crate::types::TripleProtocol; use crate::util::AffinePointExt; @@ -27,6 +26,7 @@ use near_account_id::AccountId; /// messages. pub type TripleId = u64; +// TODO: why do we have Clone here? Triples can not be reused. /// A completed triple. #[derive(Clone, Serialize, Deserialize, Debug)] pub struct Triple { @@ -79,8 +79,8 @@ impl TripleGenerator { /// Abstracts how triples are generated by providing a way to request a new triple that will be /// complete some time in the future and a way to take an already generated triple. pub struct TripleManager { - /// Completed unspent triples - pub triples: HashMap, + /// Triple Storage + pub triple_storage: LockTripleMemoryStorage, /// The pool of triple protocols that have yet to be completed. pub generators: HashMap, @@ -96,9 +96,6 @@ pub struct TripleManager { /// The set of triples that were introduced to the system by the current node. pub introduced: HashSet, - /// List of triple ids generation of which was initiated by the current node. - pub mine: VecDeque, - /// The set of triple ids that were already taken or failed. This will be maintained for at most /// triple timeout period just so messages are cycled through the system. pub gc: HashMap, @@ -106,20 +103,17 @@ pub struct TripleManager { pub me: Participant, pub threshold: usize, pub epoch: u64, - pub triple_storage: LockMemoryTripleStorage, pub my_account_id: AccountId, } impl fmt::Debug for TripleManager { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("TripleManager") - .field("triples", &self.triples.keys().collect::>()) .field("generators", &self.generators.keys().collect::>()) .field("queued", &self.queued) .field("ongoing", &self.ongoing) .field("introduced", &self.introduced) .field("gc", &self.gc.keys().collect::>()) - .field("mine", &self.mine) .field("me", &self.me) .field("threshold", &self.threshold) .field("epoch", &self.epoch) @@ -133,28 +127,15 @@ impl TripleManager { me: Participant, threshold: usize, epoch: u64, - triple_data: Vec, - triple_storage: LockMemoryTripleStorage, + triple_storage: LockTripleMemoryStorage, my_account_id: &AccountId, ) -> Self { - let mut mine: VecDeque = VecDeque::new(); - let mut all_triples = HashMap::new(); - for entry in triple_data { - tracing::debug!("the triple data loaded is {:?}", entry); - if entry.mine { - tracing::debug!("pushed tripleId = {} into mine.", entry.triple.id); - mine.push_back(entry.triple.id); - } - all_triples.insert(entry.triple.id, entry.triple); - } Self { - triples: all_triples, generators: HashMap::new(), queued: VecDeque::new(), ongoing: HashSet::new(), introduced: HashSet::new(), gc: HashMap::new(), - mine, me, threshold, epoch, @@ -163,29 +144,164 @@ impl TripleManager { } } - /// Returns the number of unspent triples available in the manager. - pub fn count(&self) -> usize { - self.triples.len() + pub async fn insert(&mut self, triple: Triple) { + tracing::info!(id = triple.id, "inserting triple"); + self.gc.remove(&triple.id); + if let Err(e) = self.triple_storage.write().await.insert(triple) { + tracing::warn!(?e, "failed to insert triple"); + } } - /// Returns if there's any unspent triple in the manager. - pub fn is_empty(&self) -> bool { - self.count() == 0 + pub async fn insert_mine(&mut self, triple: Triple) { + tracing::debug!(id = triple.id, "inserting mine triple"); + self.gc.remove(&triple.id); + if let Err(e) = self.triple_storage.write().await.insert_mine(triple) { + tracing::warn!(?e, "failed to insert mine triple"); + } + } + + pub async fn contains(&self, id: &TripleId) -> bool { + self.triple_storage + .write() + .await + .contains(id) + .map_err(|e| tracing::warn!(?e, "failed to check if triple exists")) + .unwrap_or(false) + } + + pub async fn contains_mine(&self, id: &TripleId) -> bool { + self.triple_storage + .write() + .await + .contains_mine(id) + .map_err(|e| tracing::warn!(?e, "failed to check if mine triple exists")) + .unwrap_or(false) + } + + /// Take two unspent triple by theirs id with no way to return it. Only takes + /// if both of them are present. + /// It is very important to NOT reuse the same triple twice for two different + /// protocols. + pub async fn take_two( + &mut self, + id0: TripleId, + id1: TripleId, + ) -> Result<(Triple, Triple), GenerationError> { + let triple_0 = match self.triple_storage.write().await.take(&id0) { + Ok(Some(triple)) => triple, + Ok(None) => { + if self.generators.contains_key(&id0) { + tracing::warn!(id0, "triple is generating"); + return Err(GenerationError::TripleIsGenerating(id0)); + } else if self.gc.contains_key(&id0) { + tracing::warn!(id0, "triple is garbage collected"); + return Err(GenerationError::TripleIsGarbageCollected(id0)); + } else { + tracing::warn!(id0, "triple is missing"); + return Err(GenerationError::TripleIsMissing(id0)); + } + } + Err(e) => { + tracing::warn!(id0, ?e, "failed to take triple"); + return Err(GenerationError::TripleIsMissing(id0)); + } + }; + + let triple_1 = match self.triple_storage.write().await.take(&id1) { + Ok(Some(triple)) => triple, + Ok(None) => { + if let Err(e) = self.triple_storage.write().await.insert(triple_0) { + tracing::warn!(id0, ?e, "failed to insert triple back"); + } + if self.generators.contains_key(&id1) { + tracing::warn!(id1, "triple is generating"); + return Err(GenerationError::TripleIsGenerating(id1)); + } else if self.gc.contains_key(&id1) { + tracing::warn!(id1, "triple is garbage collected"); + return Err(GenerationError::TripleIsGarbageCollected(id1)); + } else { + tracing::warn!(id1, "triple is missing"); + return Err(GenerationError::TripleIsMissing(id1)); + } + } + Err(e) => { + tracing::warn!(id1, ?e, "failed to take triple"); + if let Err(e) = self.triple_storage.write().await.insert(triple_0) { + tracing::warn!(id0, ?e, "failed to insert triple back"); + } + return Err(GenerationError::TripleIsMissing(id1)); + } + }; + + self.gc.insert(id0, Instant::now()); + self.gc.insert(id1, Instant::now()); + + Ok((triple_0, triple_1)) + } + + /// Take two random unspent triple generated by this node. Either takes both or none. + /// It is very important to NOT reuse the same triple twice for two different + /// protocols. + pub async fn take_two_mine(&mut self) -> Option<(Triple, Triple)> { + let triple_0 = match self.triple_storage.write().await.take_mine() { + Ok(Some(triple)) => triple, + Ok(None) => { + tracing::warn!("no mine triple left"); + return None; + } + Err(e) => { + tracing::warn!(?e, "failed to take mine triple"); + return None; + } + }; + + let triple_1 = match self.triple_storage.write().await.take_mine() { + Ok(Some(triple)) => triple, + Ok(None) => { + if let Err(e) = self.triple_storage.write().await.insert_mine(triple_0) { + tracing::warn!(?e, "failed to insert mine triple back"); + } + tracing::warn!("no mine triple left"); + return None; + } + Err(e) => { + tracing::warn!(?e, "failed to take mine triple"); + if let Err(e) = self.triple_storage.write().await.insert_mine(triple_0) { + tracing::warn!(?e, "failed to insert mine triple back"); + } + return None; + } + }; + + self.gc.insert(triple_0.id, Instant::now()); + self.gc.insert(triple_1.id, Instant::now()); + + Some((triple_0, triple_1)) + } + + /// Returns the number of unspent triples available in the manager. + pub async fn count_all(&self) -> usize { + self.triple_storage.write().await.count_all().unwrap_or(0) } /// Returns the number of unspent triples assigned to this node. - pub fn count_mine(&self) -> usize { - self.mine.len() + pub async fn count_mine(&self) -> usize { + self.triple_storage.write().await.count_mine().unwrap_or(0) + } + + /// Returns if there's any unspent triple in the manager. + pub async fn is_empty(&self) -> bool { + self.count_all().await == 0 } /// Returns the number of unspent triples we will have in the manager once /// all ongoing generation protocols complete. - pub fn count_potential(&self) -> usize { - self.count() + self.generators.len() + pub async fn count_potential(&self) -> usize { + self.count_all().await + self.generators.len() } - pub fn has_min_triples(&self, cfg: &ProtocolConfig) -> bool { - self.count_mine() >= cfg.triple.min_triples as usize + pub async fn has_min_triples(&self, cfg: &ProtocolConfig) -> bool { + self.count_mine().await >= cfg.triple.min_triples as usize } /// Clears an entry from failed triples if that triple protocol was created more than 2 hrs ago @@ -208,7 +324,7 @@ impl TripleManager { } /// Starts a new Beaver triple generation protocol. - pub fn generate( + pub async fn generate( &mut self, participants: &Participants, timeout: u64, @@ -217,7 +333,7 @@ impl TripleManager { // Check if the `id` is already in the system. Error out and have the next cycle try again. if self.generators.contains_key(&id) - || self.triples.contains_key(&id) + || self.contains(&id).await || self.gc.contains_key(&id) { tracing::warn!(id, "triple id collision"); @@ -247,7 +363,7 @@ impl TripleManager { /// Stockpile triples if the amount of unspent triples is below the minimum /// and the maximum number of all ongoing generation protocols is below the maximum. - pub fn stockpile( + pub async fn stockpile( &mut self, participants: &Participants, cfg: &ProtocolConfig, @@ -256,11 +372,11 @@ impl TripleManager { // Stopgap to prevent too many triples in the system. This should be around min_triple*nodes*2 // for good measure so that we have enough triples to do presig generation while also maintain // the minimum number of triples where a single node can't flood the system. - if self.count_potential() >= cfg.triple.max_triples as usize { + if self.count_potential().await >= cfg.triple.max_triples as usize { false } else { // We will always try to generate a new triple if we have less than the minimum - self.count_mine() < cfg.triple.min_triples as usize + self.count_mine().await < cfg.triple.min_triples as usize && self.introduced.len() < cfg.max_concurrent_introduction as usize && self.generators.len() < cfg.max_concurrent_generation as usize } @@ -268,151 +384,27 @@ impl TripleManager { if not_enough_triples { tracing::debug!("not enough triples, generating"); - self.generate(participants, cfg.triple.generation_timeout)?; + self.generate(participants, cfg.triple.generation_timeout) + .await?; } Ok(()) } - /// Take two unspent triple by theirs id with no way to return it. Only takes - /// if both of them are present. - /// It is very important to NOT reuse the same triple twice for two different - /// protocols. - pub async fn take_two( - &mut self, - id0: TripleId, - id1: TripleId, - ) -> Result<(Triple, Triple), GenerationError> { - if !self.triples.contains_key(&id0) { - if self.generators.contains_key(&id0) { - tracing::warn!(id0, "triple is generating"); - Err(GenerationError::TripleIsGenerating(id0)) - } else if self.gc.contains_key(&id0) { - tracing::warn!(id0, "triple is garbage collected"); - Err(GenerationError::TripleIsGarbageCollected(id0)) - } else { - tracing::warn!(id0, "triple is missing"); - Err(GenerationError::TripleIsMissing(id0)) - } - } else if !self.triples.contains_key(&id1) { - if self.generators.contains_key(&id1) { - tracing::warn!(id1, "triple is generating"); - Err(GenerationError::TripleIsGenerating(id1)) - } else if self.gc.contains_key(&id1) { - tracing::warn!(id1, "triple is garbage collected"); - Err(GenerationError::TripleIsGarbageCollected(id1)) - } else { - tracing::warn!(id1, "triple is missing"); - Err(GenerationError::TripleIsMissing(id1)) - } - } else { - // Ensure that the triples have been removed from the datastore if they're going to be used in a signing protocol. - // We expect them to be there so warn if they're not. - // They may already be in memory, so even if this fails still try to pull them out. - if let Err(err) = self.delete_triple_from_storage(id0).await { - tracing::warn!(triple_id = id0, ?err, "unable to delete triple: potentially missing from datastore; deleting from memory only"); - } - if let Err(err) = self.delete_triple_from_storage(id1).await { - tracing::warn!(triple_id = id1, ?err, "unable to delete triple: potentially missing from datastore; deleting from memory only"); - } - - self.gc.insert(id0, Instant::now()); - self.gc.insert(id1, Instant::now()); - - let triple_0 = self - .triples - .remove(&id0) - .ok_or(GenerationError::TripleIsMissing(id0))?; - let triple_1 = self - .triples - .remove(&id1) - .ok_or(GenerationError::TripleIsMissing(id1))?; - Ok((triple_0, triple_1)) - } - } - - async fn delete_triple_from_storage( - &mut self, - id: TripleId, - ) -> Result<(), error::DatastoreStorageError> { - let action = || async { - let mut triple_storage = self.triple_storage.write().await; - if let Err(err) = triple_storage.delete(id).await { - tracing::warn!(?err, id, "triple deletion failed."); - return Err(err); - } - Ok(()) - }; - - // Retry the action 3x with 500ms delay between each retry - let retry_strategy = std::iter::repeat_with(|| Duration::from_millis(500)).take(3); - tokio_retry::Retry::spawn(retry_strategy, action).await - } - - /// Take two random unspent triple generated by this node. Either takes both or none. - /// It is very important to NOT reuse the same triple twice for two different - /// protocols. - pub async fn take_two_mine(&mut self) -> Option<(Triple, Triple)> { - if self.mine.len() < 2 { - return None; - } - let id0 = self.mine.pop_front()?; - let id1 = self.mine.pop_front()?; - tracing::info!(id0, id1, me = ?self.me, "trying to take two mine triples"); - - let take_two_result = self.take_two(id0, id1).await; - match take_two_result { - Err(error) - if matches!( - error, - GenerationError::TripleIsMissing(_) | GenerationError::TripleIsGenerating(_) - ) => - { - tracing::warn!( - triple_id0 = id0, - triple_id1 = id1, - ?error, - "unable to take two triples: one or both of the triples are missing/not-generated", - ); - self.mine.push_front(id1); - self.mine.push_front(id0); - None - } - Err(error) => { - tracing::warn!( - triple_id0 = id0, - triple_id1 = id1, - ?error, - "unexpected error encountered while taking two triples" - ); - None - } - Ok(val) => Some(val), - } - } - - pub async fn insert_mine(&mut self, triple: Triple) { - tracing::debug!(id = triple.id, "inserting mine triple"); - self.mine.push_back(triple.id); - self.triples.insert(triple.id, triple.clone()); - self.gc.remove(&triple.id); - self.insert_triples_to_storage(vec![triple]).await; - } - /// Ensures that the triple with the given id is either: /// 1) Already generated in which case returns `None`, or /// 2) Is currently being generated by `protocol` in which case returns `Some(protocol)`, or /// 3) Has never been seen by the manager in which case start a new protocol and returns `Some(protocol)` // TODO: What if the triple completed generation and is already spent? - pub fn get_or_generate( + pub async fn get_or_start_generation( &mut self, id: TripleId, participants: &Participants, cfg: &ProtocolConfig, ) -> Result, CryptographicError> { - if self.triples.contains_key(&id) || self.gc.contains_key(&id) { + if self.contains(&id).await || self.gc.contains_key(&id) { Ok(None) } else { - let potential_len = self.count_potential(); + let potential_len = self.count_potential().await; match self.generators.entry(id) { Entry::Vacant(e) => { if potential_len >= cfg.triple.max_triples as usize { @@ -459,8 +451,9 @@ impl TripleManager { } let mut messages = Vec::new(); - let mut triples_to_insert = Vec::new(); let mut errors = Vec::new(); + let mut new_triples = Vec::new(); + let mut new_mine_triples = Vec::new(); self.generators.retain(|id, generator| { if !self.ongoing.contains(id) { // If the protocol is not ongoing, we should retain it for the next time @@ -564,15 +557,14 @@ impl TripleManager { }; if triple_is_mine { - self.mine.push_back(*id); + new_mine_triples.push(triple.clone()); crate::metrics::NUM_TOTAL_HISTORICAL_TRIPLE_GENERATIONS_MINE_SUCCESS .with_label_values(&[self.my_account_id.as_str()]) .inc(); + } else { + new_triples.push(triple.clone()); } - self.triples.insert(*id, triple.clone()); - triples_to_insert.push(triple); - // Protocol done, remove it from the ongoing pool. self.ongoing.remove(id); self.introduced.remove(id); @@ -582,7 +574,14 @@ impl TripleManager { } } }); - self.insert_triples_to_storage(triples_to_insert).await; + + for triple in new_triples { + self.insert(triple).await; + } + + for triple in new_mine_triples { + self.insert_mine(triple).await; + } if !errors.is_empty() { tracing::warn!(?errors, "faled to generate some triples"); @@ -590,22 +589,4 @@ impl TripleManager { messages } - - async fn insert_triples_to_storage(&mut self, triples_to_insert: Vec) { - for triple in triples_to_insert { - let mine = self.mine.contains(&triple.id); - let action = || async { - let mut triple_storage = self.triple_storage.write().await; - if let Err(e) = triple_storage.insert(triple.clone(), mine).await { - tracing::warn!(?e, id = triple.id, "triple insertion failed."); - return Err(e); - } - Ok(()) - }; - - // Retry the action 3x with 500ms delay between each retry - let retry_strategy = std::iter::repeat_with(|| Duration::from_millis(500)).take(3); - let _ = tokio_retry::Retry::spawn(retry_strategy, action).await; - } - } } diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index d1d523eb9..f55b1c6fa 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -64,6 +64,10 @@ impl RedisPresignatureStorage { } pub fn take(&mut self, id: &PresignatureId) -> PresigResult> { + if self.contains_mine(id)? { + tracing::error!("Can not take mine presignature as foreign: {:?}", id); + return Ok(None); + } let result: Option = self.redis_connection.hget(self.presignature_key(), id)?; match result { @@ -94,6 +98,13 @@ impl RedisPresignatureStorage { Ok(result) } + pub fn clear(&mut self) -> PresigResult<()> { + self.redis_connection + .del::<&str, ()>(&self.presignature_key())?; + self.redis_connection.del::<&str, ()>(&self.mine_key())?; + Ok(()) + } + fn presignature_key(&self) -> String { format!("presignatures:{}:{}", STORAGE_VERSION, self.node_account_id) } diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index 73eefd64f..529d86ec7 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -1,76 +1,78 @@ -use crate::gcp::error; use crate::protocol::triple::{Triple, TripleId}; use std::collections::{HashMap, HashSet}; use std::sync::Arc; +use rand::seq::IteratorRandom; +use rand::thread_rng; use tokio::sync::RwLock; use near_account_id::AccountId; -pub type LockMemoryTripleStorage = Arc>; +pub type LockTripleMemoryStorage = Arc>; +type TripleResult = std::result::Result; pub fn init(account_id: &AccountId) -> TripleMemoryStorage { TripleMemoryStorage { triples: HashMap::new(), mine: HashSet::new(), - account_id: account_id.clone(), + _account_id: account_id.clone(), } } -// TODO: do we need this stuct? -#[derive(Clone, Debug)] -pub struct TripleData { - pub account_id: AccountId, - pub triple: Triple, - pub mine: bool, -} - -// TODO: remove or refactor use of DatastoreStorageError -type TripleResult = std::result::Result; - #[derive(Clone)] pub struct TripleMemoryStorage { triples: HashMap, mine: HashSet, - account_id: AccountId, + _account_id: AccountId, // TODO: will be used after migratio to Redis } impl TripleMemoryStorage { - pub async fn insert(&mut self, triple: Triple, mine: bool) -> TripleResult<()> { - if mine { - self.mine.insert(triple.id); - } + pub fn insert(&mut self, triple: Triple) -> TripleResult<()> { self.triples.insert(triple.id, triple); Ok(()) } - pub async fn delete(&mut self, id: TripleId) -> TripleResult<()> { - self.triples.remove(&id); - self.mine.remove(&id); + pub fn insert_mine(&mut self, triple: Triple) -> TripleResult<()> { + self.mine.insert(triple.id); + self.triples.insert(triple.id, triple); Ok(()) } - pub async fn clear(&mut self) -> TripleResult> { - let res = self.load().await?; - self.triples.clear(); - self.mine.clear(); - Ok(res) + pub fn contains(&mut self, id: &TripleId) -> TripleResult { + Ok(self.triples.contains_key(id)) } - pub async fn load(&self) -> TripleResult> { - let mut res: Vec = vec![]; - for (triple_id, triple) in self.triples.clone() { - let mine = self.mine.contains(&triple_id); - res.push(TripleData { - account_id: self.account_id().clone(), - triple, - mine, - }); + pub fn contains_mine(&mut self, id: &TripleId) -> TripleResult { + Ok(self.mine.contains(id)) + } + + pub fn take(&mut self, id: &TripleId) -> TripleResult> { + if self.contains_mine(id)? { + tracing::error!("Can not take mine triple as foreign: {:?}", id); + return Ok(None); } - Ok(res) + Ok(self.triples.remove(&id)) } - pub fn account_id(&self) -> &AccountId { - &self.account_id + pub fn take_mine(&mut self) -> TripleResult> { + let mut rng = thread_rng(); + match self.mine.iter().choose(&mut rng) { + Some(id) => Ok(self.triples.remove(id)), + None => Ok(None), + } + } + + pub fn count_all(&mut self) -> TripleResult { + Ok(self.triples.len()) + } + + pub fn count_mine(&mut self) -> TripleResult { + Ok(self.mine.len()) + } + + pub fn clear(&mut self) -> TripleResult<()> { + self.triples.clear(); + self.mine.clear(); + Ok(()) } } diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index 33b9e96f7..942117072 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -137,9 +137,9 @@ async fn state(Extension(state): Extension>) -> Result { let triple_manager_read = state.triple_manager.read().await; - let triple_potential_count = triple_manager_read.count_potential(); - let triple_count = triple_manager_read.count(); - let triple_mine_count = triple_manager_read.count_mine(); + let triple_potential_count = triple_manager_read.count_potential().await; + let triple_count = triple_manager_read.count_all().await; + let triple_mine_count = triple_manager_read.count_mine().await; let presignature_read = state.presignature_manager.read().await; let presignature_count = presignature_read.count_all().await; let presignature_mine_count = presignature_read.count_mine().await; From c8eccc861e07eb5a0b17b938d34d43468b759eee Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 23 Oct 2024 19:11:41 +0300 Subject: [PATCH 36/64] use redis to store triples --- chain-signatures/node/src/cli.rs | 13 +- .../node/src/protocol/consensus.rs | 12 +- chain-signatures/node/src/protocol/mod.rs | 16 +-- .../node/src/protocol/presignature.rs | 6 +- chain-signatures/node/src/protocol/triple.rs | 6 +- .../node/src/storage/presignature_storage.rs | 21 +-- .../node/src/storage/triple_storage.rs | 124 ++++++++++++++---- integration-tests/chain-signatures/src/lib.rs | 11 +- .../chain-signatures/tests/cases/mod.rs | 107 ++++++++++++++- 9 files changed, 247 insertions(+), 69 deletions(-) diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 76ea5471e..04569f461 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -1,8 +1,8 @@ use crate::config::{Config, LocalConfig, NetworkConfig, OverrideConfig}; use crate::gcp::GcpService; use crate::protocol::{MpcSignProtocol, SignQueue}; -use crate::storage::presignature_storage::LockRedisPresignatureStorage; -use crate::storage::triple_storage::LockTripleMemoryStorage; +use crate::storage::presignature_storage::LockPresignatureRedisStorage; +use crate::storage::triple_storage::LockTripleRedisStorage; use crate::{http_client, indexer, mesh, storage, web}; use clap::Parser; use local_ip_address::local_ip; @@ -207,11 +207,14 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let key_storage = storage::secret_storage::init(Some(&gcp_service), &storage_options, &account_id); - let triple_storage: LockTripleMemoryStorage = - Arc::new(RwLock::new(storage::triple_storage::init(&account_id))); let redis_url: Url = Url::parse(storage_options.redis_url.as_str())?; - let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new( + + let triple_storage: LockTripleRedisStorage = Arc::new(RwLock::new( + storage::triple_storage::init(redis_url.clone(), &account_id), + )); + + let presignature_storage: LockPresignatureRedisStorage = Arc::new(RwLock::new( storage::presignature_storage::init(redis_url, &account_id), )); diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index 08405604d..793fcb209 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -12,9 +12,9 @@ use crate::protocol::presignature::PresignatureManager; use crate::protocol::signature::SignatureManager; use crate::protocol::state::{GeneratingState, ResharingState}; use crate::protocol::triple::TripleManager; -use crate::storage::presignature_storage::LockRedisPresignatureStorage; +use crate::storage::presignature_storage::LockPresignatureRedisStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::LockTripleMemoryStorage; +use crate::storage::triple_storage::LockTripleRedisStorage; use crate::types::{KeygenProtocol, ReshareProtocol, SecretKeyShare}; use crate::util::AffinePointExt; use crate::{http_client, rpc_client}; @@ -40,8 +40,8 @@ pub trait ConsensusCtx { fn my_address(&self) -> &Url; fn sign_queue(&self) -> Arc>; fn secret_storage(&self) -> &SecretNodeStorageBox; - fn triple_storage(&self) -> LockTripleMemoryStorage; - fn presignature_storage(&self) -> LockRedisPresignatureStorage; + fn triple_storage(&self) -> LockTripleRedisStorage; + fn presignature_storage(&self) -> LockPresignatureRedisStorage; fn cfg(&self) -> &Config; fn message_options(&self) -> http_client::Options; } @@ -138,8 +138,8 @@ impl ConsensusProtocol for StartedState { me, contract_state.threshold, epoch, - ctx.triple_storage(), ctx.my_account_id(), + ctx.triple_storage(), ))); let presignature_manager = @@ -379,8 +379,8 @@ impl ConsensusProtocol for WaitingForConsensusState { me, self.threshold, self.epoch, - ctx.triple_storage(), ctx.my_account_id(), + ctx.triple_storage(), ))); let presignature_manager = Arc::new(RwLock::new(PresignatureManager::new( diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 7e18e91a0..48bc89385 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -29,9 +29,9 @@ use crate::protocol::consensus::ConsensusProtocol; use crate::protocol::cryptography::CryptographicProtocol; use crate::protocol::message::{MessageHandler, MpcMessageQueue}; use crate::rpc_client; -use crate::storage::presignature_storage::LockRedisPresignatureStorage; +use crate::storage::presignature_storage::LockPresignatureRedisStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::LockTripleMemoryStorage; +use crate::storage::triple_storage::LockTripleRedisStorage; use cait_sith::protocol::Participant; use near_account_id::AccountId; @@ -53,8 +53,8 @@ struct Ctx { http_client: reqwest::Client, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: LockTripleMemoryStorage, - presignature_storage: LockRedisPresignatureStorage, + triple_storage: LockTripleRedisStorage, + presignature_storage: LockPresignatureRedisStorage, cfg: Config, mesh: Mesh, message_options: http_client::Options, @@ -97,11 +97,11 @@ impl ConsensusCtx for &mut MpcSignProtocol { &self.ctx.cfg } - fn triple_storage(&self) -> LockTripleMemoryStorage { + fn triple_storage(&self) -> LockTripleRedisStorage { self.ctx.triple_storage.clone() } - fn presignature_storage(&self) -> LockRedisPresignatureStorage { + fn presignature_storage(&self) -> LockPresignatureRedisStorage { self.ctx.presignature_storage.clone() } @@ -177,8 +177,8 @@ impl MpcSignProtocol { receiver: mpsc::Receiver, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: LockTripleMemoryStorage, - presignature_storage: LockRedisPresignatureStorage, + triple_storage: LockTripleRedisStorage, + presignature_storage: LockPresignatureRedisStorage, cfg: Config, mesh_options: mesh::Options, message_options: http_client::Options, diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 015d37e76..fdab557e7 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -1,7 +1,7 @@ use super::message::PresignatureMessage; use super::triple::{Triple, TripleId, TripleManager}; use crate::protocol::contract::primitives::Participants; -use crate::storage::presignature_storage::LockRedisPresignatureStorage; +use crate::storage::presignature_storage::LockPresignatureRedisStorage; use crate::types::{PresignatureProtocol, SecretKeyShare}; use crate::util::AffinePointExt; @@ -150,7 +150,7 @@ pub enum GenerationError { /// Abstracts how triples are generated by providing a way to request a new triple that will be /// complete some time in the future and a way to take an already generated triple. pub struct PresignatureManager { - presignature_storage: LockRedisPresignatureStorage, + presignature_storage: LockPresignatureRedisStorage, /// Ongoing presignature generation protocols. generators: HashMap, /// The set of presignatures that were introduced to the system by the current node. @@ -171,7 +171,7 @@ impl PresignatureManager { threshold: usize, epoch: u64, my_account_id: &AccountId, - presignature_storage: LockRedisPresignatureStorage, + presignature_storage: LockPresignatureRedisStorage, ) -> Self { Self { presignature_storage, diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index 328acbd04..287c066dc 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -2,7 +2,7 @@ use super::contract::primitives::Participants; use super::cryptography::CryptographicError; use super::message::TripleMessage; use super::presignature::GenerationError; -use crate::storage::triple_storage::LockTripleMemoryStorage; +use crate::storage::triple_storage::LockTripleRedisStorage; use crate::types::TripleProtocol; use crate::util::AffinePointExt; @@ -80,7 +80,7 @@ impl TripleGenerator { /// complete some time in the future and a way to take an already generated triple. pub struct TripleManager { /// Triple Storage - pub triple_storage: LockTripleMemoryStorage, + pub triple_storage: LockTripleRedisStorage, /// The pool of triple protocols that have yet to be completed. pub generators: HashMap, @@ -127,8 +127,8 @@ impl TripleManager { me: Participant, threshold: usize, epoch: u64, - triple_storage: LockTripleMemoryStorage, my_account_id: &AccountId, + triple_storage: LockTripleRedisStorage, ) -> Self { Self { generators: HashMap::new(), diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index f55b1c6fa..c820167b7 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -9,21 +9,21 @@ use url::Url; use crate::protocol::presignature::{Presignature, PresignatureId}; type PresigResult = std::result::Result; -pub type LockRedisPresignatureStorage = Arc>; +pub type LockPresignatureRedisStorage = Arc>; // Can be used to "clear" redis storage in case of a breaking change -const STORAGE_VERSION: &str = "v1"; +const PRESIGNATURE_STORAGE_VERSION: &str = "v1"; -pub fn init(redis_url: Url, node_account_id: &AccountId) -> RedisPresignatureStorage { - RedisPresignatureStorage::new(redis_url, node_account_id) +pub fn init(redis_url: Url, node_account_id: &AccountId) -> PresignatureRedisStorage { + PresignatureRedisStorage::new(redis_url, node_account_id) } -pub struct RedisPresignatureStorage { +pub struct PresignatureRedisStorage { redis_connection: Connection, node_account_id: AccountId, } -impl RedisPresignatureStorage { +impl PresignatureRedisStorage { fn new(redis_url: Url, node_account_id: &AccountId) -> Self { Self { redis_connection: redis::Client::open(redis_url.as_str()) @@ -35,7 +35,7 @@ impl RedisPresignatureStorage { } } -impl RedisPresignatureStorage { +impl PresignatureRedisStorage { pub fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { self.redis_connection .hset::<&str, PresignatureId, Presignature, ()>( @@ -106,13 +106,16 @@ impl RedisPresignatureStorage { } fn presignature_key(&self) -> String { - format!("presignatures:{}:{}", STORAGE_VERSION, self.node_account_id) + format!( + "presignatures:{}:{}", + PRESIGNATURE_STORAGE_VERSION, self.node_account_id + ) } fn mine_key(&self) -> String { format!( "presignatures_mine:{}:{}", - STORAGE_VERSION, self.node_account_id + PRESIGNATURE_STORAGE_VERSION, self.node_account_id ) } } diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index 529d86ec7..06f202ea5 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -1,49 +1,62 @@ use crate::protocol::triple::{Triple, TripleId}; -use std::collections::{HashMap, HashSet}; use std::sync::Arc; -use rand::seq::IteratorRandom; -use rand::thread_rng; +use redis::{Commands, Connection, FromRedisValue, RedisWrite, ToRedisArgs}; use tokio::sync::RwLock; use near_account_id::AccountId; +use url::Url; -pub type LockTripleMemoryStorage = Arc>; +pub type LockTripleRedisStorage = Arc>; type TripleResult = std::result::Result; -pub fn init(account_id: &AccountId) -> TripleMemoryStorage { - TripleMemoryStorage { - triples: HashMap::new(), - mine: HashSet::new(), - _account_id: account_id.clone(), - } +// Can be used to "clear" redis storage in case of a breaking change +const TRIPLE_STORAGE_VERSION: &str = "v1"; + +pub fn init(redis_url: Url, account_id: &AccountId) -> TripleRedisStorage { + TripleRedisStorage::new(redis_url, account_id) } -#[derive(Clone)] -pub struct TripleMemoryStorage { - triples: HashMap, - mine: HashSet, - _account_id: AccountId, // TODO: will be used after migratio to Redis +pub struct TripleRedisStorage { + redis_connection: Connection, + node_account_id: AccountId, } -impl TripleMemoryStorage { +impl TripleRedisStorage { + fn new(redis_url: Url, account_id: &AccountId) -> Self { + Self { + redis_connection: redis::Client::open(redis_url.as_str()) + .expect("Failed to connect to Redis") + .get_connection() + .expect("Failed to get Redis connection"), + node_account_id: account_id.clone(), + } + } + pub fn insert(&mut self, triple: Triple) -> TripleResult<()> { - self.triples.insert(triple.id, triple); + self.redis_connection.hset::<&str, TripleId, Triple, ()>( + &self.triple_key(), + triple.id, + triple, + )?; Ok(()) } pub fn insert_mine(&mut self, triple: Triple) -> TripleResult<()> { - self.mine.insert(triple.id); - self.triples.insert(triple.id, triple); + self.redis_connection + .sadd::<&str, TripleId, ()>(&self.mine_key(), triple.id)?; + self.insert(triple)?; Ok(()) } pub fn contains(&mut self, id: &TripleId) -> TripleResult { - Ok(self.triples.contains_key(id)) + let result: bool = self.redis_connection.hexists(self.triple_key(), id)?; + Ok(result) } pub fn contains_mine(&mut self, id: &TripleId) -> TripleResult { - Ok(self.mine.contains(id)) + let result: bool = self.redis_connection.sismember(self.mine_key(), id)?; + Ok(result) } pub fn take(&mut self, id: &TripleId) -> TripleResult> { @@ -51,28 +64,81 @@ impl TripleMemoryStorage { tracing::error!("Can not take mine triple as foreign: {:?}", id); return Ok(None); } - Ok(self.triples.remove(&id)) + let result: Option = self.redis_connection.hget(self.triple_key(), id)?; + match result { + Some(triple) => { + self.redis_connection + .hdel::<&str, TripleId, ()>(&self.triple_key(), *id)?; + Ok(Some(triple)) + } + None => Ok(None), + } } pub fn take_mine(&mut self) -> TripleResult> { - let mut rng = thread_rng(); - match self.mine.iter().choose(&mut rng) { - Some(id) => Ok(self.triples.remove(id)), + let id: Option = self.redis_connection.spop(self.mine_key())?; + match id { + Some(id) => self.take(&id), None => Ok(None), } } pub fn count_all(&mut self) -> TripleResult { - Ok(self.triples.len()) + let result: usize = self.redis_connection.hlen(self.triple_key())?; + Ok(result) } pub fn count_mine(&mut self) -> TripleResult { - Ok(self.mine.len()) + let result: usize = self.redis_connection.scard(self.mine_key())?; + Ok(result) } pub fn clear(&mut self) -> TripleResult<()> { - self.triples.clear(); - self.mine.clear(); + self.redis_connection.del(&self.triple_key())?; + self.redis_connection.del(&self.mine_key())?; Ok(()) } + + fn triple_key(&self) -> String { + format!( + "triples:{}:{}", + TRIPLE_STORAGE_VERSION, self.node_account_id + ) + } + + fn mine_key(&self) -> String { + format!( + "triples_mine:{}:{}", + TRIPLE_STORAGE_VERSION, self.node_account_id + ) + } +} + +impl ToRedisArgs for Triple { + fn write_redis_args(&self, out: &mut W) + where + W: ?Sized + RedisWrite, + { + match serde_json::to_string(self) { + std::result::Result::Ok(json) => out.write_arg(json.as_bytes()), + Err(e) => { + tracing::error!("Failed to serialize Triple: {}", e); + out.write_arg("failed_to_serialize".as_bytes()) + } + } + } +} + +impl FromRedisValue for Triple { + fn from_redis_value(v: &redis::Value) -> redis::RedisResult { + let json: String = String::from_redis_value(v)?; + + serde_json::from_str(&json).map_err(|e| { + redis::RedisError::from(( + redis::ErrorKind::TypeError, + "Failed to deserialize Triple", + e.to_string(), + )) + }) + } } diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 84f6583cb..328061cf2 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -18,13 +18,14 @@ use mpc_node::gcp::GcpService; use mpc_node::http_client; use mpc_node::mesh; use mpc_node::storage; -use mpc_node::storage::triple_storage::TripleMemoryStorage; +use mpc_node::storage::triple_storage::TripleRedisStorage; use near_crypto::KeyFile; use near_workspaces::network::{Sandbox, ValidatorKey}; use near_workspaces::types::{KeyType, SecretKey}; use near_workspaces::{Account, AccountId, Contract, Worker}; use serde_json::json; use testcontainers::{Container, GenericImage}; +use url::Url; const NETWORK: &str = "mpc_it_network"; @@ -155,8 +156,12 @@ impl Nodes<'_> { Ok(()) } - pub async fn triple_storage(&self, account_id: &AccountId) -> TripleMemoryStorage { - storage::triple_storage::init(account_id) + pub async fn triple_storage( + &self, + redis_url: Url, + account_id: &AccountId, + ) -> TripleRedisStorage { + storage::triple_storage::init(redis_url, account_id) } pub async fn gcp_services(&self) -> anyhow::Result> { diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 4f0d4a0cf..7045199d9 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -5,6 +5,7 @@ use crate::actions::{self, add_latency, wait_for}; use crate::with_multichain_nodes; use cait_sith::protocol::Participant; +use cait_sith::triples::{TriplePub, TripleShare}; use cait_sith::PresignOutput; use crypto_shared::{self, derive_epsilon, derive_key, x_coordinate, ScalarExt}; use elliptic_curve::CurveArithmetic; @@ -16,8 +17,9 @@ use mpc_contract::config::Config; use mpc_contract::update::ProposeUpdateArgs; use mpc_node::kdf::into_eth_sig; use mpc_node::protocol::presignature::{Presignature, PresignatureId, PresignatureManager}; +use mpc_node::protocol::triple::{Triple, TripleManager}; use mpc_node::storage; -use mpc_node::storage::presignature_storage::LockRedisPresignatureStorage; +use mpc_node::storage::presignature_storage::LockPresignatureRedisStorage; use mpc_node::types::LatestBlockHeight; use mpc_node::util::NearPublicKeyExt; use near_account_id::AccountId; @@ -210,7 +212,88 @@ async fn test_key_derivation() -> anyhow::Result<()> { #[test(tokio::test)] async fn test_triple_persistence() -> anyhow::Result<()> { - // TODO: add triple persistence test + let docker_client = DockerClient::default(); + let docker_network = "test-triple-persistence"; + docker_client.create_network(docker_network).await?; + let redis = containers::Redis::run(&docker_client, docker_network).await?; + let redis_url = Url::parse(redis.internal_address.as_str())?; + let triple_storage: storage::triple_storage::LockTripleRedisStorage = Arc::new(RwLock::new( + storage::triple_storage::init(redis_url, &AccountId::from_str("test.near").unwrap()), + )); + + let mut triple_manager = TripleManager::new( + Participant::from(0), + 5, + 123, + &AccountId::from_str("test.near").unwrap(), + triple_storage, + ); + + let triple_id_1: u64 = 1; + let triple_1 = dummy_triple(triple_id_1); + let triple_id_2: u64 = 2; + let triple_2 = dummy_triple(triple_id_2); + + // Check that the storage is empty at the start + assert!(!triple_manager.contains(&triple_id_1).await); + assert!(!triple_manager.contains_mine(&triple_id_1).await); + assert_eq!(triple_manager.count_all().await, 0); + assert_eq!(triple_manager.count_mine().await, 0); + assert!(triple_manager.is_empty().await); + assert_eq!(triple_manager.count_potential().await, 0); + + triple_manager.insert(triple_1).await; + triple_manager.insert(triple_2).await; + + // Check that the storage contains the foreign triple + assert!(triple_manager.contains(&triple_id_1).await); + assert!(triple_manager.contains(&triple_id_2).await); + assert!(!triple_manager.contains_mine(&triple_id_1).await); + assert!(!triple_manager.contains_mine(&triple_id_2).await); + assert_eq!(triple_manager.count_all().await, 2); + assert_eq!(triple_manager.count_mine().await, 0); + assert_eq!(triple_manager.count_potential().await, 2); + + // Take triple and check that it is removed from the storage + triple_manager + .take_two(triple_id_1, triple_id_2) + .await + .unwrap(); + assert!(!triple_manager.contains(&triple_id_1).await); + assert!(!triple_manager.contains(&triple_id_2).await); + assert!(!triple_manager.contains_mine(&triple_id_1).await); + assert!(!triple_manager.contains_mine(&triple_id_2).await); + assert_eq!(triple_manager.count_all().await, 0); + assert_eq!(triple_manager.count_mine().await, 0); + assert_eq!(triple_manager.count_potential().await, 0); + + let mine_id_1: u64 = 3; + let mine_triple_1 = dummy_triple(mine_id_1); + let mine_id_2: u64 = 4; + let mine_triple_2 = dummy_triple(mine_id_2); + + // Add mine triple and check that it is in the storage + triple_manager.insert_mine(mine_triple_1).await; + triple_manager.insert_mine(mine_triple_2).await; + assert!(triple_manager.contains(&mine_id_1).await); + assert!(triple_manager.contains(&mine_id_2).await); + assert!(triple_manager.contains_mine(&mine_id_1).await); + assert!(triple_manager.contains_mine(&mine_id_2).await); + assert_eq!(triple_manager.count_all().await, 2); + assert_eq!(triple_manager.count_mine().await, 2); + assert_eq!(triple_manager.count_potential().await, 2); + + // Take mine triple and check that it is removed from the storage + triple_manager.take_two_mine().await.unwrap(); + assert!(!triple_manager.contains(&mine_id_1).await); + assert!(!triple_manager.contains(&mine_id_2).await); + assert!(!triple_manager.contains_mine(&mine_id_1).await); + assert!(!triple_manager.contains_mine(&mine_id_2).await); + assert_eq!(triple_manager.count_all().await, 0); + assert_eq!(triple_manager.count_mine().await, 0); + assert!(triple_manager.is_empty().await); + assert_eq!(triple_manager.count_potential().await, 0); + Ok(()) } @@ -221,7 +304,7 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { docker_client.create_network(docker_network).await?; let redis = containers::Redis::run(&docker_client, docker_network).await?; let redis_url = Url::parse(redis.internal_address.as_str())?; - let presignature_storage: LockRedisPresignatureStorage = Arc::new(RwLock::new( + let presignature_storage: LockPresignatureRedisStorage = Arc::new(RwLock::new( storage::presignature_storage::init(redis_url, &AccountId::from_str("test.near").unwrap()), )); let mut presignature_manager = PresignatureManager::new( @@ -295,6 +378,24 @@ fn dummy_presignature() -> Presignature { } } +fn dummy_triple(id: u64) -> Triple { + Triple { + id, + share: TripleShare { + a: ::Scalar::ZERO, + b: ::Scalar::ZERO, + c: ::Scalar::ZERO, + }, + public: TriplePub { + big_a: ::AffinePoint::default(), + big_b: ::AffinePoint::default(), + big_c: ::AffinePoint::default(), + participants: vec![Participant::from(1), Participant::from(2)], + threshold: 5, + }, + } +} + #[test(tokio::test)] async fn test_latest_block_height() -> anyhow::Result<()> { with_multichain_nodes(MultichainConfig::default(), |ctx| { From 0f5d0783d8463d6dc34e706e982ec79c6bd19d7b Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 23 Oct 2024 19:51:38 +0300 Subject: [PATCH 37/64] fix rust typing issue --- chain-signatures/node/src/storage/triple_storage.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index 06f202ea5..f24039dee 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -94,8 +94,8 @@ impl TripleRedisStorage { } pub fn clear(&mut self) -> TripleResult<()> { - self.redis_connection.del(&self.triple_key())?; - self.redis_connection.del(&self.mine_key())?; + self.redis_connection.del::<&str, ()>(&self.triple_key())?; + self.redis_connection.del::<&str, ()>(&self.mine_key())?; Ok(()) } From b764321e0a473363a16e013b283cd970da361846 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 24 Oct 2024 12:36:32 +0300 Subject: [PATCH 38/64] 2 triple pre-check added --- chain-signatures/node/src/protocol/presignature.rs | 2 -- chain-signatures/node/src/protocol/triple.rs | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index fdab557e7..1b9828bf1 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -465,8 +465,6 @@ impl PresignatureManager { ) .await?; } - } else { - tracing::warn!("running: we don't have enough triples to generate a presignature"); } } diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index 287c066dc..95c42db69 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -236,6 +236,8 @@ impl TripleManager { self.gc.insert(id0, Instant::now()); self.gc.insert(id1, Instant::now()); + tracing::info!(id0, id1, "took two triples"); + Ok((triple_0, triple_1)) } @@ -243,6 +245,10 @@ impl TripleManager { /// It is very important to NOT reuse the same triple twice for two different /// protocols. pub async fn take_two_mine(&mut self) -> Option<(Triple, Triple)> { + if self.count_mine().await < 2 { + tracing::warn!("not enough mine triples"); + return None; + } let triple_0 = match self.triple_storage.write().await.take_mine() { Ok(Some(triple)) => triple, Ok(None) => { @@ -276,6 +282,8 @@ impl TripleManager { self.gc.insert(triple_0.id, Instant::now()); self.gc.insert(triple_1.id, Instant::now()); + tracing::info!(triple_0.id, triple_1.id, "took two mine triples"); + Some((triple_0, triple_1)) } From f10bafca4e47645a23cd76e7bb1b0f2b330de55f Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Mon, 28 Oct 2024 23:00:04 +0200 Subject: [PATCH 39/64] add link to redis in setup-env --- integration-tests/chain-signatures/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/integration-tests/chain-signatures/src/main.rs b/integration-tests/chain-signatures/src/main.rs index 5d8f919ac..65e1548f1 100644 --- a/integration-tests/chain-signatures/src/main.rs +++ b/integration-tests/chain-signatures/src/main.rs @@ -50,6 +50,7 @@ async fn main() -> anyhow::Result<()> { println!("\nExternal services:"); println!(" datastore: {}", ctx.datastore.local_address); println!(" lake_indexer: {}", ctx.lake_indexer.rpc_host_address); + println!(" redis: {}", ctx.redis.internal_address); println!("\nNodes:"); for i in 0..urls.len() { From 41a46ce3308d2309f3dd590c6cc0572206a37d11 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 29 Oct 2024 15:55:14 +0200 Subject: [PATCH 40/64] use redis connection pool --- chain-signatures/Cargo.lock | 51 ++++++++++ chain-signatures/node/Cargo.toml | 1 + chain-signatures/node/src/cli.rs | 8 +- .../node/src/protocol/consensus.rs | 4 +- .../node/src/protocol/presignature.rs | 33 +++++-- chain-signatures/node/src/protocol/triple.rs | 48 +++++++--- .../node/src/storage/presignature_storage.rs | 95 ++++++++++--------- .../node/src/storage/triple_storage.rs | 87 +++++++++-------- integration-tests/chain-signatures/Cargo.lock | 46 ++++++++- integration-tests/chain-signatures/Cargo.toml | 1 + integration-tests/chain-signatures/src/lib.rs | 6 +- .../chain-signatures/tests/cases/mod.rs | 9 +- 12 files changed, 265 insertions(+), 124 deletions(-) diff --git a/chain-signatures/Cargo.lock b/chain-signatures/Cargo.lock index fecf0a24a..90bf3f840 100644 --- a/chain-signatures/Cargo.lock +++ b/chain-signatures/Cargo.lock @@ -1310,7 +1310,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", + "futures-core", "memchr", + "pin-project-lite", + "tokio", + "tokio-util", ] [[package]] @@ -1601,6 +1605,36 @@ dependencies = [ "syn 2.0.72", ] +[[package]] +name = "deadpool" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6541a3916932fe57768d4be0b1ffb5ec7cbf74ca8c903fdfd5c0fe8aa958f0ed" +dependencies = [ + "deadpool-runtime", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-redis" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfae6799b68a735270e4344ee3e834365f707c72da09c9a8bb89b45cc3351395" +dependencies = [ + "deadpool", + "redis", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" +dependencies = [ + "tokio", +] + [[package]] name = "debugid" version = "0.7.3" @@ -3190,6 +3224,7 @@ dependencies = [ "chrono", "clap", "crypto-shared", + "deadpool-redis", "google-datastore1", "google-secretmanager1", "hex", @@ -4131,6 +4166,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + [[package]] name = "num_threads" version = "0.1.7" @@ -4702,13 +4747,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6baebe319ef5e4b470f248335620098d1c2e9261e995be05f56f719ca4bdb2" dependencies = [ "arc-swap", + "async-trait", + "bytes", "combine", + "futures-util", "itoa", "num-bigint 0.4.6", "percent-encoding 2.3.1", + "pin-project-lite", "ryu", "sha1_smol", "socket2 0.5.7", + "tokio", + "tokio-util", "url 2.5.2", ] diff --git a/chain-signatures/node/Cargo.toml b/chain-signatures/node/Cargo.toml index cdd8ce22e..81ca8408f 100644 --- a/chain-signatures/node/Cargo.toml +++ b/chain-signatures/node/Cargo.toml @@ -61,4 +61,5 @@ http = "1.1.0" prometheus = { version = "0.13.3" } once_cell = "1.13.1" redis = "0.27.2" +deadpool-redis = "0.18.0" sysinfo = "0.32.0" diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 04569f461..85042f6aa 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -5,6 +5,7 @@ use crate::storage::presignature_storage::LockPresignatureRedisStorage; use crate::storage::triple_storage::LockTripleRedisStorage; use crate::{http_client, indexer, mesh, storage, web}; use clap::Parser; +use deadpool_redis::Runtime; use local_ip_address::local_ip; use near_account_id::AccountId; use near_crypto::{InMemorySigner, SecretKey}; @@ -210,12 +211,15 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let redis_url: Url = Url::parse(storage_options.redis_url.as_str())?; + let redis_cfg = deadpool_redis::Config::from_url(redis_url); + let redis_pool = redis_cfg.create_pool(Some(Runtime::Tokio1)).unwrap(); + let triple_storage: LockTripleRedisStorage = Arc::new(RwLock::new( - storage::triple_storage::init(redis_url.clone(), &account_id), + storage::triple_storage::init(redis_pool.clone(), &account_id), )); let presignature_storage: LockPresignatureRedisStorage = Arc::new(RwLock::new( - storage::presignature_storage::init(redis_url, &account_id), + storage::presignature_storage::init(redis_pool.clone(), &account_id), )); let sign_sk = sign_sk.unwrap_or_else(|| account_sk.clone()); diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index 793fcb209..af070acbd 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -361,14 +361,14 @@ impl ConsensusProtocol for WaitingForConsensusState { // Clear triples from storage before starting the new epoch. This is necessary if the node has accumulated // triples from previous epochs. If it was not able to clear the previous triples, we'll leave them as-is - if let Err(err) = ctx.triple_storage().write().await.clear() { + if let Err(err) = ctx.triple_storage().write().await.clear().await { tracing::error!( ?err, "failed to clear triples from storage on new epoch start" ); } - if let Err(err) = ctx.presignature_storage().write().await.clear() { + if let Err(err) = ctx.presignature_storage().write().await.clear().await { tracing::error!( ?err, "failed to clear presignatures from storage on new epoch start" diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 1b9828bf1..c0238a3a5 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -189,7 +189,13 @@ impl PresignatureManager { tracing::info!(id = ?presignature.id, "inserting presignature"); // Remove from taken list if it was there self.gc.remove(&presignature.id); - if let Err(e) = self.presignature_storage.write().await.insert(presignature) { + if let Err(e) = self + .presignature_storage + .write() + .await + .insert(presignature) + .await + { tracing::error!(?e, "failed to insert presignature"); } } @@ -203,6 +209,7 @@ impl PresignatureManager { .write() .await .insert_mine(presignature) + .await { tracing::error!(?e, "failed to insert mine presignature"); } @@ -214,6 +221,7 @@ impl PresignatureManager { .write() .await .contains(id) + .await .map_err(|e| { tracing::warn!(?e, "failed to check if presignature exist"); }) @@ -226,6 +234,7 @@ impl PresignatureManager { .write() .await .contains_mine(id) + .await .map_err(|e| { tracing::warn!(?e, "failed to check if mine presignature exist"); }) @@ -233,15 +242,16 @@ impl PresignatureManager { } pub async fn take(&mut self, id: PresignatureId) -> Result { - if let Some(presignature) = - self.presignature_storage - .write() - .await - .take(&id) - .map_err(|e| { - tracing::error!(?e, "failed to look for presignature"); - GenerationError::PresignatureIsMissing(id) - })? + if let Some(presignature) = self + .presignature_storage + .write() + .await + .take(&id) + .await + .map_err(|e| { + tracing::error!(?e, "failed to look for presignature"); + GenerationError::PresignatureIsMissing(id) + })? { self.gc.insert(id, Instant::now()); tracing::info!(id, "took presignature"); @@ -266,6 +276,7 @@ impl PresignatureManager { .write() .await .take_mine() + .await .map_err(|e| { tracing::error!(?e, "failed to look for mine presignature"); }) @@ -283,6 +294,7 @@ impl PresignatureManager { .write() .await .count_all() + .await .map_err(|e| { tracing::error!(?e, "failed to count all presignatures"); }) @@ -295,6 +307,7 @@ impl PresignatureManager { .write() .await .count_mine() + .await .map_err(|e| { tracing::error!(?e, "failed to count mine presignatures"); }) diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index 95c42db69..dece6b98f 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -147,7 +147,7 @@ impl TripleManager { pub async fn insert(&mut self, triple: Triple) { tracing::info!(id = triple.id, "inserting triple"); self.gc.remove(&triple.id); - if let Err(e) = self.triple_storage.write().await.insert(triple) { + if let Err(e) = self.triple_storage.write().await.insert(triple).await { tracing::warn!(?e, "failed to insert triple"); } } @@ -155,7 +155,7 @@ impl TripleManager { pub async fn insert_mine(&mut self, triple: Triple) { tracing::debug!(id = triple.id, "inserting mine triple"); self.gc.remove(&triple.id); - if let Err(e) = self.triple_storage.write().await.insert_mine(triple) { + if let Err(e) = self.triple_storage.write().await.insert_mine(triple).await { tracing::warn!(?e, "failed to insert mine triple"); } } @@ -165,6 +165,7 @@ impl TripleManager { .write() .await .contains(id) + .await .map_err(|e| tracing::warn!(?e, "failed to check if triple exists")) .unwrap_or(false) } @@ -174,6 +175,7 @@ impl TripleManager { .write() .await .contains_mine(id) + .await .map_err(|e| tracing::warn!(?e, "failed to check if mine triple exists")) .unwrap_or(false) } @@ -187,7 +189,7 @@ impl TripleManager { id0: TripleId, id1: TripleId, ) -> Result<(Triple, Triple), GenerationError> { - let triple_0 = match self.triple_storage.write().await.take(&id0) { + let triple_0 = match self.triple_storage.write().await.take(&id0).await { Ok(Some(triple)) => triple, Ok(None) => { if self.generators.contains_key(&id0) { @@ -207,10 +209,10 @@ impl TripleManager { } }; - let triple_1 = match self.triple_storage.write().await.take(&id1) { + let triple_1 = match self.triple_storage.write().await.take(&id1).await { Ok(Some(triple)) => triple, Ok(None) => { - if let Err(e) = self.triple_storage.write().await.insert(triple_0) { + if let Err(e) = self.triple_storage.write().await.insert(triple_0).await { tracing::warn!(id0, ?e, "failed to insert triple back"); } if self.generators.contains_key(&id1) { @@ -226,7 +228,7 @@ impl TripleManager { } Err(e) => { tracing::warn!(id1, ?e, "failed to take triple"); - if let Err(e) = self.triple_storage.write().await.insert(triple_0) { + if let Err(e) = self.triple_storage.write().await.insert(triple_0).await { tracing::warn!(id0, ?e, "failed to insert triple back"); } return Err(GenerationError::TripleIsMissing(id1)); @@ -249,7 +251,7 @@ impl TripleManager { tracing::warn!("not enough mine triples"); return None; } - let triple_0 = match self.triple_storage.write().await.take_mine() { + let triple_0 = match self.triple_storage.write().await.take_mine().await { Ok(Some(triple)) => triple, Ok(None) => { tracing::warn!("no mine triple left"); @@ -261,10 +263,16 @@ impl TripleManager { } }; - let triple_1 = match self.triple_storage.write().await.take_mine() { + let triple_1 = match self.triple_storage.write().await.take_mine().await { Ok(Some(triple)) => triple, Ok(None) => { - if let Err(e) = self.triple_storage.write().await.insert_mine(triple_0) { + if let Err(e) = self + .triple_storage + .write() + .await + .insert_mine(triple_0) + .await + { tracing::warn!(?e, "failed to insert mine triple back"); } tracing::warn!("no mine triple left"); @@ -272,7 +280,13 @@ impl TripleManager { } Err(e) => { tracing::warn!(?e, "failed to take mine triple"); - if let Err(e) = self.triple_storage.write().await.insert_mine(triple_0) { + if let Err(e) = self + .triple_storage + .write() + .await + .insert_mine(triple_0) + .await + { tracing::warn!(?e, "failed to insert mine triple back"); } return None; @@ -289,12 +303,22 @@ impl TripleManager { /// Returns the number of unspent triples available in the manager. pub async fn count_all(&self) -> usize { - self.triple_storage.write().await.count_all().unwrap_or(0) + self.triple_storage + .write() + .await + .count_all() + .await + .unwrap_or(0) } /// Returns the number of unspent triples assigned to this node. pub async fn count_mine(&self) -> usize { - self.triple_storage.write().await.count_mine().unwrap_or(0) + self.triple_storage + .write() + .await + .count_mine() + .await + .unwrap_or(0) } /// Returns if there's any unspent triple in the manager. diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index c820167b7..e955daccb 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -1,10 +1,10 @@ use std::sync::Arc; use anyhow::Ok; +use deadpool_redis::Pool; use near_sdk::AccountId; -use redis::{Commands, Connection, FromRedisValue, RedisWrite, ToRedisArgs}; +use redis::{AsyncCommands, FromRedisValue, RedisWrite, ToRedisArgs}; use tokio::sync::RwLock; -use url::Url; use crate::protocol::presignature::{Presignature, PresignatureId}; @@ -14,98 +14,99 @@ pub type LockPresignatureRedisStorage = Arc>; // Can be used to "clear" redis storage in case of a breaking change const PRESIGNATURE_STORAGE_VERSION: &str = "v1"; -pub fn init(redis_url: Url, node_account_id: &AccountId) -> PresignatureRedisStorage { - PresignatureRedisStorage::new(redis_url, node_account_id) +pub fn init(redis_pool: Pool, node_account_id: &AccountId) -> PresignatureRedisStorage { + PresignatureRedisStorage { + redis_pool, + node_account_id: node_account_id.clone(), + } } pub struct PresignatureRedisStorage { - redis_connection: Connection, + redis_pool: Pool, node_account_id: AccountId, } impl PresignatureRedisStorage { - fn new(redis_url: Url, node_account_id: &AccountId) -> Self { - Self { - redis_connection: redis::Client::open(redis_url.as_str()) - .expect("Failed to connect to Redis") - .get_connection() - .expect("Failed to get Redis connection"), - node_account_id: node_account_id.clone(), - } - } -} - -impl PresignatureRedisStorage { - pub fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { - self.redis_connection + pub async fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { + let mut connection = self.redis_pool.get().await?; + connection .hset::<&str, PresignatureId, Presignature, ()>( - &self.presignature_key(), + &self.presig_key(), presignature.id, presignature, - )?; + ) + .await?; Ok(()) } - pub fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()> { - self.redis_connection - .sadd::<&str, PresignatureId, ()>(&self.mine_key(), presignature.id)?; - self.insert(presignature)?; + pub async fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()> { + let mut connection = self.redis_pool.get().await?; + connection + .sadd::<&str, PresignatureId, ()>(&self.mine_key(), presignature.id) + .await?; + self.insert(presignature).await?; Ok(()) } - pub fn contains(&mut self, id: &PresignatureId) -> PresigResult { - let result: bool = self.redis_connection.hexists(self.presignature_key(), id)?; + pub async fn contains(&mut self, id: &PresignatureId) -> PresigResult { + let mut connection = self.redis_pool.get().await?; + let result: bool = connection.hexists(self.presig_key(), id).await?; Ok(result) } - pub fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult { - let result: bool = self.redis_connection.sismember(self.mine_key(), id)?; + pub async fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult { + let mut connection = self.redis_pool.get().await?; + let result: bool = connection.sismember(self.mine_key(), id).await?; Ok(result) } - pub fn take(&mut self, id: &PresignatureId) -> PresigResult> { - if self.contains_mine(id)? { + pub async fn take(&mut self, id: &PresignatureId) -> PresigResult> { + let mut connection = self.redis_pool.get().await?; + if self.contains_mine(id).await? { tracing::error!("Can not take mine presignature as foreign: {:?}", id); return Ok(None); } - let result: Option = - self.redis_connection.hget(self.presignature_key(), id)?; + let result: Option = connection.hget(self.presig_key(), id).await?; match result { Some(presignature) => { - self.redis_connection - .hdel::<&str, PresignatureId, ()>(&self.presignature_key(), *id)?; + connection + .hdel::<&str, PresignatureId, ()>(&self.presig_key(), *id) + .await?; Ok(Some(presignature)) } None => Ok(None), } } - pub fn take_mine(&mut self) -> PresigResult> { - let id: Option = self.redis_connection.spop(self.mine_key())?; + pub async fn take_mine(&mut self) -> PresigResult> { + let mut connection = self.redis_pool.get().await?; + let id: Option = connection.spop(self.mine_key()).await?; match id { - Some(id) => self.take(&id), + Some(id) => self.take(&id).await, None => Ok(None), } } - pub fn count_all(&mut self) -> PresigResult { - let result: usize = self.redis_connection.hlen(self.presignature_key())?; + pub async fn count_all(&mut self) -> PresigResult { + let mut connection = self.redis_pool.get().await?; + let result: usize = connection.hlen(self.presig_key()).await?; Ok(result) } - pub fn count_mine(&mut self) -> PresigResult { - let result: usize = self.redis_connection.scard(self.mine_key())?; + pub async fn count_mine(&mut self) -> PresigResult { + let mut connection = self.redis_pool.get().await?; + let result: usize = connection.scard(self.mine_key()).await?; Ok(result) } - pub fn clear(&mut self) -> PresigResult<()> { - self.redis_connection - .del::<&str, ()>(&self.presignature_key())?; - self.redis_connection.del::<&str, ()>(&self.mine_key())?; + pub async fn clear(&mut self) -> PresigResult<()> { + let mut connection = self.redis_pool.get().await?; + connection.del::<&str, ()>(&self.presig_key()).await?; + connection.del::<&str, ()>(&self.mine_key()).await?; Ok(()) } - fn presignature_key(&self) -> String { + fn presig_key(&self) -> String { format!( "presignatures:{}:{}", PRESIGNATURE_STORAGE_VERSION, self.node_account_id diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index f24039dee..98ef1418f 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -1,11 +1,11 @@ use crate::protocol::triple::{Triple, TripleId}; use std::sync::Arc; -use redis::{Commands, Connection, FromRedisValue, RedisWrite, ToRedisArgs}; +use deadpool_redis::Pool; +use redis::{AsyncCommands, FromRedisValue, RedisWrite, ToRedisArgs}; use tokio::sync::RwLock; use near_account_id::AccountId; -use url::Url; pub type LockTripleRedisStorage = Arc>; type TripleResult = std::result::Result; @@ -13,89 +13,88 @@ type TripleResult = std::result::Result; // Can be used to "clear" redis storage in case of a breaking change const TRIPLE_STORAGE_VERSION: &str = "v1"; -pub fn init(redis_url: Url, account_id: &AccountId) -> TripleRedisStorage { - TripleRedisStorage::new(redis_url, account_id) +pub fn init(redis_pool: Pool, account_id: &AccountId) -> TripleRedisStorage { + TripleRedisStorage { + redis_pool, + node_account_id: account_id.clone(), + } } pub struct TripleRedisStorage { - redis_connection: Connection, + redis_pool: Pool, node_account_id: AccountId, } impl TripleRedisStorage { - fn new(redis_url: Url, account_id: &AccountId) -> Self { - Self { - redis_connection: redis::Client::open(redis_url.as_str()) - .expect("Failed to connect to Redis") - .get_connection() - .expect("Failed to get Redis connection"), - node_account_id: account_id.clone(), - } - } - - pub fn insert(&mut self, triple: Triple) -> TripleResult<()> { - self.redis_connection.hset::<&str, TripleId, Triple, ()>( - &self.triple_key(), - triple.id, - triple, - )?; + pub async fn insert(&mut self, triple: Triple) -> TripleResult<()> { + let mut conn = self.redis_pool.get().await?; + conn.hset::<&str, TripleId, Triple, ()>(&self.triple_key(), triple.id, triple) + .await?; Ok(()) } - pub fn insert_mine(&mut self, triple: Triple) -> TripleResult<()> { - self.redis_connection - .sadd::<&str, TripleId, ()>(&self.mine_key(), triple.id)?; - self.insert(triple)?; + pub async fn insert_mine(&mut self, triple: Triple) -> TripleResult<()> { + let mut conn = self.redis_pool.get().await?; + conn.sadd::<&str, TripleId, ()>(&self.mine_key(), triple.id) + .await?; + self.insert(triple).await?; Ok(()) } - pub fn contains(&mut self, id: &TripleId) -> TripleResult { - let result: bool = self.redis_connection.hexists(self.triple_key(), id)?; + pub async fn contains(&mut self, id: &TripleId) -> TripleResult { + let mut conn = self.redis_pool.get().await?; + let result: bool = conn.hexists(self.triple_key(), id).await?; Ok(result) } - pub fn contains_mine(&mut self, id: &TripleId) -> TripleResult { - let result: bool = self.redis_connection.sismember(self.mine_key(), id)?; + pub async fn contains_mine(&mut self, id: &TripleId) -> TripleResult { + let mut conn = self.redis_pool.get().await?; + let result: bool = conn.sismember(self.mine_key(), id).await?; Ok(result) } - pub fn take(&mut self, id: &TripleId) -> TripleResult> { - if self.contains_mine(id)? { + pub async fn take(&mut self, id: &TripleId) -> TripleResult> { + let mut conn = self.redis_pool.get().await?; + if self.contains_mine(id).await? { tracing::error!("Can not take mine triple as foreign: {:?}", id); return Ok(None); } - let result: Option = self.redis_connection.hget(self.triple_key(), id)?; + let result: Option = conn.hget(self.triple_key(), id).await?; match result { Some(triple) => { - self.redis_connection - .hdel::<&str, TripleId, ()>(&self.triple_key(), *id)?; + conn.hdel::<&str, TripleId, ()>(&self.triple_key(), *id) + .await?; Ok(Some(triple)) } None => Ok(None), } } - pub fn take_mine(&mut self) -> TripleResult> { - let id: Option = self.redis_connection.spop(self.mine_key())?; + pub async fn take_mine(&mut self) -> TripleResult> { + let mut conn = self.redis_pool.get().await?; + let id: Option = conn.spop(self.mine_key()).await?; match id { - Some(id) => self.take(&id), + Some(id) => self.take(&id).await, None => Ok(None), } } - pub fn count_all(&mut self) -> TripleResult { - let result: usize = self.redis_connection.hlen(self.triple_key())?; + pub async fn count_all(&mut self) -> TripleResult { + let mut conn = self.redis_pool.get().await?; + let result: usize = conn.hlen(self.triple_key()).await?; Ok(result) } - pub fn count_mine(&mut self) -> TripleResult { - let result: usize = self.redis_connection.scard(self.mine_key())?; + pub async fn count_mine(&mut self) -> TripleResult { + let mut conn = self.redis_pool.get().await?; + let result: usize = conn.scard(self.mine_key()).await?; Ok(result) } - pub fn clear(&mut self) -> TripleResult<()> { - self.redis_connection.del::<&str, ()>(&self.triple_key())?; - self.redis_connection.del::<&str, ()>(&self.mine_key())?; + pub async fn clear(&mut self) -> TripleResult<()> { + let mut conn = self.redis_pool.get().await?; + conn.del::<&str, ()>(&self.triple_key()).await?; + conn.del::<&str, ()>(&self.mine_key()).await?; Ok(()) } diff --git a/integration-tests/chain-signatures/Cargo.lock b/integration-tests/chain-signatures/Cargo.lock index 6f2d03ed8..67e027189 100644 --- a/integration-tests/chain-signatures/Cargo.lock +++ b/integration-tests/chain-signatures/Cargo.lock @@ -377,9 +377,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", @@ -1397,7 +1397,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ "bytes", + "futures-core", "memchr", + "pin-project-lite", + "tokio", + "tokio-util", ] [[package]] @@ -1713,6 +1717,36 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "deadpool" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6541a3916932fe57768d4be0b1ffb5ec7cbf74ca8c903fdfd5c0fe8aa958f0ed" +dependencies = [ + "deadpool-runtime", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-redis" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfae6799b68a735270e4344ee3e834365f707c72da09c9a8bb89b45cc3351395" +dependencies = [ + "deadpool", + "redis", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" +dependencies = [ + "tokio", +] + [[package]] name = "debugid" version = "0.7.3" @@ -3284,6 +3318,7 @@ dependencies = [ "cait-sith", "clap", "crypto-shared", + "deadpool-redis", "ecdsa 0.16.9", "elliptic-curve 0.13.8", "ethers-core", @@ -3715,6 +3750,7 @@ dependencies = [ "chrono", "clap", "crypto-shared", + "deadpool-redis", "google-datastore1", "google-secretmanager1", "hex", @@ -5387,13 +5423,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6baebe319ef5e4b470f248335620098d1c2e9261e995be05f56f719ca4bdb2" dependencies = [ "arc-swap", + "async-trait", + "bytes", "combine", + "futures-util", "itoa", "num-bigint 0.4.6", "percent-encoding 2.3.1", + "pin-project-lite", "ryu", "sha1_smol", "socket2 0.5.7", + "tokio", + "tokio-util", "url 2.5.1", ] diff --git a/integration-tests/chain-signatures/Cargo.toml b/integration-tests/chain-signatures/Cargo.toml index 0712fba45..1b80084b6 100644 --- a/integration-tests/chain-signatures/Cargo.toml +++ b/integration-tests/chain-signatures/Cargo.toml @@ -28,6 +28,7 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } thiserror = "1" url = { version = "2.4.0", features = ["serde"] } +deadpool-redis = "0.18.0" # crypto dependencies cait-sith = { git = "https://github.com/LIT-Protocol/cait-sith.git", features = [ diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 328061cf2..028f203a3 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -3,6 +3,7 @@ pub mod execute; pub mod local; pub mod utils; +use deadpool_redis::Pool; use std::collections::HashMap; use self::local::NodeConfig; @@ -25,7 +26,6 @@ use near_workspaces::types::{KeyType, SecretKey}; use near_workspaces::{Account, AccountId, Contract, Worker}; use serde_json::json; use testcontainers::{Container, GenericImage}; -use url::Url; const NETWORK: &str = "mpc_it_network"; @@ -158,10 +158,10 @@ impl Nodes<'_> { pub async fn triple_storage( &self, - redis_url: Url, + redis_pool: Pool, account_id: &AccountId, ) -> TripleRedisStorage { - storage::triple_storage::init(redis_url, account_id) + storage::triple_storage::init(redis_pool, account_id) } pub async fn gcp_services(&self) -> anyhow::Result> { diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 36007a21a..c3daac370 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -8,6 +8,7 @@ use cait_sith::protocol::Participant; use cait_sith::triples::{TriplePub, TripleShare}; use cait_sith::PresignOutput; use crypto_shared::{self, derive_epsilon, derive_key, x_coordinate, ScalarExt}; +use deadpool_redis::Runtime; use elliptic_curve::CurveArithmetic; use integration_tests_chain_signatures::containers::{self, DockerClient}; use integration_tests_chain_signatures::MultichainConfig; @@ -217,8 +218,10 @@ async fn test_triple_persistence() -> anyhow::Result<()> { docker_client.create_network(docker_network).await?; let redis = containers::Redis::run(&docker_client, docker_network).await?; let redis_url = Url::parse(redis.internal_address.as_str())?; + let redis_cfg = deadpool_redis::Config::from_url(redis_url); + let redis_pool = redis_cfg.create_pool(Some(Runtime::Tokio1)).unwrap(); let triple_storage: storage::triple_storage::LockTripleRedisStorage = Arc::new(RwLock::new( - storage::triple_storage::init(redis_url, &AccountId::from_str("test.near").unwrap()), + storage::triple_storage::init(redis_pool.clone(), &AccountId::from_str("test.near").unwrap()), )); let mut triple_manager = TripleManager::new( @@ -304,8 +307,10 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { docker_client.create_network(docker_network).await?; let redis = containers::Redis::run(&docker_client, docker_network).await?; let redis_url = Url::parse(redis.internal_address.as_str())?; + let redis_cfg = deadpool_redis::Config::from_url(redis_url); + let redis_pool = redis_cfg.create_pool(Some(Runtime::Tokio1)).unwrap(); let presignature_storage: LockPresignatureRedisStorage = Arc::new(RwLock::new( - storage::presignature_storage::init(redis_url, &AccountId::from_str("test.near").unwrap()), + storage::presignature_storage::init(redis_pool.clone(), &AccountId::from_str("test.near").unwrap()), )); let mut presignature_manager = PresignatureManager::new( Participant::from(0), From 900d0d541ec425190db874a47dc21138fcb71805 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 29 Oct 2024 16:07:06 +0200 Subject: [PATCH 41/64] fmt --- .../chain-signatures/tests/cases/mod.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index c3daac370..cff300df9 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -220,9 +220,11 @@ async fn test_triple_persistence() -> anyhow::Result<()> { let redis_url = Url::parse(redis.internal_address.as_str())?; let redis_cfg = deadpool_redis::Config::from_url(redis_url); let redis_pool = redis_cfg.create_pool(Some(Runtime::Tokio1)).unwrap(); - let triple_storage: storage::triple_storage::LockTripleRedisStorage = Arc::new(RwLock::new( - storage::triple_storage::init(redis_pool.clone(), &AccountId::from_str("test.near").unwrap()), - )); + let triple_storage: storage::triple_storage::LockTripleRedisStorage = + Arc::new(RwLock::new(storage::triple_storage::init( + redis_pool.clone(), + &AccountId::from_str("test.near").unwrap(), + ))); let mut triple_manager = TripleManager::new( Participant::from(0), @@ -309,9 +311,11 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { let redis_url = Url::parse(redis.internal_address.as_str())?; let redis_cfg = deadpool_redis::Config::from_url(redis_url); let redis_pool = redis_cfg.create_pool(Some(Runtime::Tokio1)).unwrap(); - let presignature_storage: LockPresignatureRedisStorage = Arc::new(RwLock::new( - storage::presignature_storage::init(redis_pool.clone(), &AccountId::from_str("test.near").unwrap()), - )); + let presignature_storage: LockPresignatureRedisStorage = + Arc::new(RwLock::new(storage::presignature_storage::init( + redis_pool.clone(), + &AccountId::from_str("test.near").unwrap(), + ))); let mut presignature_manager = PresignatureManager::new( Participant::from(0), 5, From b83ba1b312b603f202c24e9801a48ea790e52923 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 29 Oct 2024 16:22:21 +0200 Subject: [PATCH 42/64] change info to debug in storage layer --- chain-signatures/node/src/protocol/presignature.rs | 8 ++++---- chain-signatures/node/src/protocol/triple.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index c0238a3a5..8c94b0b3c 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -186,7 +186,7 @@ impl PresignatureManager { } pub async fn insert(&mut self, presignature: Presignature) { - tracing::info!(id = ?presignature.id, "inserting presignature"); + tracing::debug!(id = ?presignature.id, "inserting presignature"); // Remove from taken list if it was there self.gc.remove(&presignature.id); if let Err(e) = self @@ -201,7 +201,7 @@ impl PresignatureManager { } pub async fn insert_mine(&mut self, presignature: Presignature) { - tracing::info!(id = ?presignature.id, "inserting mine presignature"); + tracing::debug!(id = ?presignature.id, "inserting mine presignature"); // Remove from taken list if it was there self.gc.remove(&presignature.id); if let Err(e) = self @@ -254,7 +254,7 @@ impl PresignatureManager { })? { self.gc.insert(id, Instant::now()); - tracing::info!(id, "took presignature"); + tracing::debug!(id, "took presignature"); return Ok(presignature); }; @@ -282,7 +282,7 @@ impl PresignatureManager { }) .ok()? { - tracing::info!(id = ?presignature.id, "took presignature of mine"); + tracing::debug!(id = ?presignature.id, "took presignature of mine"); return Some(presignature); } None diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index dece6b98f..7f4edd624 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -145,7 +145,7 @@ impl TripleManager { } pub async fn insert(&mut self, triple: Triple) { - tracing::info!(id = triple.id, "inserting triple"); + tracing::debug!(id = triple.id, "inserting triple"); self.gc.remove(&triple.id); if let Err(e) = self.triple_storage.write().await.insert(triple).await { tracing::warn!(?e, "failed to insert triple"); @@ -238,7 +238,7 @@ impl TripleManager { self.gc.insert(id0, Instant::now()); self.gc.insert(id1, Instant::now()); - tracing::info!(id0, id1, "took two triples"); + tracing::debug!(id0, id1, "took two triples"); Ok((triple_0, triple_1)) } @@ -296,7 +296,7 @@ impl TripleManager { self.gc.insert(triple_0.id, Instant::now()); self.gc.insert(triple_1.id, Instant::now()); - tracing::info!(triple_0.id, triple_1.id, "took two mine triples"); + tracing::debug!(triple_0.id, triple_1.id, "took two mine triples"); Some((triple_0, triple_1)) } From 54e3c499a871011a8e0b30f7f315248f84b2684c Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 29 Oct 2024 16:32:04 +0200 Subject: [PATCH 43/64] rename count to lem --- .../node/src/protocol/cryptography.rs | 12 ++-- .../node/src/protocol/presignature.rs | 18 +++--- chain-signatures/node/src/protocol/triple.rs | 24 ++++---- .../node/src/storage/presignature_storage.rs | 4 +- .../node/src/storage/triple_storage.rs | 4 +- chain-signatures/node/src/web/mod.rs | 12 ++-- .../chain-signatures/tests/cases/mod.rs | 60 +++++++++---------- 7 files changed, 67 insertions(+), 67 deletions(-) diff --git a/chain-signatures/node/src/protocol/cryptography.rs b/chain-signatures/node/src/protocol/cryptography.rs index 85ea6b074..24faac927 100644 --- a/chain-signatures/node/src/protocol/cryptography.rs +++ b/chain-signatures/node/src/protocol/cryptography.rs @@ -382,10 +382,10 @@ impl CryptographicProtocol for RunningState { crate::metrics::NUM_TRIPLES_MINE .with_label_values(&[my_account_id.as_str()]) - .set(triple_manager.count_mine().await as i64); + .set(triple_manager.len_mine().await as i64); crate::metrics::NUM_TRIPLES_TOTAL .with_label_values(&[my_account_id.as_str()]) - .set(triple_manager.count_all().await as i64); + .set(triple_manager.len_generated().await as i64); crate::metrics::NUM_TRIPLE_GENERATORS_INTRODUCED .with_label_values(&[my_account_id.as_str()]) .set(triple_manager.introduced.len() as i64); @@ -414,15 +414,15 @@ impl CryptographicProtocol for RunningState { crate::metrics::NUM_PRESIGNATURES_MINE .with_label_values(&[my_account_id.as_str()]) - .set(presignature_manager.count_mine().await as i64); + .set(presignature_manager.len_mine().await as i64); crate::metrics::NUM_PRESIGNATURES_TOTAL .with_label_values(&[my_account_id.as_str()]) - .set(presignature_manager.count_all().await as i64); + .set(presignature_manager.len_generated().await as i64); crate::metrics::NUM_PRESIGNATURE_GENERATORS_TOTAL .with_label_values(&[my_account_id.as_str()]) .set( - presignature_manager.count_potential().await as i64 - - presignature_manager.count_all().await as i64, + presignature_manager.len_potential().await as i64 + - presignature_manager.len_generated().await as i64, ); // NOTE: signatures should only use stable and not active participants. The difference here is that diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 8c94b0b3c..233c54983 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -289,11 +289,11 @@ impl PresignatureManager { } /// Returns the number of unspent presignatures available in the manager. - pub async fn count_all(&self) -> usize { + pub async fn len_generated(&self) -> usize { self.presignature_storage .write() .await - .count_all() + .len_generated() .await .map_err(|e| { tracing::error!(?e, "failed to count all presignatures"); @@ -302,11 +302,11 @@ impl PresignatureManager { } /// Returns the number of unspent presignatures assigned to this node. - pub async fn count_mine(&self) -> usize { + pub async fn len_mine(&self) -> usize { self.presignature_storage .write() .await - .count_mine() + .len_mine() .await .map_err(|e| { tracing::error!(?e, "failed to count mine presignatures"); @@ -316,13 +316,13 @@ impl PresignatureManager { /// Returns if there are unspent presignatures available in the manager. pub async fn is_empty(&self) -> bool { - self.count_all().await == 0 + self.len_generated().await == 0 } /// Returns the number of unspent presignatures we will have in the manager once /// all ongoing generation protocols complete. - pub async fn count_potential(&self) -> usize { - let complete_presignatures = self.count_all().await; + pub async fn len_potential(&self) -> usize { + let complete_presignatures = self.len_generated().await; let ongoing_generators = self.generators.len(); complete_presignatures + ongoing_generators } @@ -440,11 +440,11 @@ impl PresignatureManager { // Stopgap to prevent too many presignatures in the system. This should be around min_presig*nodes*2 // for good measure so that we have enough presignatures to do sig generation while also maintain // the minimum number of presignature where a single node can't flood the system. - if self.count_potential().await >= cfg.presignature.max_presignatures as usize { + if self.len_potential().await >= cfg.presignature.max_presignatures as usize { false } else { // We will always try to generate a new triple if we have less than the minimum - self.count_mine().await < cfg.presignature.min_presignatures as usize + self.len_mine().await < cfg.presignature.min_presignatures as usize && self.introduced.len() < cfg.max_concurrent_introduction as usize } }; diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index 7f4edd624..d7399bce2 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -247,7 +247,7 @@ impl TripleManager { /// It is very important to NOT reuse the same triple twice for two different /// protocols. pub async fn take_two_mine(&mut self) -> Option<(Triple, Triple)> { - if self.count_mine().await < 2 { + if self.len_mine().await < 2 { tracing::warn!("not enough mine triples"); return None; } @@ -302,38 +302,38 @@ impl TripleManager { } /// Returns the number of unspent triples available in the manager. - pub async fn count_all(&self) -> usize { + pub async fn len_generated(&self) -> usize { self.triple_storage .write() .await - .count_all() + .len_generated() .await .unwrap_or(0) } /// Returns the number of unspent triples assigned to this node. - pub async fn count_mine(&self) -> usize { + pub async fn len_mine(&self) -> usize { self.triple_storage .write() .await - .count_mine() + .len_mine() .await .unwrap_or(0) } /// Returns if there's any unspent triple in the manager. pub async fn is_empty(&self) -> bool { - self.count_all().await == 0 + self.len_generated().await == 0 } /// Returns the number of unspent triples we will have in the manager once /// all ongoing generation protocols complete. - pub async fn count_potential(&self) -> usize { - self.count_all().await + self.generators.len() + pub async fn len_potential(&self) -> usize { + self.len_generated().await + self.generators.len() } pub async fn has_min_triples(&self, cfg: &ProtocolConfig) -> bool { - self.count_mine().await >= cfg.triple.min_triples as usize + self.len_mine().await >= cfg.triple.min_triples as usize } /// Clears an entry from failed triples if that triple protocol was created more than 2 hrs ago @@ -404,11 +404,11 @@ impl TripleManager { // Stopgap to prevent too many triples in the system. This should be around min_triple*nodes*2 // for good measure so that we have enough triples to do presig generation while also maintain // the minimum number of triples where a single node can't flood the system. - if self.count_potential().await >= cfg.triple.max_triples as usize { + if self.len_potential().await >= cfg.triple.max_triples as usize { false } else { // We will always try to generate a new triple if we have less than the minimum - self.count_mine().await < cfg.triple.min_triples as usize + self.len_mine().await < cfg.triple.min_triples as usize && self.introduced.len() < cfg.max_concurrent_introduction as usize && self.generators.len() < cfg.max_concurrent_generation as usize } @@ -436,7 +436,7 @@ impl TripleManager { if self.contains(&id).await || self.gc.contains_key(&id) { Ok(None) } else { - let potential_len = self.count_potential().await; + let potential_len = self.len_potential().await; match self.generators.entry(id) { Entry::Vacant(e) => { if potential_len >= cfg.triple.max_triples as usize { diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index e955daccb..f8b246845 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -87,13 +87,13 @@ impl PresignatureRedisStorage { } } - pub async fn count_all(&mut self) -> PresigResult { + pub async fn len_generated(&mut self) -> PresigResult { let mut connection = self.redis_pool.get().await?; let result: usize = connection.hlen(self.presig_key()).await?; Ok(result) } - pub async fn count_mine(&mut self) -> PresigResult { + pub async fn len_mine(&mut self) -> PresigResult { let mut connection = self.redis_pool.get().await?; let result: usize = connection.scard(self.mine_key()).await?; Ok(result) diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index 98ef1418f..9d128b219 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -79,13 +79,13 @@ impl TripleRedisStorage { } } - pub async fn count_all(&mut self) -> TripleResult { + pub async fn len_generated(&mut self) -> TripleResult { let mut conn = self.redis_pool.get().await?; let result: usize = conn.hlen(self.triple_key()).await?; Ok(result) } - pub async fn count_mine(&mut self) -> TripleResult { + pub async fn len_mine(&mut self) -> TripleResult { let mut conn = self.redis_pool.get().await?; let result: usize = conn.scard(self.mine_key()).await?; Ok(result) diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index 942117072..f3a2ec6fb 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -137,13 +137,13 @@ async fn state(Extension(state): Extension>) -> Result { let triple_manager_read = state.triple_manager.read().await; - let triple_potential_count = triple_manager_read.count_potential().await; - let triple_count = triple_manager_read.count_all().await; - let triple_mine_count = triple_manager_read.count_mine().await; + let triple_potential_count = triple_manager_read.len_potential().await; + let triple_count = triple_manager_read.len_generated().await; + let triple_mine_count = triple_manager_read.len_mine().await; let presignature_read = state.presignature_manager.read().await; - let presignature_count = presignature_read.count_all().await; - let presignature_mine_count = presignature_read.count_mine().await; - let presignature_potential_count = presignature_read.count_potential().await; + let presignature_count = presignature_read.len_generated().await; + let presignature_mine_count = presignature_read.len_mine().await; + let presignature_potential_count = presignature_read.len_potential().await; let participants = state.participants.keys_vec(); Ok(Json(StateView::Running { diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index cff300df9..8413af52e 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -242,10 +242,10 @@ async fn test_triple_persistence() -> anyhow::Result<()> { // Check that the storage is empty at the start assert!(!triple_manager.contains(&triple_id_1).await); assert!(!triple_manager.contains_mine(&triple_id_1).await); - assert_eq!(triple_manager.count_all().await, 0); - assert_eq!(triple_manager.count_mine().await, 0); + assert_eq!(triple_manager.len_generated().await, 0); + assert_eq!(triple_manager.len_mine().await, 0); assert!(triple_manager.is_empty().await); - assert_eq!(triple_manager.count_potential().await, 0); + assert_eq!(triple_manager.len_potential().await, 0); triple_manager.insert(triple_1).await; triple_manager.insert(triple_2).await; @@ -255,9 +255,9 @@ async fn test_triple_persistence() -> anyhow::Result<()> { assert!(triple_manager.contains(&triple_id_2).await); assert!(!triple_manager.contains_mine(&triple_id_1).await); assert!(!triple_manager.contains_mine(&triple_id_2).await); - assert_eq!(triple_manager.count_all().await, 2); - assert_eq!(triple_manager.count_mine().await, 0); - assert_eq!(triple_manager.count_potential().await, 2); + assert_eq!(triple_manager.len_generated().await, 2); + assert_eq!(triple_manager.len_mine().await, 0); + assert_eq!(triple_manager.len_potential().await, 2); // Take triple and check that it is removed from the storage triple_manager @@ -268,9 +268,9 @@ async fn test_triple_persistence() -> anyhow::Result<()> { assert!(!triple_manager.contains(&triple_id_2).await); assert!(!triple_manager.contains_mine(&triple_id_1).await); assert!(!triple_manager.contains_mine(&triple_id_2).await); - assert_eq!(triple_manager.count_all().await, 0); - assert_eq!(triple_manager.count_mine().await, 0); - assert_eq!(triple_manager.count_potential().await, 0); + assert_eq!(triple_manager.len_generated().await, 0); + assert_eq!(triple_manager.len_mine().await, 0); + assert_eq!(triple_manager.len_potential().await, 0); let mine_id_1: u64 = 3; let mine_triple_1 = dummy_triple(mine_id_1); @@ -284,9 +284,9 @@ async fn test_triple_persistence() -> anyhow::Result<()> { assert!(triple_manager.contains(&mine_id_2).await); assert!(triple_manager.contains_mine(&mine_id_1).await); assert!(triple_manager.contains_mine(&mine_id_2).await); - assert_eq!(triple_manager.count_all().await, 2); - assert_eq!(triple_manager.count_mine().await, 2); - assert_eq!(triple_manager.count_potential().await, 2); + assert_eq!(triple_manager.len_generated().await, 2); + assert_eq!(triple_manager.len_mine().await, 2); + assert_eq!(triple_manager.len_potential().await, 2); // Take mine triple and check that it is removed from the storage triple_manager.take_two_mine().await.unwrap(); @@ -294,10 +294,10 @@ async fn test_triple_persistence() -> anyhow::Result<()> { assert!(!triple_manager.contains(&mine_id_2).await); assert!(!triple_manager.contains_mine(&mine_id_1).await); assert!(!triple_manager.contains_mine(&mine_id_2).await); - assert_eq!(triple_manager.count_all().await, 0); - assert_eq!(triple_manager.count_mine().await, 0); + assert_eq!(triple_manager.len_generated().await, 0); + assert_eq!(triple_manager.len_mine().await, 0); assert!(triple_manager.is_empty().await); - assert_eq!(triple_manager.count_potential().await, 0); + assert_eq!(triple_manager.len_potential().await, 0); Ok(()) } @@ -330,27 +330,27 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { // Check that the storage is empty at the start assert!(!presignature_manager.contains(&presignature_id).await); assert!(!presignature_manager.contains_mine(&presignature_id).await); - assert_eq!(presignature_manager.count_all().await, 0); - assert_eq!(presignature_manager.count_mine().await, 0); + assert_eq!(presignature_manager.len_generated().await, 0); + assert_eq!(presignature_manager.len_mine().await, 0); assert!(presignature_manager.is_empty().await); - assert_eq!(presignature_manager.count_potential().await, 0); + assert_eq!(presignature_manager.len_potential().await, 0); presignature_manager.insert(presignature).await; // Check that the storage contains the foreign presignature assert!(presignature_manager.contains(&presignature_id).await); assert!(!presignature_manager.contains_mine(&presignature_id).await); - assert_eq!(presignature_manager.count_all().await, 1); - assert_eq!(presignature_manager.count_mine().await, 0); - assert_eq!(presignature_manager.count_potential().await, 1); + assert_eq!(presignature_manager.len_generated().await, 1); + assert_eq!(presignature_manager.len_mine().await, 0); + assert_eq!(presignature_manager.len_potential().await, 1); // Take presignature and check that it is removed from the storage presignature_manager.take(presignature_id).await.unwrap(); assert!(!presignature_manager.contains(&presignature_id).await); assert!(!presignature_manager.contains_mine(&presignature_id).await); - assert_eq!(presignature_manager.count_all().await, 0); - assert_eq!(presignature_manager.count_mine().await, 0); - assert_eq!(presignature_manager.count_potential().await, 0); + assert_eq!(presignature_manager.len_generated().await, 0); + assert_eq!(presignature_manager.len_mine().await, 0); + assert_eq!(presignature_manager.len_potential().await, 0); let mine_presignature = dummy_presignature(); let mine_presig_id: PresignatureId = mine_presignature.id; @@ -359,18 +359,18 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { presignature_manager.insert_mine(mine_presignature).await; assert!(presignature_manager.contains(&mine_presig_id).await); assert!(presignature_manager.contains_mine(&mine_presig_id).await); - assert_eq!(presignature_manager.count_all().await, 1); - assert_eq!(presignature_manager.count_mine().await, 1); - assert_eq!(presignature_manager.count_potential().await, 1); + assert_eq!(presignature_manager.len_generated().await, 1); + assert_eq!(presignature_manager.len_mine().await, 1); + assert_eq!(presignature_manager.len_potential().await, 1); // Take mine presignature and check that it is removed from the storage presignature_manager.take_mine().await.unwrap(); assert!(!presignature_manager.contains(&mine_presig_id).await); assert!(!presignature_manager.contains_mine(&mine_presig_id).await); - assert_eq!(presignature_manager.count_all().await, 0); - assert_eq!(presignature_manager.count_mine().await, 0); + assert_eq!(presignature_manager.len_generated().await, 0); + assert_eq!(presignature_manager.len_mine().await, 0); assert!(presignature_manager.is_empty().await); - assert_eq!(presignature_manager.count_potential().await, 0); + assert_eq!(presignature_manager.len_potential().await, 0); Ok(()) } From df919c8bcc626135411f471b95eb6bd06d62cf80 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Tue, 29 Oct 2024 21:21:42 +0200 Subject: [PATCH 44/64] develop --- chain-signatures/Cargo.lock | 1188 +++++++++++++++-------------------- 1 file changed, 504 insertions(+), 684 deletions(-) diff --git a/chain-signatures/Cargo.lock b/chain-signatures/Cargo.lock index 90bf3f840..47c8b8a3e 100644 --- a/chain-signatures/Cargo.lock +++ b/chain-signatures/Cargo.lock @@ -14,18 +14,18 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "gimli 0.28.1", + "gimli 0.31.1", ] [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aead" @@ -62,29 +62,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if 1.0.0", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -117,9 +94,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" dependencies = [ "anstyle", "anstyle-parse", @@ -132,43 +109,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" dependencies = [ "backtrace", ] @@ -190,9 +167,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "async-channel" @@ -219,13 +196,13 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ebdfa2ebdab6b1760375fa7d6f382b9f486eac35fc994625a00e89280bdbb7" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-lite 2.3.0", "slab", ] @@ -264,9 +241,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock 3.4.0", "cfg-if 1.0.0", @@ -274,11 +251,11 @@ dependencies = [ "futures-io", "futures-lite 2.3.0", "parking", - "polling 3.7.2", - "rustix 0.38.34", + "polling 3.7.3", + "rustix 0.38.38", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -325,33 +302,33 @@ dependencies = [ "cfg-if 1.0.0", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.34", + "rustix 0.38.38", "windows-sys 0.48.0", ] [[package]] name = "async-signal" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ - "async-io 2.3.3", + "async-io 2.3.4", "async-lock 3.4.0", "atomic-waker", "cfg-if 1.0.0", "futures-core", "futures-io", - "rustix 0.38.34", + "rustix 0.38.38", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -360,13 +337,13 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -377,13 +354,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -400,15 +377,15 @@ checksum = "7460f7dd8e100147b82a63afca1a20eb6c231ee36b90ba7272e14951cb58af59" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.5.4" +version = "1.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf6cfe2881cb1fcbba9ae946fb9a6480d3b7a714ca84c74925014a89ef3387a" +checksum = "2d6448cfb224dd6a9b9ac734f58622dd0d4751f3589f3b777345745f46b2eb14" dependencies = [ "aws-credential-types", "aws-runtime", @@ -423,10 +400,9 @@ dependencies = [ "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "hex", "http 0.2.12", - "hyper 0.14.30", "ring", "time", "tokio", @@ -437,9 +413,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16838e6c9e12125face1c1eff1343c75e3ff540de98ff7ebd61874a89bcfeb9" +checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -449,35 +425,36 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.3.1" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c5f920ffd1e0526ec9e70e50bf444db50b204395a0fa7016bbf9e31ea1698f" +checksum = "a10d5c055aa540164d9561a0e2e74ad30f0dcf7393c3a92f6733ddf9c5762468" dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-async", "aws-smithy-eventstream", "aws-smithy-http", + "aws-smithy-runtime", "aws-smithy-runtime-api", "aws-smithy-types", "aws-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "http 0.2.12", "http-body 0.4.6", + "once_cell", "percent-encoding 2.3.1", "pin-project-lite", "tracing", - "uuid 1.10.0", + "uuid 1.11.0", ] [[package]] name = "aws-sdk-s3" -version = "1.42.0" +version = "1.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558bbcec8db82a1a8af1610afcb3b10d00652d25ad366a0558eecdff2400a1d1" +checksum = "0656a79cf5e6ab0d4bb2465cd750a7a2fd7ea26c062183ed94225f5782e22365" dependencies = [ - "ahash 0.8.11", "aws-credential-types", "aws-runtime", "aws-sigv4", @@ -492,12 +469,12 @@ dependencies = [ "aws-smithy-xml", "aws-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "hex", "hmac", "http 0.2.12", "http-body 0.4.6", - "lru 0.12.3", + "lru", "once_cell", "percent-encoding 2.3.1", "regex-lite", @@ -508,9 +485,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.36.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6acca681c53374bf1d9af0e317a41d12a44902ca0f2d1e10e5cb5bb98ed74f35" +checksum = "a8776850becacbd3a82a4737a9375ddb5c6832a51379f24443a98e61513f852c" dependencies = [ "aws-credential-types", "aws-runtime", @@ -530,9 +507,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.37.0" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79c6bdfe612503a526059c05c9ccccbf6bd9530b003673cb863e547fd7c0c9a" +checksum = "0007b5b8004547133319b6c4e87193eee2a0bcb3e4c18c75d09febe9dab7b383" dependencies = [ "aws-credential-types", "aws-runtime", @@ -552,9 +529,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.36.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e6ecdb2bd756f3b2383e6f0588dc10a4e65f5d551e70a56e0bfe0c884673ce" +checksum = "9fffaa356e7f1c725908b75136d53207fa714e348f365671df14e95a60530ad3" dependencies = [ "aws-credential-types", "aws-runtime", @@ -575,9 +552,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.3" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5df1b0fa6be58efe9d4ccc257df0a53b89cd8909e86591a13ca54817c87517be" +checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", @@ -615,9 +592,9 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.60.11" +version = "0.60.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c4134cf3adaeacff34d588dbe814200357b0c466d730cf1c0d8054384a2de4" +checksum = "ba1a71073fca26775c8b5189175ea8863afb1c9ea2cceb02a5de5ad9dfbaa795" dependencies = [ "aws-smithy-http", "aws-smithy-types", @@ -636,9 +613,9 @@ dependencies = [ [[package]] name = "aws-smithy-eventstream" -version = "0.60.4" +version = "0.60.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6363078f927f612b970edf9d1903ef5cef9a64d1e8423525ebb1f0a1633c858" +checksum = "cef7d0a272725f87e51ba2bf89f8c21e4df61b9e49ae1ac367a6d69916ef7c90" dependencies = [ "aws-smithy-types", "bytes", @@ -647,9 +624,9 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.60.9" +version = "0.60.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9cd0ae3d97daa0a2bf377a4d8e8e1362cae590c4a1aad0d40058ebca18eb91e" +checksum = "5c8bc3e8fdc6b8d07d976e301c02fe553f72a39b7a9fea820e023268467d7ab6" dependencies = [ "aws-smithy-eventstream", "aws-smithy-runtime-api", @@ -687,22 +664,22 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.6.2" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce87155eba55e11768b8c1afa607f3e864ae82f03caf63258b37455b0ad02537" +checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" dependencies = [ "aws-smithy-async", "aws-smithy-http", "aws-smithy-runtime-api", "aws-smithy-types", "bytes", - "fastrand 2.1.0", + "fastrand 2.1.1", "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "http-body 1.0.1", "httparse", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", "once_cell", "pin-project-lite", @@ -714,9 +691,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30819352ed0a04ecf6a2f3477e344d2d1ba33d43e0f09ad9047c12e0d923616f" +checksum = "e086682a53d3aa241192aa110fa8dfce98f2f5ac2ead0de84d41582c7e8fdb96" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -731,9 +708,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.0" +version = "1.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe321a6b21f5d8eabd0ade9c55d3d0335f3c3157fc2b3e87f05f34b539e4df5" +checksum = "07c9cdc179e6afbf5d391ab08c85eac817b51c87e1892a5edb5f7bbdc64314b4" dependencies = [ "base64-simd", "bytes", @@ -757,9 +734,9 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.8" +version = "0.60.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d123fbc2a4adc3c301652ba8e149bf4bc1d1725affb9784eb20c953ace06bf55" +checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" dependencies = [ "xmlparser", ] @@ -791,7 +768,7 @@ dependencies = [ "futures-util", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "itoa", "matchit", "memchr", @@ -850,17 +827,17 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if 1.0.0", "libc", "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -976,6 +953,18 @@ dependencies = [ "piper", ] +[[package]] +name = "blst" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + [[package]] name = "borsh" version = "1.5.1" @@ -996,7 +985,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", "syn_derive", ] @@ -1038,9 +1027,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "bytes-utils" @@ -1104,9 +1093,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -1160,12 +1149,13 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.7" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -1249,9 +1239,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.11" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -1259,9 +1249,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.11" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -1271,14 +1261,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.11" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -1289,9 +1279,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" @@ -1362,15 +1352,15 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -1495,7 +1485,6 @@ dependencies = [ "curve25519-dalek-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "digest", "fiat-crypto", - "rand_core", "rustc_version", "subtle", "zeroize", @@ -1522,7 +1511,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -1532,7 +1521,7 @@ source = "git+https://github.com/dalek-cryptography/curve25519-dalek?rev=5b7082b dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -1580,7 +1569,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -1602,7 +1591,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -1682,7 +1671,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -1726,7 +1715,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -1770,9 +1759,9 @@ checksum = "f0bc8fbe9441c17c9f46f75dfe27fa1ddb6c68a461ccaed0481419219d4f10d3" [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" @@ -1894,9 +1883,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if 1.0.0", ] @@ -1918,7 +1907,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -2002,9 +1991,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "ff" @@ -2034,14 +2023,14 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -2055,9 +2044,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", "miniz_oxide", @@ -2078,6 +2067,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -2120,9 +2115,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -2135,9 +2130,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -2145,15 +2140,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -2162,9 +2157,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -2187,7 +2182,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-core", "futures-io", "parking", @@ -2196,32 +2191,32 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -2280,9 +2275,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "goblin" @@ -2304,7 +2305,7 @@ dependencies = [ "base64 0.22.1", "chrono", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "itertools 0.12.1", "mime", "percent-encoding 2.3.1", @@ -2326,7 +2327,7 @@ dependencies = [ "anyhow", "google-apis-common", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", "itertools 0.10.5", "mime", @@ -2346,7 +2347,7 @@ dependencies = [ "anyhow", "google-apis-common", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.25.0", "itertools 0.13.0", "mime", @@ -2391,7 +2392,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2410,7 +2411,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.2.6", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2422,18 +2423,16 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" dependencies = [ - "ahash 0.8.11", "allocator-api2", + "equivalent", + "foldhash", ] [[package]] @@ -2583,9 +2582,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2595,9 +2594,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -2619,9 +2618,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -2645,7 +2644,7 @@ checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "log", "rustls 0.21.12", "rustls-native-certs 0.6.3", @@ -2661,10 +2660,10 @@ checksum = "399c78f9338483cb7e630c8474b07268983c6bd5acee012e4211f9f7bb21b070" dependencies = [ "futures-util", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "log", "rustls 0.22.4", - "rustls-native-certs 0.7.1", + "rustls-native-certs 0.7.3", "rustls-pki-types", "tokio", "tokio-rustls 0.25.0", @@ -2672,15 +2671,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", "http 1.1.0", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -2695,7 +2694,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.30", + "hyper 0.14.31", "native-tls", "tokio", "tokio-native-tls", @@ -2709,7 +2708,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "native-tls", "tokio", @@ -2719,29 +2718,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", "socket2 0.5.7", "tokio", - "tower", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2812,12 +2810,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] @@ -2852,9 +2850,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.9.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_executable" @@ -2921,9 +2919,9 @@ checksum = "72167d68f5fce3b8655487b8038691a3c9984ee769590f93f2a631f4ad64e4f5" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -2959,9 +2957,9 @@ dependencies = [ [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if 1.0.0", "ecdsa 0.16.9", @@ -2998,9 +2996,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libloading" @@ -3020,6 +3018,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", + "redox_syscall", ] [[package]] @@ -3064,20 +3063,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.7.8" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.12.3", -] - -[[package]] -name = "lru" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" -dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -3156,18 +3146,18 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", @@ -3185,7 +3175,7 @@ dependencies = [ "digest", "ecdsa 0.16.9", "k256", - "near-crypto 0.26.0", + "near-crypto", "near-gas 0.2.5", "near-sdk", "near-workspaces", @@ -3231,7 +3221,7 @@ dependencies = [ "highway", "hkdf", "http 1.1.0", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.24.2", "itertools 0.12.1", "k256", @@ -3239,11 +3229,11 @@ dependencies = [ "mpc-contract", "mpc-keys", "near-account-id", - "near-crypto 0.26.0", + "near-crypto", "near-fetch", "near-lake-framework", "near-lake-primitives", - "near-primitives 0.26.0", + "near-primitives", "near-sdk", "once_cell", "prometheus", @@ -3354,11 +3344,11 @@ dependencies = [ "bytesize", "chrono", "derive_more", - "near-config-utils 0.26.0", - "near-crypto 0.26.0", - "near-parameters 0.26.0", - "near-primitives 0.26.0", - "near-time 0.26.0", + "near-config-utils", + "near-crypto", + "near-parameters", + "near-primitives", + "near-time", "num-rational", "once_cell", "serde", @@ -3369,18 +3359,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "near-config-utils" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b3db4ac2d4340caef06b6363c3fd16c0be1f70267908dfa53e2e6241649b0c" -dependencies = [ - "anyhow", - "json_comments", - "thiserror", - "tracing", -] - [[package]] name = "near-config-utils" version = "0.26.0" @@ -3393,31 +3371,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "near-crypto" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9807fb257f7dda41383bb33e14cfd4a8840ffa7932cb972db9eabff19ce3bf4" -dependencies = [ - "blake2", - "borsh", - "bs58 0.4.0", - "curve25519-dalek 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more", - "ed25519-dalek", - "hex", - "near-account-id", - "near-config-utils 0.23.0", - "near-stdx 0.23.0", - "once_cell", - "primitive-types", - "secp256k1", - "serde", - "serde_json", - "subtle", - "thiserror", -] - [[package]] name = "near-crypto" version = "0.26.0" @@ -3432,8 +3385,8 @@ dependencies = [ "ed25519-dalek", "hex", "near-account-id", - "near-config-utils 0.26.0", - "near-stdx 0.26.0", + "near-config-utils", + "near-stdx", "once_cell", "primitive-types", "rand", @@ -3452,12 +3405,12 @@ checksum = "af19136e92e226674e696ebb935866b91d18a4b1488ed1ac183d18ff32273361" dependencies = [ "base64 0.22.1", "near-account-id", - "near-crypto 0.26.0", + "near-crypto", "near-gas 0.3.0", "near-jsonrpc-client", "near-jsonrpc-primitives", - "near-primitives 0.26.0", - "near-token 0.3.0", + "near-primitives", + "near-token", "serde", "serde_json", "thiserror", @@ -3465,22 +3418,13 @@ dependencies = [ "tokio-retry", ] -[[package]] -name = "near-fmt" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00ce363e4078b870775e2a5a5189feae22f0870ca673f6409b1974922dada0c4" -dependencies = [ - "near-primitives-core 0.23.0", -] - [[package]] name = "near-fmt" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a36518bfcf2177096d4298d9158ba698ffd6944cb035ecc0938b098337b933c" dependencies = [ - "near-primitives-core 0.26.0", + "near-primitives-core", ] [[package]] @@ -3511,7 +3455,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f73dc123eaef5571c4704eb7da39e9ec398bdcb501236469f3ca06d60787bac" dependencies = [ - "near-primitives 0.26.0", + "near-primitives", "serde", "serde_json", ] @@ -3526,10 +3470,10 @@ dependencies = [ "lazy_static", "log", "near-chain-configs", - "near-crypto 0.26.0", + "near-crypto", "near-jsonrpc-primitives", - "near-primitives 0.26.0", - "reqwest 0.12.8", + "near-primitives", + "reqwest 0.12.9", "serde", "serde_json", "thiserror", @@ -3543,9 +3487,9 @@ checksum = "2b24bfd0fedef42e07daa79e463a7908e9abee4f6de3532e0e1dde45f6951657" dependencies = [ "arbitrary", "near-chain-configs", - "near-crypto 0.26.0", - "near-primitives 0.26.0", - "near-rpc-error-macro 0.26.0", + "near-crypto", + "near-primitives", + "near-rpc-error-macro", "serde", "serde_json", "thiserror", @@ -3558,7 +3502,7 @@ version = "0.8.0-beta.3" source = "git+https://github.com/near/near-lake-framework-rs?branch=node/2.3.0#d452f5be481cf6ae6627333aa97a506434c5bc9a" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -3590,34 +3534,16 @@ version = "0.8.0-beta.3" source = "git+https://github.com/near/near-lake-framework-rs?branch=node/2.3.0#d452f5be481cf6ae6627333aa97a506434c5bc9a" dependencies = [ "anyhow", - "near-crypto 0.26.0", + "near-crypto", "near-indexer-primitives", - "near-primitives 0.26.0", - "near-primitives-core 0.26.0", + "near-primitives", + "near-primitives-core", "paste", "serde", "serde_json", "thiserror", ] -[[package]] -name = "near-parameters" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fddf39f5f729976a791d86e0e30a71ec4d8e8dcf58117c8694e7b22fb3f50ee6" -dependencies = [ - "borsh", - "enum-map", - "near-account-id", - "near-primitives-core 0.23.0", - "num-rational", - "serde", - "serde_repr", - "serde_yaml", - "strum 0.24.1", - "thiserror", -] - [[package]] name = "near-parameters" version = "0.26.0" @@ -3627,7 +3553,7 @@ dependencies = [ "borsh", "enum-map", "near-account-id", - "near-primitives-core 0.26.0", + "near-primitives-core", "num-rational", "serde", "serde_repr", @@ -3636,48 +3562,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "near-primitives" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d58c175262923db9885ed0347e96ec3bcbec57825e3b6d7de03da220f5e14ef5" -dependencies = [ - "arbitrary", - "base64 0.21.7", - "borsh", - "bytes", - "bytesize", - "cfg-if 1.0.0", - "chrono", - "derive_more", - "easy-ext", - "enum-map", - "hex", - "itertools 0.10.5", - "near-crypto 0.23.0", - "near-fmt 0.23.0", - "near-parameters 0.23.0", - "near-primitives-core 0.23.0", - "near-rpc-error-macro 0.23.0", - "near-stdx 0.23.0", - "near-time 0.23.0", - "num-rational", - "once_cell", - "primitive-types", - "rand", - "rand_chacha", - "reed-solomon-erasure", - "serde", - "serde_json", - "serde_with", - "sha3", - "smart-default", - "strum 0.24.1", - "thiserror", - "tracing", - "zstd 0.13.2", -] - [[package]] name = "near-primitives" version = "0.26.0" @@ -3696,14 +3580,14 @@ dependencies = [ "enum-map", "hex", "itertools 0.10.5", - "near-crypto 0.26.0", - "near-fmt 0.26.0", - "near-parameters 0.26.0", - "near-primitives-core 0.26.0", - "near-rpc-error-macro 0.26.0", - "near-stdx 0.26.0", + "near-crypto", + "near-fmt", + "near-parameters", + "near-primitives-core", + "near-rpc-error-macro", + "near-stdx", "near-structs-checker-lib", - "near-time 0.26.0", + "near-time", "num-rational", "once_cell", "ordered-float", @@ -3721,26 +3605,6 @@ dependencies = [ "zstd 0.13.2", ] -[[package]] -name = "near-primitives-core" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45de00d413f5bb890a3912f32fcd0974b2b0a975cc7874012e2c4c4fa7f28917" -dependencies = [ - "arbitrary", - "base64 0.21.7", - "borsh", - "bs58 0.4.0", - "derive_more", - "enum-map", - "near-account-id", - "num-rational", - "serde", - "serde_repr", - "sha2", - "thiserror", -] - [[package]] name = "near-primitives-core" version = "0.26.0" @@ -3762,17 +3626,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "near-rpc-error-core" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf41b149dcc1f5a35d6a96fbcd8c28c92625c05b52025a72ee7378c72bcd68ce" -dependencies = [ - "quote", - "serde", - "syn 2.0.72", -] - [[package]] name = "near-rpc-error-core" version = "0.26.0" @@ -3781,18 +3634,7 @@ checksum = "df598b0785a3e36d7e4fb73afcdf20536988b13d07cead71dfa777db4783e552" dependencies = [ "quote", "serde", - "syn 2.0.72", -] - -[[package]] -name = "near-rpc-error-macro" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73c7f0f12f426792dd2c9d83df43d73c3b15d80f6e99e8d0e16ff3e024d0f9ba" -dependencies = [ - "near-rpc-error-core 0.23.0", - "serde", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -3801,9 +3643,9 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "647ef261df99ad877c08c97af2f10368c8b8cde0968250d3482a5a249e9f3926" dependencies = [ - "near-rpc-error-core 0.26.0", + "near-rpc-error-core", "serde", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -3821,22 +3663,22 @@ dependencies = [ [[package]] name = "near-sdk" -version = "5.2.1" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951ac0ba9c90e4ed6e927914d2ecee3d8ae2d74e794656b5ca42a992bd370863" +checksum = "4e296b02c85539c16659e171242d6c6bbea87eec7c9ef860d8dfd3fb3168a18a" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "borsh", "bs58 0.5.1", "near-account-id", - "near-crypto 0.23.0", - "near-gas 0.2.5", - "near-parameters 0.23.0", - "near-primitives 0.23.0", - "near-primitives-core 0.23.0", + "near-crypto", + "near-gas 0.3.0", + "near-parameters", + "near-primitives", + "near-primitives-core", "near-sdk-macros", "near-sys", - "near-token 0.2.0", + "near-token", "near-vm-runner", "once_cell", "serde", @@ -3846,9 +3688,9 @@ dependencies = [ [[package]] name = "near-sdk-macros" -version = "5.2.1" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2d758ff2701e7a53292a9dc2eeede6ed648574456c14f2464bf0a3ba047be3" +checksum = "0adc79466aa556f56a995c0db34a933b32597ab92bbb0e526597118899c8bcaf" dependencies = [ "Inflector", "darling 0.20.10", @@ -3858,15 +3700,9 @@ dependencies = [ "serde_json", "strum 0.26.3", "strum_macros 0.26.4", - "syn 2.0.72", + "syn 2.0.85", ] -[[package]] -name = "near-stdx" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e1897481272eb144328abd51ca9f59b5b558e7a6dc6e2177c8c9bb18fbd818" - [[package]] name = "near-stdx" version = "0.26.0" @@ -3901,18 +3737,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf4ca5c805cb78700e10e43484902d8da05f25788db277999d209568aaf4c8e" -[[package]] -name = "near-time" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56db32f26b089441c1a7c5451f0d68637afa9d66f6d8f6a6f2d6c2f7953520a" -dependencies = [ - "once_cell", - "serde", - "time", - "tokio", -] - [[package]] name = "near-time" version = "0.26.0" @@ -3925,43 +3749,36 @@ dependencies = [ "tokio", ] -[[package]] -name = "near-token" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b68f3f8a2409f72b43efdbeff8e820b81e70824c49fee8572979d789d1683fb" -dependencies = [ - "borsh", - "serde", -] - [[package]] name = "near-token" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3e60aa26a74dc514b1b6408fdd06cefe2eb0ff029020956c1c6517594048fd" dependencies = [ + "borsh", "serde", ] [[package]] name = "near-vm-runner" -version = "0.23.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b382e9fda99cdc6f1684d95e9f10ef0ed556c14ff972099269e96f8fde84064" +checksum = "b5a2fecdbec69a1748bd80aa0d73e4de0064d2d8097f429677d3e37a6bde3b2d" dependencies = [ + "blst", "borsh", + "bytesize", "ed25519-dalek", "enum-map", - "lru 0.7.8", - "near-crypto 0.23.0", - "near-parameters 0.23.0", - "near-primitives-core 0.23.0", - "near-stdx 0.23.0", + "lru", + "near-crypto", + "near-parameters", + "near-primitives-core", + "near-stdx", "num-rational", "once_cell", "ripemd", - "rustix 0.38.34", + "rustix 0.38.38", "serde", "serde_repr", "sha2", @@ -3988,15 +3805,15 @@ dependencies = [ "libc", "near-abi-client", "near-account-id", - "near-crypto 0.26.0", + "near-crypto", "near-gas 0.3.0", "near-jsonrpc-client", "near-jsonrpc-primitives", - "near-primitives 0.26.0", + "near-primitives", "near-sandbox-utils", - "near-token 0.3.0", + "near-token", "rand", - "reqwest 0.12.8", + "reqwest 0.12.9", "serde", "serde_json", "sha2", @@ -4187,18 +4004,18 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -4208,9 +4025,9 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if 1.0.0", @@ -4229,7 +4046,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -4240,9 +4057,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -4252,9 +4069,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "4.2.2" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a91171844676f8c7990ce64959210cd2eaef32c2612c50f9fae9f8aaa6065a6" +checksum = "83e7ccb95e240b7c9506a3d544f10d935e142cc90b0a1d56954fb44d89ad6b97" dependencies = [ "borsh", "num-traits", @@ -4297,9 +4114,9 @@ dependencies = [ [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -4319,7 +4136,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -4387,29 +4204,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -4419,12 +4236,12 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand 2.1.1", "futures-io", ] @@ -4450,9 +4267,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plain" @@ -4478,17 +4295,17 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.2" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if 1.0.0", "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.34", + "rustix 0.38.38", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4522,12 +4339,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.19" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2288c0e17cc8d342c712bb43a257a80ebffce59cdb33d5000d8348f3ec02528b" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", - "zerocopy-derive", ] [[package]] @@ -4567,9 +4383,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ "toml_edit", ] @@ -4599,9 +4415,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -4629,16 +4445,17 @@ checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 1.1.0", - "rustls 0.23.12", + "rustc-hash", + "rustls 0.23.16", + "socket2 0.5.7", "thiserror", "tokio", "tracing", @@ -4653,8 +4470,8 @@ dependencies = [ "bytes", "rand", "ring", - "rustc-hash 2.0.0", - "rustls 0.23.12", + "rustc-hash", + "rustls 0.23.16", "slab", "thiserror", "tinyvec", @@ -4663,21 +4480,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" dependencies = [ + "cfg_aliases", "libc", "once_cell", "socket2 0.5.7", - "windows-sys 0.52.0", + "tracing", + "windows-sys 0.59.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -4742,9 +4561,9 @@ dependencies = [ [[package]] name = "redis" -version = "0.27.4" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6baebe319ef5e4b470f248335620098d1c2e9261e995be05f56f719ca4bdb2" +checksum = "81cccf17a692ce51b86564334614d72dcae1def0fd5ecebc9f02956da74352b5" dependencies = [ "arc-swap", "async-trait", @@ -4765,52 +4584,34 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", "thiserror", ] -[[package]] -name = "reed-solomon-erasure" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a415a013dd7c5d4221382329a5a3482566da675737494935cbbbcdec04662f9d" -dependencies = [ - "smallvec", -] - [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -4824,13 +4625,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4847,9 +4648,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -4865,7 +4666,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-tls 0.5.0", "ipnet", "js-sys", @@ -4893,9 +4694,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.8" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" dependencies = [ "base64 0.22.1", "bytes", @@ -4906,8 +4707,8 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", - "hyper-rustls 0.27.2", + "hyper 1.5.0", + "hyper-rustls 0.27.3", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -4919,8 +4720,8 @@ dependencies = [ "percent-encoding 2.3.1", "pin-project-lite", "quinn", - "rustls 0.23.12", - "rustls-pemfile 2.1.2", + "rustls 0.23.16", + "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", "serde_json", @@ -5012,12 +4813,6 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.0.0" @@ -5032,9 +4827,9 @@ checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -5055,9 +4850,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" dependencies = [ "bitflags 2.6.0", "errno", @@ -5087,22 +4882,22 @@ dependencies = [ "log", "ring", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] [[package]] name = "rustls" -version = "0.23.12" +version = "0.23.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" dependencies = [ "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.8", "subtle", "zeroize", ] @@ -5121,12 +4916,12 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a88d6d420651b496bdd98684116959239430022a115c1240e6c3993be0b15fba" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -5143,19 +4938,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -5169,9 +4963,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -5180,9 +4974,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -5192,11 +4986,11 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5220,7 +5014,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -5252,7 +5046,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -5334,9 +5128,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -5353,22 +5147,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.204" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -5379,14 +5173,14 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] name = "serde_json" -version = "1.0.121" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -5412,7 +5206,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -5429,15 +5223,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.6", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -5447,14 +5241,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -5463,7 +5257,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "itoa", "ryu", "serde", @@ -5527,6 +5321,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -5727,7 +5527,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -5791,9 +5591,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" dependencies = [ "proc-macro2", "quote", @@ -5809,7 +5609,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -5891,9 +5691,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -5902,34 +5702,35 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if 1.0.0", - "fastrand 2.1.0", - "rustix 0.38.34", - "windows-sys 0.52.0", + "fastrand 2.1.1", + "once_cell", + "rustix 0.38.38", + "windows-sys 0.59.0", ] [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -5942,6 +5743,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + [[package]] name = "time" version = "0.3.36" @@ -5992,9 +5802,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", @@ -6016,7 +5826,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -6067,16 +5877,16 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -6085,9 +5895,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -6104,11 +5914,11 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.6.0", "toml_datetime", "winnow", ] @@ -6131,15 +5941,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -6161,7 +5971,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -6257,21 +6067,21 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] @@ -6300,15 +6110,15 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72139d247e5f97a3eff96229a7ae85ead5328a39efe76f8bf5a06313d505b6ea" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" dependencies = [ "base64 0.22.1", "flate2", "log", "once_cell", - "rustls 0.23.12", + "rustls 0.23.16", "rustls-pki-types", "url 2.5.2", "webpki-roots", @@ -6367,9 +6177,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" [[package]] name = "valuable" @@ -6418,34 +6228,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if 1.0.0", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -6455,9 +6266,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6465,22 +6276,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasmparser" @@ -6490,9 +6301,9 @@ checksum = "718ed7c55c2add6548cca3ddd6383d738cd73b892df400e96b9aa876f0141d7a" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -6500,9 +6311,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" dependencies = [ "rustls-pki-types", ] @@ -6580,7 +6391,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -6591,7 +6402,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -6651,6 +6462,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -6774,9 +6594,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -6817,14 +6637,14 @@ checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", "linux-raw-sys 0.4.14", - "rustix 0.38.34", + "rustix 0.38.38", ] [[package]] name = "xml-rs" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" [[package]] name = "xmlparser" @@ -6843,7 +6663,7 @@ dependencies = [ "base64 0.21.7", "futures", "http 0.2.12", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-rustls 0.25.0", "itertools 0.12.1", "log", @@ -6877,7 +6697,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -6897,7 +6717,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.85", ] [[package]] @@ -6960,7 +6780,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe 7.2.0", + "zstd-safe 7.2.1", ] [[package]] @@ -6975,18 +6795,18 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "7.2.0" +version = "7.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.12+zstd.1.5.6" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", From 566a134a99659b22de90f787407abec070d18d91 Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Wed, 30 Oct 2024 18:09:07 +0900 Subject: [PATCH 45/64] Fix locks being acquired incorrectly (#914) --- .../node/src/protocol/presignature.rs | 8 ++--- chain-signatures/node/src/protocol/triple.rs | 34 ++++++++----------- .../node/src/storage/presignature_storage.rs | 8 ++--- .../node/src/storage/triple_storage.rs | 8 ++--- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 233c54983..16aca0a25 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -218,7 +218,7 @@ impl PresignatureManager { /// Returns true if the presignature with the given id is already generated pub async fn contains(&self, id: &PresignatureId) -> bool { self.presignature_storage - .write() + .read() .await .contains(id) .await @@ -231,7 +231,7 @@ impl PresignatureManager { /// Returns true if the mine presignature with the given id is already generated pub async fn contains_mine(&self, id: &PresignatureId) -> bool { self.presignature_storage - .write() + .read() .await .contains_mine(id) .await @@ -291,7 +291,7 @@ impl PresignatureManager { /// Returns the number of unspent presignatures available in the manager. pub async fn len_generated(&self) -> usize { self.presignature_storage - .write() + .read() .await .len_generated() .await @@ -304,7 +304,7 @@ impl PresignatureManager { /// Returns the number of unspent presignatures assigned to this node. pub async fn len_mine(&self) -> usize { self.presignature_storage - .write() + .read() .await .len_mine() .await diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index d7399bce2..327d543ff 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -162,7 +162,7 @@ impl TripleManager { pub async fn contains(&self, id: &TripleId) -> bool { self.triple_storage - .write() + .read() .await .contains(id) .await @@ -172,7 +172,7 @@ impl TripleManager { pub async fn contains_mine(&self, id: &TripleId) -> bool { self.triple_storage - .write() + .read() .await .contains_mine(id) .await @@ -189,7 +189,8 @@ impl TripleManager { id0: TripleId, id1: TripleId, ) -> Result<(Triple, Triple), GenerationError> { - let triple_0 = match self.triple_storage.write().await.take(&id0).await { + let mut triples = self.triple_storage.write().await; + let triple_0 = match triples.take(&id0).await { Ok(Some(triple)) => triple, Ok(None) => { if self.generators.contains_key(&id0) { @@ -209,10 +210,10 @@ impl TripleManager { } }; - let triple_1 = match self.triple_storage.write().await.take(&id1).await { + let triple_1 = match triples.take(&id1).await { Ok(Some(triple)) => triple, Ok(None) => { - if let Err(e) = self.triple_storage.write().await.insert(triple_0).await { + if let Err(e) = triples.insert(triple_0).await { tracing::warn!(id0, ?e, "failed to insert triple back"); } if self.generators.contains_key(&id1) { @@ -228,7 +229,7 @@ impl TripleManager { } Err(e) => { tracing::warn!(id1, ?e, "failed to take triple"); - if let Err(e) = self.triple_storage.write().await.insert(triple_0).await { + if let Err(e) = triples.insert(triple_0).await { tracing::warn!(id0, ?e, "failed to insert triple back"); } return Err(GenerationError::TripleIsMissing(id1)); @@ -247,11 +248,12 @@ impl TripleManager { /// It is very important to NOT reuse the same triple twice for two different /// protocols. pub async fn take_two_mine(&mut self) -> Option<(Triple, Triple)> { - if self.len_mine().await < 2 { + let mut triples = self.triple_storage.write().await; + if triples.len_mine().await.unwrap_or(0) < 2 { tracing::warn!("not enough mine triples"); return None; } - let triple_0 = match self.triple_storage.write().await.take_mine().await { + let triple_0 = match triples.take_mine().await { Ok(Some(triple)) => triple, Ok(None) => { tracing::warn!("no mine triple left"); @@ -263,13 +265,10 @@ impl TripleManager { } }; - let triple_1 = match self.triple_storage.write().await.take_mine().await { + let triple_1 = match triples.take_mine().await { Ok(Some(triple)) => triple, Ok(None) => { - if let Err(e) = self - .triple_storage - .write() - .await + if let Err(e) = triples .insert_mine(triple_0) .await { @@ -280,10 +279,7 @@ impl TripleManager { } Err(e) => { tracing::warn!(?e, "failed to take mine triple"); - if let Err(e) = self - .triple_storage - .write() - .await + if let Err(e) = triples .insert_mine(triple_0) .await { @@ -304,7 +300,7 @@ impl TripleManager { /// Returns the number of unspent triples available in the manager. pub async fn len_generated(&self) -> usize { self.triple_storage - .write() + .read() .await .len_generated() .await @@ -314,7 +310,7 @@ impl TripleManager { /// Returns the number of unspent triples assigned to this node. pub async fn len_mine(&self) -> usize { self.triple_storage - .write() + .read() .await .len_mine() .await diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index f8b246845..7720976ba 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -48,13 +48,13 @@ impl PresignatureRedisStorage { Ok(()) } - pub async fn contains(&mut self, id: &PresignatureId) -> PresigResult { + pub async fn contains(&self, id: &PresignatureId) -> PresigResult { let mut connection = self.redis_pool.get().await?; let result: bool = connection.hexists(self.presig_key(), id).await?; Ok(result) } - pub async fn contains_mine(&mut self, id: &PresignatureId) -> PresigResult { + pub async fn contains_mine(&self, id: &PresignatureId) -> PresigResult { let mut connection = self.redis_pool.get().await?; let result: bool = connection.sismember(self.mine_key(), id).await?; Ok(result) @@ -87,13 +87,13 @@ impl PresignatureRedisStorage { } } - pub async fn len_generated(&mut self) -> PresigResult { + pub async fn len_generated(&self) -> PresigResult { let mut connection = self.redis_pool.get().await?; let result: usize = connection.hlen(self.presig_key()).await?; Ok(result) } - pub async fn len_mine(&mut self) -> PresigResult { + pub async fn len_mine(&self) -> PresigResult { let mut connection = self.redis_pool.get().await?; let result: usize = connection.scard(self.mine_key()).await?; Ok(result) diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index 9d128b219..89c021514 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -41,13 +41,13 @@ impl TripleRedisStorage { Ok(()) } - pub async fn contains(&mut self, id: &TripleId) -> TripleResult { + pub async fn contains(&self, id: &TripleId) -> TripleResult { let mut conn = self.redis_pool.get().await?; let result: bool = conn.hexists(self.triple_key(), id).await?; Ok(result) } - pub async fn contains_mine(&mut self, id: &TripleId) -> TripleResult { + pub async fn contains_mine(&self, id: &TripleId) -> TripleResult { let mut conn = self.redis_pool.get().await?; let result: bool = conn.sismember(self.mine_key(), id).await?; Ok(result) @@ -79,13 +79,13 @@ impl TripleRedisStorage { } } - pub async fn len_generated(&mut self) -> TripleResult { + pub async fn len_generated(&self) -> TripleResult { let mut conn = self.redis_pool.get().await?; let result: usize = conn.hlen(self.triple_key()).await?; Ok(result) } - pub async fn len_mine(&mut self) -> TripleResult { + pub async fn len_mine(&self) -> TripleResult { let mut conn = self.redis_pool.get().await?; let result: usize = conn.scard(self.mine_key()).await?; Ok(result) From b654fba9cd1b8c954d6222529262f0571517c001 Mon Sep 17 00:00:00 2001 From: Phuong Nguyen Date: Wed, 30 Oct 2024 19:46:16 +0900 Subject: [PATCH 46/64] chore: removed Arc and RwLock for triple/presignature storage (#915) * Removed Arc and RwLock for triple/presignature storage --- chain-signatures/node/src/cli.rs | 13 ++--- .../node/src/protocol/consensus.rs | 12 ++--- chain-signatures/node/src/protocol/mod.rs | 20 ++++---- .../node/src/protocol/presignature.rs | 49 ++++--------------- chain-signatures/node/src/protocol/triple.rs | 44 +++++------------ .../node/src/storage/presignature_storage.rs | 19 +++---- .../node/src/storage/triple_storage.rs | 18 +++---- integration-tests/chain-signatures/src/lib.rs | 2 +- .../chain-signatures/tests/cases/mod.rs | 23 +++------ 9 files changed, 66 insertions(+), 134 deletions(-) diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 85042f6aa..83131e2df 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -1,8 +1,6 @@ use crate::config::{Config, LocalConfig, NetworkConfig, OverrideConfig}; use crate::gcp::GcpService; use crate::protocol::{MpcSignProtocol, SignQueue}; -use crate::storage::presignature_storage::LockPresignatureRedisStorage; -use crate::storage::triple_storage::LockTripleRedisStorage; use crate::{http_client, indexer, mesh, storage, web}; use clap::Parser; use deadpool_redis::Runtime; @@ -213,14 +211,9 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let redis_cfg = deadpool_redis::Config::from_url(redis_url); let redis_pool = redis_cfg.create_pool(Some(Runtime::Tokio1)).unwrap(); - - let triple_storage: LockTripleRedisStorage = Arc::new(RwLock::new( - storage::triple_storage::init(redis_pool.clone(), &account_id), - )); - - let presignature_storage: LockPresignatureRedisStorage = Arc::new(RwLock::new( - storage::presignature_storage::init(redis_pool.clone(), &account_id), - )); + let triple_storage = storage::triple_storage::init(&redis_pool, &account_id); + let presignature_storage = + storage::presignature_storage::init(&redis_pool, &account_id); let sign_sk = sign_sk.unwrap_or_else(|| account_sk.clone()); let my_address = my_address diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index af070acbd..d50fd0317 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -12,9 +12,9 @@ use crate::protocol::presignature::PresignatureManager; use crate::protocol::signature::SignatureManager; use crate::protocol::state::{GeneratingState, ResharingState}; use crate::protocol::triple::TripleManager; -use crate::storage::presignature_storage::LockPresignatureRedisStorage; +use crate::storage::presignature_storage::PresignatureRedisStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::LockTripleRedisStorage; +use crate::storage::triple_storage::TripleRedisStorage; use crate::types::{KeygenProtocol, ReshareProtocol, SecretKeyShare}; use crate::util::AffinePointExt; use crate::{http_client, rpc_client}; @@ -40,8 +40,8 @@ pub trait ConsensusCtx { fn my_address(&self) -> &Url; fn sign_queue(&self) -> Arc>; fn secret_storage(&self) -> &SecretNodeStorageBox; - fn triple_storage(&self) -> LockTripleRedisStorage; - fn presignature_storage(&self) -> LockPresignatureRedisStorage; + fn triple_storage(&self) -> &TripleRedisStorage; + fn presignature_storage(&self) -> &PresignatureRedisStorage; fn cfg(&self) -> &Config; fn message_options(&self) -> http_client::Options; } @@ -361,14 +361,14 @@ impl ConsensusProtocol for WaitingForConsensusState { // Clear triples from storage before starting the new epoch. This is necessary if the node has accumulated // triples from previous epochs. If it was not able to clear the previous triples, we'll leave them as-is - if let Err(err) = ctx.triple_storage().write().await.clear().await { + if let Err(err) = ctx.triple_storage().clear().await { tracing::error!( ?err, "failed to clear triples from storage on new epoch start" ); } - if let Err(err) = ctx.presignature_storage().write().await.clear().await { + if let Err(err) = ctx.presignature_storage().clear().await { tracing::error!( ?err, "failed to clear presignatures from storage on new epoch start" diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 48bc89385..7109e7c4c 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -29,9 +29,9 @@ use crate::protocol::consensus::ConsensusProtocol; use crate::protocol::cryptography::CryptographicProtocol; use crate::protocol::message::{MessageHandler, MpcMessageQueue}; use crate::rpc_client; -use crate::storage::presignature_storage::LockPresignatureRedisStorage; +use crate::storage::presignature_storage::PresignatureRedisStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::LockTripleRedisStorage; +use crate::storage::triple_storage::TripleRedisStorage; use cait_sith::protocol::Participant; use near_account_id::AccountId; @@ -53,8 +53,8 @@ struct Ctx { http_client: reqwest::Client, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: LockTripleRedisStorage, - presignature_storage: LockPresignatureRedisStorage, + triple_storage: TripleRedisStorage, + presignature_storage: PresignatureRedisStorage, cfg: Config, mesh: Mesh, message_options: http_client::Options, @@ -97,12 +97,12 @@ impl ConsensusCtx for &mut MpcSignProtocol { &self.ctx.cfg } - fn triple_storage(&self) -> LockTripleRedisStorage { - self.ctx.triple_storage.clone() + fn triple_storage(&self) -> &TripleRedisStorage { + &self.ctx.triple_storage } - fn presignature_storage(&self) -> LockPresignatureRedisStorage { - self.ctx.presignature_storage.clone() + fn presignature_storage(&self) -> &PresignatureRedisStorage { + &self.ctx.presignature_storage } fn message_options(&self) -> http_client::Options { @@ -177,8 +177,8 @@ impl MpcSignProtocol { receiver: mpsc::Receiver, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: LockTripleRedisStorage, - presignature_storage: LockPresignatureRedisStorage, + triple_storage: TripleRedisStorage, + presignature_storage: PresignatureRedisStorage, cfg: Config, mesh_options: mesh::Options, message_options: http_client::Options, diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 16aca0a25..6aecae80b 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -1,7 +1,7 @@ use super::message::PresignatureMessage; use super::triple::{Triple, TripleId, TripleManager}; use crate::protocol::contract::primitives::Participants; -use crate::storage::presignature_storage::LockPresignatureRedisStorage; +use crate::storage::presignature_storage::PresignatureRedisStorage; use crate::types::{PresignatureProtocol, SecretKeyShare}; use crate::util::AffinePointExt; @@ -150,7 +150,7 @@ pub enum GenerationError { /// Abstracts how triples are generated by providing a way to request a new triple that will be /// complete some time in the future and a way to take an already generated triple. pub struct PresignatureManager { - presignature_storage: LockPresignatureRedisStorage, + presignature_storage: PresignatureRedisStorage, /// Ongoing presignature generation protocols. generators: HashMap, /// The set of presignatures that were introduced to the system by the current node. @@ -171,10 +171,10 @@ impl PresignatureManager { threshold: usize, epoch: u64, my_account_id: &AccountId, - presignature_storage: LockPresignatureRedisStorage, + storage: &PresignatureRedisStorage, ) -> Self { Self { - presignature_storage, + presignature_storage: storage.clone(), generators: HashMap::new(), introduced: HashSet::new(), gc: HashMap::new(), @@ -189,13 +189,7 @@ impl PresignatureManager { tracing::debug!(id = ?presignature.id, "inserting presignature"); // Remove from taken list if it was there self.gc.remove(&presignature.id); - if let Err(e) = self - .presignature_storage - .write() - .await - .insert(presignature) - .await - { + if let Err(e) = self.presignature_storage.insert(presignature).await { tracing::error!(?e, "failed to insert presignature"); } } @@ -204,13 +198,7 @@ impl PresignatureManager { tracing::debug!(id = ?presignature.id, "inserting mine presignature"); // Remove from taken list if it was there self.gc.remove(&presignature.id); - if let Err(e) = self - .presignature_storage - .write() - .await - .insert_mine(presignature) - .await - { + if let Err(e) = self.presignature_storage.insert_mine(presignature).await { tracing::error!(?e, "failed to insert mine presignature"); } } @@ -218,8 +206,6 @@ impl PresignatureManager { /// Returns true if the presignature with the given id is already generated pub async fn contains(&self, id: &PresignatureId) -> bool { self.presignature_storage - .read() - .await .contains(id) .await .map_err(|e| { @@ -231,8 +217,6 @@ impl PresignatureManager { /// Returns true if the mine presignature with the given id is already generated pub async fn contains_mine(&self, id: &PresignatureId) -> bool { self.presignature_storage - .read() - .await .contains_mine(id) .await .map_err(|e| { @@ -242,17 +226,10 @@ impl PresignatureManager { } pub async fn take(&mut self, id: PresignatureId) -> Result { - if let Some(presignature) = self - .presignature_storage - .write() - .await - .take(&id) - .await - .map_err(|e| { - tracing::error!(?e, "failed to look for presignature"); - GenerationError::PresignatureIsMissing(id) - })? - { + if let Some(presignature) = self.presignature_storage.take(&id).await.map_err(|e| { + tracing::error!(?e, "failed to look for presignature"); + GenerationError::PresignatureIsMissing(id) + })? { self.gc.insert(id, Instant::now()); tracing::debug!(id, "took presignature"); return Ok(presignature); @@ -273,8 +250,6 @@ impl PresignatureManager { pub async fn take_mine(&mut self) -> Option { if let Some(presignature) = self .presignature_storage - .write() - .await .take_mine() .await .map_err(|e| { @@ -291,8 +266,6 @@ impl PresignatureManager { /// Returns the number of unspent presignatures available in the manager. pub async fn len_generated(&self) -> usize { self.presignature_storage - .read() - .await .len_generated() .await .map_err(|e| { @@ -304,8 +277,6 @@ impl PresignatureManager { /// Returns the number of unspent presignatures assigned to this node. pub async fn len_mine(&self) -> usize { self.presignature_storage - .read() - .await .len_mine() .await .map_err(|e| { diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index 327d543ff..798b4d350 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -2,7 +2,7 @@ use super::contract::primitives::Participants; use super::cryptography::CryptographicError; use super::message::TripleMessage; use super::presignature::GenerationError; -use crate::storage::triple_storage::LockTripleRedisStorage; +use crate::storage::triple_storage::TripleRedisStorage; use crate::types::TripleProtocol; use crate::util::AffinePointExt; @@ -80,7 +80,7 @@ impl TripleGenerator { /// complete some time in the future and a way to take an already generated triple. pub struct TripleManager { /// Triple Storage - pub triple_storage: LockTripleRedisStorage, + pub triple_storage: TripleRedisStorage, /// The pool of triple protocols that have yet to be completed. pub generators: HashMap, @@ -128,7 +128,7 @@ impl TripleManager { threshold: usize, epoch: u64, my_account_id: &AccountId, - triple_storage: LockTripleRedisStorage, + storage: &TripleRedisStorage, ) -> Self { Self { generators: HashMap::new(), @@ -139,7 +139,7 @@ impl TripleManager { me, threshold, epoch, - triple_storage, + triple_storage: storage.clone(), my_account_id: my_account_id.clone(), } } @@ -147,7 +147,7 @@ impl TripleManager { pub async fn insert(&mut self, triple: Triple) { tracing::debug!(id = triple.id, "inserting triple"); self.gc.remove(&triple.id); - if let Err(e) = self.triple_storage.write().await.insert(triple).await { + if let Err(e) = self.triple_storage.insert(triple).await { tracing::warn!(?e, "failed to insert triple"); } } @@ -155,15 +155,13 @@ impl TripleManager { pub async fn insert_mine(&mut self, triple: Triple) { tracing::debug!(id = triple.id, "inserting mine triple"); self.gc.remove(&triple.id); - if let Err(e) = self.triple_storage.write().await.insert_mine(triple).await { + if let Err(e) = self.triple_storage.insert_mine(triple).await { tracing::warn!(?e, "failed to insert mine triple"); } } pub async fn contains(&self, id: &TripleId) -> bool { self.triple_storage - .read() - .await .contains(id) .await .map_err(|e| tracing::warn!(?e, "failed to check if triple exists")) @@ -172,8 +170,6 @@ impl TripleManager { pub async fn contains_mine(&self, id: &TripleId) -> bool { self.triple_storage - .read() - .await .contains_mine(id) .await .map_err(|e| tracing::warn!(?e, "failed to check if mine triple exists")) @@ -189,7 +185,7 @@ impl TripleManager { id0: TripleId, id1: TripleId, ) -> Result<(Triple, Triple), GenerationError> { - let mut triples = self.triple_storage.write().await; + let triples = &self.triple_storage; let triple_0 = match triples.take(&id0).await { Ok(Some(triple)) => triple, Ok(None) => { @@ -248,7 +244,7 @@ impl TripleManager { /// It is very important to NOT reuse the same triple twice for two different /// protocols. pub async fn take_two_mine(&mut self) -> Option<(Triple, Triple)> { - let mut triples = self.triple_storage.write().await; + let triples = &self.triple_storage; if triples.len_mine().await.unwrap_or(0) < 2 { tracing::warn!("not enough mine triples"); return None; @@ -268,10 +264,7 @@ impl TripleManager { let triple_1 = match triples.take_mine().await { Ok(Some(triple)) => triple, Ok(None) => { - if let Err(e) = triples - .insert_mine(triple_0) - .await - { + if let Err(e) = triples.insert_mine(triple_0).await { tracing::warn!(?e, "failed to insert mine triple back"); } tracing::warn!("no mine triple left"); @@ -279,10 +272,7 @@ impl TripleManager { } Err(e) => { tracing::warn!(?e, "failed to take mine triple"); - if let Err(e) = triples - .insert_mine(triple_0) - .await - { + if let Err(e) = triples.insert_mine(triple_0).await { tracing::warn!(?e, "failed to insert mine triple back"); } return None; @@ -299,22 +289,12 @@ impl TripleManager { /// Returns the number of unspent triples available in the manager. pub async fn len_generated(&self) -> usize { - self.triple_storage - .read() - .await - .len_generated() - .await - .unwrap_or(0) + self.triple_storage.len_generated().await.unwrap_or(0) } /// Returns the number of unspent triples assigned to this node. pub async fn len_mine(&self) -> usize { - self.triple_storage - .read() - .await - .len_mine() - .await - .unwrap_or(0) + self.triple_storage.len_mine().await.unwrap_or(0) } /// Returns if there's any unspent triple in the manager. diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index 7720976ba..0f750185a 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -1,33 +1,30 @@ -use std::sync::Arc; - use anyhow::Ok; use deadpool_redis::Pool; use near_sdk::AccountId; use redis::{AsyncCommands, FromRedisValue, RedisWrite, ToRedisArgs}; -use tokio::sync::RwLock; use crate::protocol::presignature::{Presignature, PresignatureId}; type PresigResult = std::result::Result; -pub type LockPresignatureRedisStorage = Arc>; // Can be used to "clear" redis storage in case of a breaking change const PRESIGNATURE_STORAGE_VERSION: &str = "v1"; -pub fn init(redis_pool: Pool, node_account_id: &AccountId) -> PresignatureRedisStorage { +pub fn init(pool: &Pool, node_account_id: &AccountId) -> PresignatureRedisStorage { PresignatureRedisStorage { - redis_pool, + redis_pool: pool.clone(), node_account_id: node_account_id.clone(), } } +#[derive(Clone)] pub struct PresignatureRedisStorage { redis_pool: Pool, node_account_id: AccountId, } impl PresignatureRedisStorage { - pub async fn insert(&mut self, presignature: Presignature) -> PresigResult<()> { + pub async fn insert(&self, presignature: Presignature) -> PresigResult<()> { let mut connection = self.redis_pool.get().await?; connection .hset::<&str, PresignatureId, Presignature, ()>( @@ -39,7 +36,7 @@ impl PresignatureRedisStorage { Ok(()) } - pub async fn insert_mine(&mut self, presignature: Presignature) -> PresigResult<()> { + pub async fn insert_mine(&self, presignature: Presignature) -> PresigResult<()> { let mut connection = self.redis_pool.get().await?; connection .sadd::<&str, PresignatureId, ()>(&self.mine_key(), presignature.id) @@ -60,7 +57,7 @@ impl PresignatureRedisStorage { Ok(result) } - pub async fn take(&mut self, id: &PresignatureId) -> PresigResult> { + pub async fn take(&self, id: &PresignatureId) -> PresigResult> { let mut connection = self.redis_pool.get().await?; if self.contains_mine(id).await? { tracing::error!("Can not take mine presignature as foreign: {:?}", id); @@ -78,7 +75,7 @@ impl PresignatureRedisStorage { } } - pub async fn take_mine(&mut self) -> PresigResult> { + pub async fn take_mine(&self) -> PresigResult> { let mut connection = self.redis_pool.get().await?; let id: Option = connection.spop(self.mine_key()).await?; match id { @@ -99,7 +96,7 @@ impl PresignatureRedisStorage { Ok(result) } - pub async fn clear(&mut self) -> PresigResult<()> { + pub async fn clear(&self) -> PresigResult<()> { let mut connection = self.redis_pool.get().await?; connection.del::<&str, ()>(&self.presig_key()).await?; connection.del::<&str, ()>(&self.mine_key()).await?; diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index 89c021514..4a76c3365 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -1,39 +1,37 @@ use crate::protocol::triple::{Triple, TripleId}; -use std::sync::Arc; use deadpool_redis::Pool; use redis::{AsyncCommands, FromRedisValue, RedisWrite, ToRedisArgs}; -use tokio::sync::RwLock; use near_account_id::AccountId; -pub type LockTripleRedisStorage = Arc>; type TripleResult = std::result::Result; // Can be used to "clear" redis storage in case of a breaking change const TRIPLE_STORAGE_VERSION: &str = "v1"; -pub fn init(redis_pool: Pool, account_id: &AccountId) -> TripleRedisStorage { +pub fn init(pool: &Pool, account_id: &AccountId) -> TripleRedisStorage { TripleRedisStorage { - redis_pool, + redis_pool: pool.clone(), node_account_id: account_id.clone(), } } +#[derive(Clone)] pub struct TripleRedisStorage { redis_pool: Pool, node_account_id: AccountId, } impl TripleRedisStorage { - pub async fn insert(&mut self, triple: Triple) -> TripleResult<()> { + pub async fn insert(&self, triple: Triple) -> TripleResult<()> { let mut conn = self.redis_pool.get().await?; conn.hset::<&str, TripleId, Triple, ()>(&self.triple_key(), triple.id, triple) .await?; Ok(()) } - pub async fn insert_mine(&mut self, triple: Triple) -> TripleResult<()> { + pub async fn insert_mine(&self, triple: Triple) -> TripleResult<()> { let mut conn = self.redis_pool.get().await?; conn.sadd::<&str, TripleId, ()>(&self.mine_key(), triple.id) .await?; @@ -53,7 +51,7 @@ impl TripleRedisStorage { Ok(result) } - pub async fn take(&mut self, id: &TripleId) -> TripleResult> { + pub async fn take(&self, id: &TripleId) -> TripleResult> { let mut conn = self.redis_pool.get().await?; if self.contains_mine(id).await? { tracing::error!("Can not take mine triple as foreign: {:?}", id); @@ -70,7 +68,7 @@ impl TripleRedisStorage { } } - pub async fn take_mine(&mut self) -> TripleResult> { + pub async fn take_mine(&self) -> TripleResult> { let mut conn = self.redis_pool.get().await?; let id: Option = conn.spop(self.mine_key()).await?; match id { @@ -91,7 +89,7 @@ impl TripleRedisStorage { Ok(result) } - pub async fn clear(&mut self) -> TripleResult<()> { + pub async fn clear(&self) -> TripleResult<()> { let mut conn = self.redis_pool.get().await?; conn.del::<&str, ()>(&self.triple_key()).await?; conn.del::<&str, ()>(&self.mine_key()).await?; diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 028f203a3..54f470d4b 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -158,7 +158,7 @@ impl Nodes<'_> { pub async fn triple_storage( &self, - redis_pool: Pool, + redis_pool: &Pool, account_id: &AccountId, ) -> TripleRedisStorage { storage::triple_storage::init(redis_pool, account_id) diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 8413af52e..99736231d 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -1,5 +1,4 @@ use std::str::FromStr; -use std::sync::Arc; use crate::actions::{self, add_latency, wait_for}; use crate::with_multichain_nodes; @@ -20,12 +19,10 @@ use mpc_node::kdf::into_eth_sig; use mpc_node::protocol::presignature::{Presignature, PresignatureId, PresignatureManager}; use mpc_node::protocol::triple::{Triple, TripleManager}; use mpc_node::storage; -use mpc_node::storage::presignature_storage::LockPresignatureRedisStorage; use mpc_node::types::LatestBlockHeight; use mpc_node::util::NearPublicKeyExt; use near_account_id::AccountId; use test_log::test; -use tokio::sync::RwLock; use url::Url; pub mod nightly; @@ -220,18 +217,15 @@ async fn test_triple_persistence() -> anyhow::Result<()> { let redis_url = Url::parse(redis.internal_address.as_str())?; let redis_cfg = deadpool_redis::Config::from_url(redis_url); let redis_pool = redis_cfg.create_pool(Some(Runtime::Tokio1)).unwrap(); - let triple_storage: storage::triple_storage::LockTripleRedisStorage = - Arc::new(RwLock::new(storage::triple_storage::init( - redis_pool.clone(), - &AccountId::from_str("test.near").unwrap(), - ))); + let triple_storage = + storage::triple_storage::init(&redis_pool, &AccountId::from_str("test.near").unwrap()); let mut triple_manager = TripleManager::new( Participant::from(0), 5, 123, &AccountId::from_str("test.near").unwrap(), - triple_storage, + &triple_storage, ); let triple_id_1: u64 = 1; @@ -311,17 +305,16 @@ async fn test_presignature_persistence() -> anyhow::Result<()> { let redis_url = Url::parse(redis.internal_address.as_str())?; let redis_cfg = deadpool_redis::Config::from_url(redis_url); let redis_pool = redis_cfg.create_pool(Some(Runtime::Tokio1)).unwrap(); - let presignature_storage: LockPresignatureRedisStorage = - Arc::new(RwLock::new(storage::presignature_storage::init( - redis_pool.clone(), - &AccountId::from_str("test.near").unwrap(), - ))); + let presignature_storage = storage::presignature_storage::init( + &redis_pool, + &AccountId::from_str("test.near").unwrap(), + ); let mut presignature_manager = PresignatureManager::new( Participant::from(0), 5, 123, &AccountId::from_str("test.near").unwrap(), - presignature_storage, + &presignature_storage, ); let presignature = dummy_presignature(); From b552acf58f24690998ec1ae06f7daeb7f44040a9 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 30 Oct 2024 13:15:57 +0200 Subject: [PATCH 47/64] fix conflicts --- .github/workflows/unit.yml | 8 +- chain-signatures/Cargo.lock | 401 ++++++++++++------ chain-signatures/contract/Cargo.toml | 2 +- chain-signatures/contract/src/errors/mod.rs | 2 +- chain-signatures/contract/src/lib.rs | 25 +- chain-signatures/contract/tests/updates.rs | 3 +- chain-signatures/node/Cargo.toml | 1 + chain-signatures/node/src/http_client.rs | 2 +- chain-signatures/node/src/indexer.rs | 38 +- chain-signatures/node/src/kdf.rs | 4 +- chain-signatures/node/src/mesh/connection.rs | 43 +- chain-signatures/node/src/protocol/message.rs | 30 +- .../node/src/protocol/signature.rs | 161 +++---- chain-signatures/node/src/protocol/triple.rs | 2 +- chain-signatures/node/src/web/mod.rs | 2 +- integration-tests/chain-signatures/Cargo.lock | 1 + .../chain-signatures/tests/actions/mod.rs | 109 ++++- .../tests/actions/wait_for.rs | 96 +++++ .../chain-signatures/tests/cases/mod.rs | 26 ++ 19 files changed, 711 insertions(+), 245 deletions(-) diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 79ac2aefd..7fa884fe1 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -61,8 +61,6 @@ jobs: ( cd test-oidc-provider ; cargo fmt -- --check ) ( cd integration-tests/chain-signatures ; cargo fmt -- --check ) ( cd integration-tests/fastauth ; cargo fmt -- --check ) - - name: Unit tests - run: ( cd mpc-recovery && cargo test ) - name: Test clippy run: | ( cd chain-signatures ; cargo clippy --tests -- -Dclippy::all ) @@ -71,6 +69,12 @@ jobs: ( cd test-oidc-provider ; cargo clippy --tests -- -Dclippy::all ) ( cd integration-tests/chain-signatures ; cargo clippy --tests -- -Dclippy::all ) ( cd integration-tests/fastauth ; cargo clippy --tests -- -Dclippy::all ) + - name: Unit tests (FastAuth) + working-directory: mpc-recovery + run: cargo test + - name: Unit tests (Chain Signatures) + working-directory: chain-signatures + run: cargo test audit: name: Audit diff --git a/chain-signatures/Cargo.lock b/chain-signatures/Cargo.lock index 47c8b8a3e..aa0151ec0 100644 --- a/chain-signatures/Cargo.lock +++ b/chain-signatures/Cargo.lock @@ -62,6 +62,18 @@ dependencies = [ "subtle", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.3" @@ -94,9 +106,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -109,43 +121,43 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.9" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] name = "anyhow" -version = "1.0.91" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" +checksum = "37bf3594c4c988a53154954629820791dde498571819ae4ca50ca811e060cc95" dependencies = [ "backtrace", ] @@ -252,7 +264,7 @@ dependencies = [ "futures-lite 2.3.0", "parking", "polling 3.7.3", - "rustix 0.38.38", + "rustix 0.38.37", "slab", "tracing", "windows-sys 0.59.0", @@ -302,7 +314,7 @@ dependencies = [ "cfg-if 1.0.0", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.38", + "rustix 0.38.37", "windows-sys 0.48.0", ] @@ -318,7 +330,7 @@ dependencies = [ "cfg-if 1.0.0", "futures-core", "futures-io", - "rustix 0.38.38", + "rustix 0.38.37", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -343,7 +355,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -360,7 +372,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -383,9 +395,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "aws-config" -version = "1.5.9" +version = "1.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6448cfb224dd6a9b9ac734f58622dd0d4751f3589f3b777345745f46b2eb14" +checksum = "7198e6f03240fdceba36656d8be440297b6b82270325908c7381f37d826a74f6" dependencies = [ "aws-credential-types", "aws-runtime", @@ -451,10 +463,11 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.58.0" +version = "1.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0656a79cf5e6ab0d4bb2465cd750a7a2fd7ea26c062183ed94225f5782e22365" +checksum = "8888c238bf93c77c5df8274b3999fd7fc1bb3fb658616f40dfde9e4fcd9efd94" dependencies = [ + "ahash", "aws-credential-types", "aws-runtime", "aws-sigv4", @@ -485,9 +498,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.47.0" +version = "1.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8776850becacbd3a82a4737a9375ddb5c6832a51379f24443a98e61513f852c" +checksum = "0dc2faec3205d496c7e57eff685dd944203df7ce16a4116d0281c44021788a7b" dependencies = [ "aws-credential-types", "aws-runtime", @@ -507,9 +520,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.48.0" +version = "1.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0007b5b8004547133319b6c4e87193eee2a0bcb3e4c18c75d09febe9dab7b383" +checksum = "c93c241f52bc5e0476e259c953234dab7e2a35ee207ee202e86c0095ec4951dc" dependencies = [ "aws-credential-types", "aws-runtime", @@ -529,9 +542,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.47.0" +version = "1.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fffaa356e7f1c725908b75136d53207fa714e348f365671df14e95a60530ad3" +checksum = "b259429be94a3459fa1b00c5684faee118d74f9577cc50aebadc36e507c63b5f" dependencies = [ "aws-credential-types", "aws-runtime", @@ -552,9 +565,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.2.5" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5619742a0d8f253be760bfbb8e8e8368c69e3587e4637af5754e488a611499b1" +checksum = "cc8db6904450bafe7473c6ca9123f88cc11089e41a025408f992db4e22d3be68" dependencies = [ "aws-credential-types", "aws-smithy-eventstream", @@ -592,9 +605,9 @@ dependencies = [ [[package]] name = "aws-smithy-checksums" -version = "0.60.13" +version = "0.60.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1a71073fca26775c8b5189175ea8863afb1c9ea2cceb02a5de5ad9dfbaa795" +checksum = "598b1689d001c4d4dc3cb386adb07d37786783aee3ac4b324bcadac116bf3d23" dependencies = [ "aws-smithy-http", "aws-smithy-types", @@ -664,9 +677,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.7.3" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" +checksum = "a065c0fe6fdbdf9f11817eb68582b2ab4aff9e9c39e986ae48f7ec576c6322db" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -708,9 +721,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.2.8" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07c9cdc179e6afbf5d391ab08c85eac817b51c87e1892a5edb5f7bbdc64314b4" +checksum = "147100a7bea70fa20ef224a6bad700358305f5dc0f84649c53769761395b355b" dependencies = [ "base64-simd", "bytes", @@ -985,7 +998,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", "syn_derive", ] @@ -1102,9 +1115,9 @@ dependencies = [ [[package]] name = "cargo-near-build" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd00f13698319e43d9af5b1afc7045131342f3097dd78320a09bb6303bbf2d06" +checksum = "09e969adcb72ace16b0048c1d73bbd2824cf931236473ec7f606b3f635334a34" dependencies = [ "bs58 0.5.1", "camino", @@ -1113,6 +1126,7 @@ dependencies = [ "dunce", "eyre", "hex", + "humantime", "libloading", "near-abi", "rustc_version", @@ -1121,6 +1135,7 @@ dependencies = [ "sha2", "symbolic-debuginfo", "tracing", + "wasm-opt", "zstd 0.13.2", ] @@ -1268,7 +1283,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -1277,11 +1292,21 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" @@ -1511,7 +1536,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -1521,7 +1546,51 @@ source = "git+https://github.com/dalek-cryptography/curve25519-dalek?rev=5b7082b dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", +] + +[[package]] +name = "cxx" +version = "1.0.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdc8cca144dce1c4981b5c9ab748761619979e515c3d53b5df385c677d1d007" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5764c3142ab44fcf857101d12c0ddf09c34499900557c764f5ad0597159d1fc" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.82", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d422aff542b4fa28c2ce8e5cc202d42dbf24702345c1fba3087b2d3f8a1b90ff" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1719100f31492cd6adeeab9a0f46cdbc846e615fdb66d7b398aa46ec7fdd06f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.82", ] [[package]] @@ -1569,7 +1638,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -1591,7 +1660,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core 0.20.10", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -1671,7 +1740,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -1715,7 +1784,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -1883,9 +1952,9 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.35" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if 1.0.0", ] @@ -1907,7 +1976,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -2197,7 +2266,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -2592,6 +2661,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.31" @@ -2679,7 +2754,7 @@ dependencies = [ "http 1.1.0", "hyper 1.5.0", "hyper-util", - "rustls 0.23.16", + "rustls 0.23.15", "rustls-pki-types", "tokio", "tokio-rustls 0.26.0", @@ -2718,9 +2793,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", @@ -3021,6 +3096,15 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "link-cplusplus" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d240c6f7e1ba3a28b0249f774e6a9dd0175054b52dfbb61b16eb8505c3785c9" +dependencies = [ + "cc", +] + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -3210,6 +3294,7 @@ dependencies = [ "aws-types", "axum", "axum-extra", + "borsh", "cait-sith", "chrono", "clap", @@ -3473,7 +3558,7 @@ dependencies = [ "near-crypto", "near-jsonrpc-primitives", "near-primitives", - "reqwest 0.12.9", + "reqwest 0.12.8", "serde", "serde_json", "thiserror", @@ -3502,7 +3587,7 @@ version = "0.8.0-beta.3" source = "git+https://github.com/near/near-lake-framework-rs?branch=node/2.3.0#d452f5be481cf6ae6627333aa97a506434c5bc9a" dependencies = [ "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -3634,7 +3719,7 @@ checksum = "df598b0785a3e36d7e4fb73afcdf20536988b13d07cead71dfa777db4783e552" dependencies = [ "quote", "serde", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -3645,7 +3730,7 @@ checksum = "647ef261df99ad877c08c97af2f10368c8b8cde0968250d3482a5a249e9f3926" dependencies = [ "near-rpc-error-core", "serde", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -3700,7 +3785,7 @@ dependencies = [ "serde_json", "strum 0.26.3", "strum_macros 0.26.4", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -3778,7 +3863,7 @@ dependencies = [ "num-rational", "once_cell", "ripemd", - "rustix 0.38.38", + "rustix 0.38.37", "serde", "serde_repr", "sha2", @@ -3792,8 +3877,9 @@ dependencies = [ [[package]] name = "near-workspaces" -version = "0.14.0" -source = "git+https://github.com/near/near-workspaces-rs?branch=phuong/tmp-node-2.3.0#2c3925b9af091062b19e3ff1c13753a077e74cbd" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "268b4a18fd4f24423d2d947b079608c446b3eb2bb61b9e262d5cfa198046947b" dependencies = [ "async-trait", "base64 0.22.1", @@ -3813,7 +3899,7 @@ dependencies = [ "near-sandbox-utils", "near-token", "rand", - "reqwest 0.12.9", + "reqwest 0.12.8", "serde", "serde_json", "sha2", @@ -4046,7 +4132,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -4204,29 +4290,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.7" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -4303,7 +4389,7 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.38", + "rustix 0.38.37", "tracing", "windows-sys 0.59.0", ] @@ -4415,9 +4501,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -4454,7 +4540,7 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.16", + "rustls 0.23.15", "socket2 0.5.7", "thiserror", "tokio", @@ -4471,7 +4557,7 @@ dependencies = [ "rand", "ring", "rustc-hash", - "rustls 0.23.16", + "rustls 0.23.15", "slab", "thiserror", "tinyvec", @@ -4480,11 +4566,10 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.6" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ - "cfg_aliases", "libc", "once_cell", "socket2 0.5.7", @@ -4604,9 +4689,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", @@ -4694,9 +4779,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" dependencies = [ "base64 0.22.1", "bytes", @@ -4720,7 +4805,7 @@ dependencies = [ "percent-encoding 2.3.1", "pin-project-lite", "quinn", - "rustls 0.23.16", + "rustls 0.23.15", "rustls-pemfile 2.2.0", "rustls-pki-types", "serde", @@ -4850,9 +4935,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -4889,9 +4974,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.16" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "log", "once_cell", @@ -5014,7 +5099,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5023,6 +5108,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scratch" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf7c11c38cb994f3d40e8a8cde3bbd1f72a435e4c49e85d6553d8312306152" + [[package]] name = "scroll" version = "0.10.2" @@ -5046,7 +5137,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5147,22 +5238,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5173,7 +5264,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5206,7 +5297,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5248,7 +5339,7 @@ dependencies = [ "darling 0.20.10", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5527,7 +5618,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5591,9 +5682,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.85" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -5609,7 +5700,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5709,28 +5800,37 @@ dependencies = [ "cfg-if 1.0.0", "fastrand 2.1.1", "once_cell", - "rustix 0.38.38", + "rustix 0.38.37", "windows-sys 0.59.0", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5802,9 +5902,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -5826,7 +5926,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -5877,7 +5977,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" dependencies = [ - "rustls 0.23.16", + "rustls 0.23.15", "rustls-pki-types", "tokio", ] @@ -5971,7 +6071,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -6086,6 +6186,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "universal-hash" version = "0.5.1" @@ -6118,7 +6224,7 @@ dependencies = [ "flate2", "log", "once_cell", - "rustls 0.23.16", + "rustls 0.23.15", "rustls-pki-types", "url 2.5.2", "webpki-roots", @@ -6248,7 +6354,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", "wasm-bindgen-shared", ] @@ -6282,7 +6388,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6293,6 +6399,46 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +[[package]] +name = "wasm-opt" +version = "0.116.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd87a4c135535ffed86123b6fb0f0a5a0bc89e50416c942c5f0662c645f679c" +dependencies = [ + "anyhow", + "libc", + "strum 0.24.1", + "strum_macros 0.24.3", + "tempfile", + "thiserror", + "wasm-opt-cxx-sys", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-cxx-sys" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c57b28207aa724318fcec6575fe74803c23f6f266fce10cbc9f3f116762f12e" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "wasm-opt-sys", +] + +[[package]] +name = "wasm-opt-sys" +version = "0.116.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a1cce564dc768dacbdb718fc29df2dba80bd21cb47d8f77ae7e3d95ceb98cbe" +dependencies = [ + "anyhow", + "cc", + "cxx", + "cxx-build", +] + [[package]] name = "wasmparser" version = "0.83.0" @@ -6346,6 +6492,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -6391,7 +6546,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -6402,7 +6557,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -6637,7 +6792,7 @@ checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", "linux-raw-sys 0.4.14", - "rustix 0.38.38", + "rustix 0.38.37", ] [[package]] @@ -6697,7 +6852,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] @@ -6717,7 +6872,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.85", + "syn 2.0.82", ] [[package]] diff --git a/chain-signatures/contract/Cargo.toml b/chain-signatures/contract/Cargo.toml index 6a8a25557..cc8bbc47a 100644 --- a/chain-signatures/contract/Cargo.toml +++ b/chain-signatures/contract/Cargo.toml @@ -29,4 +29,4 @@ digest = "0.10.7" # near dependencies near-crypto = "0.26.0" -near-workspaces = { git = "https://github.com/near/near-workspaces-rs", branch = "phuong/tmp-node-2.3.0" } +near-workspaces = "0.14.1" \ No newline at end of file diff --git a/chain-signatures/contract/src/errors/mod.rs b/chain-signatures/contract/src/errors/mod.rs index 2c5cf8284..b3eb3388a 100644 --- a/chain-signatures/contract/src/errors/mod.rs +++ b/chain-signatures/contract/src/errors/mod.rs @@ -6,7 +6,7 @@ pub enum SignError { #[error("Signature request has timed out.")] Timeout, #[error("Signature request has already been submitted. Please try again later.")] - PayloadCollision, + RequestCollision, #[error( "This key version is not supported. Call latest_key_version() to get the latest supported version." )] diff --git a/chain-signatures/contract/src/lib.rs b/chain-signatures/contract/src/lib.rs index c75fccb90..39740ec73 100644 --- a/chain-signatures/contract/src/lib.rs +++ b/chain-signatures/contract/src/lib.rs @@ -41,10 +41,10 @@ const GAS_FOR_SIGN_CALL: Gas = Gas::from_tgas(50); const DATA_ID_REGISTER: u64 = 0; // Prepaid gas for a `clear_state_on_finish` call -const CLEAR_STATE_ON_FINISH_CALL_GAS: Gas = Gas::from_tgas(10); +const CLEAR_STATE_ON_FINISH_CALL_GAS: Gas = Gas::from_tgas(20); // Prepaid gas for a `return_signature_on_finish` call -const RETURN_SIGNATURE_ON_FINISH_CALL_GAS: Gas = Gas::from_tgas(5); +const RETURN_SIGNATURE_ON_FINISH_CALL_GAS: Gas = Gas::from_tgas(10); // Prepaid gas for a `update_config` call const UPDATE_CONFIG_GAS: Gas = Gas::from_tgas(5); @@ -64,17 +64,23 @@ impl Default for VersionedMpcContract { #[derive(BorshDeserialize, BorshSerialize, Debug)] pub struct MpcContract { protocol_state: ProtocolContractState, - pending_requests: LookupMap, + pending_requests: LookupMap>, request_counter: u32, proposed_updates: ProposedUpdates, config: Config, } impl MpcContract { + fn mark_request_received(&mut self, request: &SignatureRequest) { + if self.pending_requests.insert(request, &None).is_none() { + self.request_counter += 1; + } + } + fn add_request(&mut self, request: &SignatureRequest, data_id: CryptoHash) { if self .pending_requests - .insert(request, &YieldIndex { data_id }) + .insert(request, &Some(YieldIndex { data_id })) .is_none() { self.request_counter += 1; @@ -166,6 +172,7 @@ impl VersionedMpcContract { "sign: predecessor={predecessor}, payload={payload:?}, path={path:?}, key_version={key_version}", ); env::log_str(&serde_json::to_string(&near_sdk::env::random_seed_array()).unwrap()); + self.mark_request_received(&request); let contract_signature_request = ContractSignatureRequest { request, requester: predecessor, @@ -174,7 +181,7 @@ impl VersionedMpcContract { }; Ok(Self::ext(env::current_account_id()).sign_helper(contract_signature_request)) } else { - Err(SignError::PayloadCollision.into()) + Err(SignError::RequestCollision.into()) } } @@ -275,7 +282,7 @@ impl VersionedMpcContract { match self { Self::V0(mpc_contract) => { - if let Some(YieldIndex { data_id }) = + if let Some(Some(YieldIndex { data_id })) = mpc_contract.pending_requests.get(&request) { env::promise_yield_resume( @@ -803,6 +810,12 @@ impl VersionedMpcContract { } } + fn mark_request_received(&mut self, request: &SignatureRequest) { + match self { + Self::V0(ref mut mpc_contract) => mpc_contract.mark_request_received(request), + } + } + fn threshold(&self) -> Result { match self { Self::V0(contract) => match &contract.protocol_state { diff --git a/chain-signatures/contract/tests/updates.rs b/chain-signatures/contract/tests/updates.rs index e9a8974b6..496309d77 100644 --- a/chain-signatures/contract/tests/updates.rs +++ b/chain-signatures/contract/tests/updates.rs @@ -46,7 +46,8 @@ async fn test_propose_contract_max_size_upload() { let execution = accounts[0] .call(contract.id(), "propose_update") .args_borsh((ProposeUpdateArgs { - code: Some(vec![0; 3900 * 1024]), + // current protocol can only accept 1.5mb as transaction arg + code: Some(vec![0; 1535 * 1024]), config: None, },)) .max_gas() diff --git a/chain-signatures/node/Cargo.toml b/chain-signatures/node/Cargo.toml index 81ca8408f..f8f089d61 100644 --- a/chain-signatures/node/Cargo.toml +++ b/chain-signatures/node/Cargo.toml @@ -15,6 +15,7 @@ aws-sdk-s3 = "1.29" aws-types = "1.2" axum = { version = "0.6.19" } axum-extra = "0.7" +borsh = "1.5.0" cait-sith = { git = "https://github.com/LIT-Protocol/cait-sith.git", features = [ "k256", ], rev = "8ad2316" } diff --git a/chain-signatures/node/src/http_client.rs b/chain-signatures/node/src/http_client.rs index eaf5c37c2..4620a805f 100644 --- a/chain-signatures/node/src/http_client.rs +++ b/chain-signatures/node/src/http_client.rs @@ -44,7 +44,7 @@ pub enum SendError { ParticipantNotAlive(String), } -async fn send_encrypted( +pub async fn send_encrypted( from: Participant, client: &Client, url: U, diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index 9335e4bfd..a744b69d5 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -47,7 +47,7 @@ pub struct Options { pub start_block_height: u64, /// The amount of time before we should that our indexer is behind. - #[clap(long, env("MPC_INDEXER_BEHIND_THRESHOLD"), default_value = "180")] + #[clap(long, env("MPC_INDEXER_BEHIND_THRESHOLD"), default_value = "200")] pub behind_threshold: u64, /// The threshold in seconds to check if the indexer needs to be restarted due to it stalling. @@ -103,6 +103,7 @@ pub struct ContractSignRequest { pub struct Indexer { latest_block_height: Arc>, last_updated_timestamp: Arc>, + latest_block_timestamp_nanosec: Arc>>, running_threshold: Duration, behind_threshold: Duration, } @@ -116,6 +117,7 @@ impl Indexer { Self { latest_block_height: Arc::new(RwLock::new(latest_block_height)), last_updated_timestamp: Arc::new(RwLock::new(Instant::now())), + latest_block_timestamp_nanosec: Arc::new(RwLock::new(None)), running_threshold: Duration::from_secs(options.running_threshold), behind_threshold: Duration::from_secs(options.behind_threshold), } @@ -126,11 +128,6 @@ impl Indexer { self.latest_block_height.read().await.block_height } - /// Check whether the indexer is on track with the latest block height from the chain. - pub async fn is_on_track(&self) -> bool { - self.last_updated_timestamp.read().await.elapsed() <= self.behind_threshold - } - /// Check whether the indexer is on track with the latest block height from the chain. pub async fn is_running(&self) -> bool { self.last_updated_timestamp.read().await.elapsed() <= self.running_threshold @@ -138,16 +135,31 @@ impl Indexer { /// Check whether the indexer is behind with the latest block height from the chain. pub async fn is_behind(&self) -> bool { - self.last_updated_timestamp.read().await.elapsed() > self.behind_threshold + if let Some(latest_block_timestamp_nanosec) = + *self.latest_block_timestamp_nanosec.read().await + { + crate::util::is_elapsed_longer_than_timeout( + latest_block_timestamp_nanosec / 1_000_000_000, + self.behind_threshold.as_millis() as u64, + ) + } else { + true + } + } + + pub async fn is_stable(&self) -> bool { + !self.is_behind().await && self.is_running().await } - async fn update_block_height( + async fn update_block_height_and_timestamp( &self, block_height: BlockHeight, + block_timestamp_nanosec: u64, gcp: &GcpService, ) -> Result<(), DatastoreStorageError> { - tracing::debug!(block_height, "update_block_height"); + tracing::debug!(block_height, "update_block_height_and_timestamp"); *self.last_updated_timestamp.write().await = Instant::now(); + *self.latest_block_timestamp_nanosec.write().await = Some(block_timestamp_nanosec); self.latest_block_height .write() .await @@ -239,7 +251,7 @@ async fn handle_block( key_version: arguments.request.key_version, }; pending_requests.push(SignRequest { - receipt_id, + request_id: receipt_id.0, request, epsilon, entropy, @@ -251,7 +263,11 @@ async fn handle_block( } ctx.indexer - .update_block_height(block.block_height(), &ctx.gcp_service) + .update_block_height_and_timestamp( + block.block_height(), + block.header().timestamp_nanosec(), + &ctx.gcp_service, + ) .await?; crate::metrics::LATEST_BLOCK_HEIGHT diff --git a/chain-signatures/node/src/kdf.rs b/chain-signatures/node/src/kdf.rs index d38218ae2..5cdaaa33a 100644 --- a/chain-signatures/node/src/kdf.rs +++ b/chain-signatures/node/src/kdf.rs @@ -9,12 +9,12 @@ use sha3::Sha3_256; // that we generate different random scalars as delta tweaks. // Receipt ID should be unique inside of a block, so it serves us as the request identifier. pub fn derive_delta( - receipt_id: CryptoHash, + request_id: [u8; 32], entropy: [u8; 32], presignature_big_r: AffinePoint, ) -> Scalar { let hk = Hkdf::::new(None, &entropy); - let info = format!("{DELTA_DERIVATION_PREFIX}:{}", receipt_id); + let info = format!("{DELTA_DERIVATION_PREFIX}:{}", CryptoHash(request_id)); let mut okm = [0u8; 32]; hk.expand(info.as_bytes(), &mut okm).unwrap(); hk.expand( diff --git a/chain-signatures/node/src/mesh/connection.rs b/chain-signatures/node/src/mesh/connection.rs index 18041fe1e..310f43638 100644 --- a/chain-signatures/node/src/mesh/connection.rs +++ b/chain-signatures/node/src/mesh/connection.rs @@ -9,6 +9,7 @@ use crate::protocol::contract::primitives::Participants; use crate::protocol::ParticipantInfo; use crate::protocol::ProtocolState; use crate::web::StateView; +use mpc_keys::hpke::Ciphered; // TODO: this is a basic connection pool and does not do most of the work yet. This is // mostly here just to facilitate offline node handling for now. @@ -71,10 +72,15 @@ impl Pool { let mut participants = Participants::default(); for (participant, info) in connections.iter() { match self.fetch_participant_state(info).await { - Ok(state) => { - status.insert(*participant, state); - participants.insert(participant, info.clone()); - } + Ok(state) => match self.send_empty_msg(participant, info).await { + Ok(()) => { + status.insert(*participant, state); + participants.insert(participant, info.clone()); + } + Err(e) => { + tracing::warn!("Send empty msg for participant {participant:?} with url {} has failed with error {e}.", info.url); + } + }, Err(e) => { tracing::warn!("Fetch state for participant {participant:?} with url {} has failed with error {e}.", info.url); } @@ -100,10 +106,15 @@ impl Pool { let mut participants = Participants::default(); for (participant, info) in connections.iter() { match self.fetch_participant_state(info).await { - Ok(state) => { - status.insert(*participant, state); - participants.insert(participant, info.clone()); - } + Ok(state) => match self.send_empty_msg(participant, info).await { + Ok(()) => { + status.insert(*participant, state); + participants.insert(participant, info.clone()); + } + Err(e) => { + tracing::warn!("Send empty msg for participant {participant:?} with url {} has failed with error {e}.", info.url); + } + }, Err(e) => { tracing::warn!("Fetch state for participant {participant:?} with url {} has failed with error {e}.", info.url); } @@ -186,4 +197,20 @@ impl Pool { Err(_) => Err(FetchParticipantError::Timeout), } } + + async fn send_empty_msg( + &self, + participant: &Participant, + participant_info: &ParticipantInfo, + ) -> Result<(), crate::http_client::SendError> { + let empty_msg: Vec = Vec::new(); + crate::http_client::send_encrypted( + *participant, + &self.http, + participant_info.url.clone(), + empty_msg, + self.fetch_participant_timeout, + ) + .await + } } diff --git a/chain-signatures/node/src/protocol/message.rs b/chain-signatures/node/src/protocol/message.rs index 91ad7f01f..e6f0f4545 100644 --- a/chain-signatures/node/src/protocol/message.rs +++ b/chain-signatures/node/src/protocol/message.rs @@ -1,5 +1,6 @@ use super::cryptography::CryptographicError; use super::presignature::{GenerationError, PresignatureId}; +use super::signature::SignRequestIdentifier; use super::state::{GeneratingState, NodeState, ResharingState, RunningState}; use super::triple::TripleId; use crate::gcp::error::SecretStorageError; @@ -13,7 +14,6 @@ use cait_sith::protocol::{InitializationError, MessageData, Participant, Protoco use k256::Scalar; use mpc_keys::hpke::{self, Ciphered}; use near_crypto::Signature; -use near_primitives::hash::CryptoHash; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, VecDeque}; use std::sync::Arc; @@ -63,7 +63,7 @@ pub struct PresignatureMessage { #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] pub struct SignatureMessage { - pub receipt_id: CryptoHash, + pub request_id: [u8; 32], pub proposer: Participant, pub presignature_id: PresignatureId, pub request: ContractSignRequest, @@ -103,7 +103,7 @@ pub struct MpcMessageQueue { resharing_bins: HashMap>, triple_bins: HashMap>>, presignature_bins: HashMap>>, - signature_bins: HashMap>>, + signature_bins: HashMap>>, } impl MpcMessageQueue { @@ -133,7 +133,11 @@ impl MpcMessageQueue { .signature_bins .entry(message.epoch) .or_default() - .entry(message.receipt_id) + .entry(SignRequestIdentifier::new( + message.request_id, + message.epsilon, + message.request.payload, + )) .or_default() .push_back(message), } @@ -369,7 +373,7 @@ impl MessageHandler for RunningState { let mut signature_manager = self.signature_manager.write().await; let signature_messages = queue.signature_bins.entry(self.epoch).or_default(); - signature_messages.retain(|receipt_id, queue| { + signature_messages.retain(|sign_request_identifier, queue| { // Skip message if it already timed out if queue.is_empty() || queue.iter().any(|msg| { @@ -382,9 +386,9 @@ impl MessageHandler for RunningState { return false; } - !signature_manager.refresh_gc(receipt_id) + !signature_manager.refresh_gc(sign_request_identifier) }); - for (receipt_id, queue) in signature_messages { + for (sign_request_identifier, queue) in signature_messages { // SAFETY: this unwrap() is safe since we have already checked that the queue is not empty. let SignatureMessage { proposer, @@ -418,7 +422,7 @@ impl MessageHandler for RunningState { let protocol = match signature_manager .get_or_start_protocol( participants, - *receipt_id, + sign_request_identifier.request_id, *proposer, *presignature_id, request, @@ -443,7 +447,11 @@ impl MessageHandler for RunningState { // and have the other nodes timeout in the following cases: // - If a presignature is in GC, then it was used already or failed to be produced. // - If a presignature is missing, that means our system cannot process this signature. - tracing::warn!(%receipt_id, ?err, "signature cannot be generated"); + tracing::warn!( + ?sign_request_identifier, + ?err, + "signature cannot be generated" + ); queue.clear(); continue; } @@ -451,7 +459,7 @@ impl MessageHandler for RunningState { // ignore the whole of the messages since the generation had bad parameters. Also have the other node who // initiated the protocol resend the message or have it timeout on their side. tracing::warn!( - ?receipt_id, + ?sign_request_identifier, presignature_id, ?error, "unable to initialize incoming signature protocol" @@ -461,7 +469,7 @@ impl MessageHandler for RunningState { } Err(err) => { tracing::warn!( - ?receipt_id, + ?sign_request_identifier, ?err, "Unexpected error encounted while generating signature" ); diff --git a/chain-signatures/node/src/protocol/signature.rs b/chain-signatures/node/src/protocol/signature.rs index 8b42e54be..4bdb898b4 100644 --- a/chain-signatures/node/src/protocol/signature.rs +++ b/chain-signatures/node/src/protocol/signature.rs @@ -28,7 +28,7 @@ use near_fetch::signer::SignerExt; pub type ReceiptId = near_primitives::hash::CryptoHash; pub struct SignRequest { - pub receipt_id: ReceiptId, + pub request_id: [u8; 32], pub request: ContractSignRequest, pub epsilon: Scalar, pub entropy: [u8; 32], @@ -38,18 +38,12 @@ pub struct SignRequest { /// Type that preserves the insertion order of requests. #[derive(Default)] pub struct ParticipantRequests { - requests: HashMap, - order: VecDeque, + requests: VecDeque, } impl ParticipantRequests { - fn insert(&mut self, receipt_id: ReceiptId, request: SignRequest) { - self.requests.insert(receipt_id, request); - self.order.push_back(receipt_id); - } - - fn contains_key(&self, receipt_id: &ReceiptId) -> bool { - self.requests.contains_key(receipt_id) + fn insert(&mut self, request: SignRequest) { + self.requests.push_back(request); } pub fn len(&self) -> usize { @@ -60,11 +54,8 @@ impl ParticipantRequests { self.len() == 0 } - pub fn pop_front(&mut self) -> Option<(ReceiptId, SignRequest)> { - let receipt_id = self.order.pop_front()?; - self.requests - .remove(&receipt_id) - .map(|req| (receipt_id, req)) + pub fn pop_front(&mut self) -> Option { + self.requests.pop_front() } } @@ -89,7 +80,7 @@ impl SignQueue { pub fn add(&mut self, request: SignRequest) { tracing::info!( - receipt_id = %request.receipt_id, + request_id = ?CryptoHash(request.request_id), payload = hex::encode(request.request.payload.to_bytes()), entropy = hex::encode(request.entropy), "new sign request" @@ -120,14 +111,14 @@ impl SignQueue { if subset.contains(&&me) { let is_mine = proposer == me; tracing::info!( - receipt_id = %request.receipt_id, + request_id = ?CryptoHash(request.request_id), ?is_mine, ?subset, ?proposer, "saving sign request: node is in the signer subset" ); let proposer_requests = self.requests.entry(proposer).or_default(); - proposer_requests.insert(request.receipt_id, request); + proposer_requests.insert(request); if is_mine { crate::metrics::NUM_SIGN_REQUESTS_MINE .with_label_values(&[my_account_id.as_str()]) @@ -135,7 +126,7 @@ impl SignQueue { } } else { tracing::info!( - receipt_id = %request.receipt_id, + rrequest_id = ?CryptoHash(request.request_id), ?me, ?subset, ?proposer, @@ -145,13 +136,6 @@ impl SignQueue { } } - pub fn contains(&self, participant: Participant, receipt_id: ReceiptId) -> bool { - let Some(participant_requests) = self.requests.get(&participant) else { - return false; - }; - participant_requests.contains_key(&receipt_id) - } - pub fn my_requests(&mut self, me: Participant) -> &mut ParticipantRequests { self.requests.entry(me).or_default() } @@ -165,7 +149,7 @@ pub struct SignatureGenerator { pub presignature_id: PresignatureId, pub request: ContractSignRequest, pub epsilon: Scalar, - pub receipt_id: CryptoHash, + pub request_id: [u8; 32], pub entropy: [u8; 32], pub sign_request_timestamp: Instant, pub generator_timestamp: Instant, @@ -182,7 +166,7 @@ impl SignatureGenerator { presignature_id: PresignatureId, request: ContractSignRequest, epsilon: Scalar, - receipt_id: CryptoHash, + request_id: [u8; 32], entropy: [u8; 32], sign_request_timestamp: Instant, cfg: &ProtocolConfig, @@ -194,7 +178,7 @@ impl SignatureGenerator { presignature_id, request, epsilon, - receipt_id, + request_id, entropy, sign_request_timestamp, generator_timestamp: Instant::now(), @@ -227,18 +211,35 @@ pub struct GenerationRequest { pub proposer: Participant, pub request: ContractSignRequest, pub epsilon: Scalar, - pub receipt_id: CryptoHash, + pub request_id: [u8; 32], pub entropy: [u8; 32], pub sign_request_timestamp: Instant, } +#[derive(Debug, Clone, Eq, Hash, PartialEq)] +pub struct SignRequestIdentifier { + pub request_id: [u8; 32], + pub epsilon: Vec, + pub payload: Vec, +} + +impl SignRequestIdentifier { + pub fn new(request_id: [u8; 32], epsilon: Scalar, payload: Scalar) -> Self { + Self { + request_id, + epsilon: borsh::to_vec(&SerializableScalar { scalar: epsilon }).unwrap(), + payload: borsh::to_vec(&SerializableScalar { scalar: payload }).unwrap(), + } + } +} + pub struct SignatureManager { /// Ongoing signature generation protocols. - generators: HashMap, + generators: HashMap, /// Failed signatures awaiting to be retried. - failed: VecDeque<(ReceiptId, GenerationRequest)>, + failed: VecDeque<(SignRequestIdentifier, GenerationRequest)>, /// Set of completed signatures - completed: HashMap, + completed: HashMap, /// Generated signatures assigned to the current node that are yet to be published. /// Vec<(receipt_id, msg_hash, timestamp, output)> signatures: Vec, @@ -250,7 +251,7 @@ pub struct SignatureManager { pub const MAX_RETRY: u8 = 10; pub struct ToPublish { - receipt_id: ReceiptId, + request_id: [u8; 32], request: SignatureRequest, time_added: Instant, signature: FullSignature, @@ -259,13 +260,13 @@ pub struct ToPublish { impl ToPublish { pub fn new( - receipt_id: ReceiptId, + request_id: [u8; 32], request: SignatureRequest, time_added: Instant, signature: FullSignature, ) -> ToPublish { ToPublish { - receipt_id, + request_id, request, time_added, signature, @@ -316,12 +317,12 @@ impl SignatureManager { proposer, request, epsilon, - receipt_id, + request_id, entropy, sign_request_timestamp, } = req; let PresignOutput { big_r, k, sigma } = presignature.output; - let delta = derive_delta(receipt_id, entropy, big_r); + let delta = derive_delta(request_id, entropy, big_r); // TODO: Check whether it is okay to use invert_vartime instead let output: PresignOutput = PresignOutput { big_r: (big_r * delta).to_affine(), @@ -346,7 +347,7 @@ impl SignatureManager { presignature_id, request, epsilon, - receipt_id, + request_id, entropy, sign_request_timestamp, cfg, @@ -356,13 +357,13 @@ impl SignatureManager { #[allow(clippy::result_large_err)] fn retry_failed_generation( &mut self, - receipt_id: ReceiptId, + sign_request_identifier: SignRequestIdentifier, req: GenerationRequest, presignature: Presignature, participants: &Participants, cfg: &ProtocolConfig, ) -> Result<(), (Presignature, InitializationError)> { - tracing::info!(receipt_id = %receipt_id, participants = ?participants.keys_vec(), "restarting failed protocol to generate signature"); + tracing::info!(sign_request_identifier = ?sign_request_identifier, participants = ?participants.keys_vec(), "restarting failed protocol to generate signature"); let generator = Self::generate_internal( participants, self.me, @@ -374,7 +375,7 @@ impl SignatureManager { crate::metrics::NUM_TOTAL_HISTORICAL_SIGNATURE_GENERATORS .with_label_values(&[self.my_account_id.as_str()]) .inc(); - self.generators.insert(receipt_id, generator); + self.generators.insert(sign_request_identifier, generator); Ok(()) } @@ -384,7 +385,7 @@ impl SignatureManager { pub fn generate( &mut self, participants: &Participants, - receipt_id: ReceiptId, + request_id: [u8; 32], presignature: Presignature, request: ContractSignRequest, epsilon: Scalar, @@ -392,8 +393,10 @@ impl SignatureManager { sign_request_timestamp: Instant, cfg: &ProtocolConfig, ) -> Result<(), (Presignature, InitializationError)> { + let sign_request_identifier = + SignRequestIdentifier::new(request_id, epsilon, request.payload); tracing::info!( - %receipt_id, + ?sign_request_identifier, me = ?self.me, presignature_id = presignature.id, participants = ?participants.keys_vec(), @@ -408,7 +411,7 @@ impl SignatureManager { proposer: self.me, request, epsilon, - receipt_id, + request_id, entropy, sign_request_timestamp, }, @@ -417,7 +420,7 @@ impl SignatureManager { crate::metrics::NUM_TOTAL_HISTORICAL_SIGNATURE_GENERATORS .with_label_values(&[self.my_account_id.as_str()]) .inc(); - self.generators.insert(receipt_id, generator); + self.generators.insert(sign_request_identifier, generator); Ok(()) } @@ -431,7 +434,7 @@ impl SignatureManager { pub async fn get_or_start_protocol( &mut self, participants: &Participants, - receipt_id: ReceiptId, + request_id: [u8; 32], proposer: Participant, presignature_id: PresignatureId, request: &ContractSignRequest, @@ -440,13 +443,15 @@ impl SignatureManager { presignature_manager: &mut PresignatureManager, cfg: &ProtocolConfig, ) -> Result<&mut SignatureProtocol, GenerationError> { - if self.completed.contains_key(&receipt_id) { - tracing::warn!(%receipt_id, presignature_id, "presignature has already been used to generate a signature"); + let sign_request_identifier = + SignRequestIdentifier::new(request_id, epsilon, request.payload); + if self.completed.contains_key(&sign_request_identifier) { + tracing::warn!(sign_request_identifier = ?sign_request_identifier.clone(), presignature_id, "presignature has already been used to generate a signature"); return Err(GenerationError::AlreadyGenerated); } - match self.generators.entry(receipt_id) { + match self.generators.entry(sign_request_identifier.clone()) { Entry::Vacant(entry) => { - tracing::info!(%receipt_id, me = ?self.me, presignature_id, "joining protocol to generate a new signature"); + tracing::info!(sign_request_identifier = ?sign_request_identifier.clone(), me = ?self.me, presignature_id, "joining protocol to generate a new signature"); let presignature = match presignature_manager.take(presignature_id).await { Ok(presignature) => presignature, Err(err @ GenerationError::PresignatureIsGenerating(_)) => { @@ -474,7 +479,7 @@ impl SignatureManager { request: request.clone(), epsilon, entropy, - receipt_id, + request_id, sign_request_timestamp: Instant::now(), }, cfg, @@ -482,7 +487,7 @@ impl SignatureManager { Ok(generator) => generator, Err((presignature, err @ InitializationError::BadParameters(_))) => { presignature_manager.insert_mine(presignature).await; - tracing::warn!(%receipt_id, presignature_id, ?err, "failed to start signature generation"); + tracing::warn!(sign_request = ?sign_request_identifier, presignature_id, ?err, "failed to start signature generation"); return Err(GenerationError::CaitSithInitializationError(err)); } }; @@ -502,7 +507,7 @@ impl SignatureManager { /// An empty vector means we cannot progress until we receive a new message. pub fn poke(&mut self) -> Vec<(Participant, SignatureMessage)> { let mut messages = Vec::new(); - self.generators.retain(|receipt_id, generator| { + self.generators.retain(|sign_request_identifier, generator| { loop { let action = match generator.poke() { Ok(action) => action, @@ -516,18 +521,18 @@ impl SignatureManager { // only retry the signature generation if it was initially proposed by us. We do not // want any nodes to be proposing the same signature multiple times. self.failed.push_back(( - *receipt_id, + sign_request_identifier.clone(), GenerationRequest { proposer: generator.proposer, request: generator.request.clone(), epsilon: generator.epsilon, - receipt_id: generator.receipt_id, + request_id: generator.request_id, entropy: generator.entropy, sign_request_timestamp: generator.sign_request_timestamp }, )); } else { - self.completed.insert(*receipt_id, Instant::now()); + self.completed.insert(sign_request_identifier.clone(), Instant::now()); crate::metrics::SIGNATURE_FAILURES .with_label_values(&[self.my_account_id.as_str()]) .inc(); @@ -548,7 +553,7 @@ impl SignatureManager { messages.push(( *p, SignatureMessage { - receipt_id: *receipt_id, + request_id: sign_request_identifier.request_id, proposer: generator.proposer, presignature_id: generator.presignature_id, request: generator.request.clone(), @@ -565,7 +570,7 @@ impl SignatureManager { Action::SendPrivate(p, data) => messages.push(( p, SignatureMessage { - receipt_id: *receipt_id, + request_id: sign_request_identifier.request_id, proposer: generator.proposer, presignature_id: generator.presignature_id, request: generator.request.clone(), @@ -579,21 +584,21 @@ impl SignatureManager { )), Action::Return(output) => { tracing::info!( - ?receipt_id, + sign_request_identifier =?sign_request_identifier.clone(), me = ?self.me, presignature_id = generator.presignature_id, big_r = ?output.big_r.to_base58(), s = ?output.s, "completed signature generation" ); - self.completed.insert(*receipt_id, Instant::now()); + self.completed.insert(sign_request_identifier.clone(), Instant::now()); let request = SignatureRequest { epsilon: SerializableScalar {scalar: generator.epsilon}, payload_hash: generator.request.payload.into(), }; if generator.proposer == self.me { self.signatures - .push(ToPublish::new(*receipt_id, request, generator.sign_request_timestamp, output)); + .push(ToPublish::new(sign_request_identifier.request_id, request, generator.sign_request_timestamp, output)); } // Do not retain the protocol return false; @@ -644,17 +649,22 @@ impl SignatureManager { // TODO: we need to decide how to prioritize certain requests over others such as with gas or time of // when the request made it into the NEAR network. // issue: https://github.com/near/mpc-recovery/issues/596 - if let Some((receipt_id, failed_req)) = self.failed.pop_front() { + if let Some((sign_request_identifier, failed_req)) = self.failed.pop_front() { if let Err((presignature, InitializationError::BadParameters(err))) = self .retry_failed_generation( - receipt_id, + sign_request_identifier.clone(), failed_req, presignature, &sig_participants, cfg, ) { - tracing::warn!(%receipt_id, presig_id, ?err, "failed to retry signature generation: trashing presignature"); + tracing::warn!( + ?sign_request_identifier, + presig_id, + ?err, + "failed to retry signature generation: trashing presignature" + ); failed_presigs.push(presignature); continue; } @@ -666,13 +676,14 @@ impl SignatureManager { } } - let Some((receipt_id, my_request)) = my_requests.pop_front() else { + let Some(my_request) = my_requests.pop_front() else { failed_presigs.push(presignature); continue; }; + if let Err((presignature, InitializationError::BadParameters(err))) = self.generate( &sig_participants, - receipt_id, + my_request.request_id, presignature, my_request.request, my_request.epsilon, @@ -681,7 +692,7 @@ impl SignatureManager { cfg, ) { failed_presigs.push(presignature); - tracing::warn!(%receipt_id, presig_id, ?err, "failed to start signature generation: trashing presignature"); + tracing::warn!(request_id = ?CryptoHash(my_request.request_id), presig_id, ?err, "failed to start signature generation: trashing presignature"); continue; } } @@ -703,7 +714,7 @@ impl SignatureManager { for mut to_publish in self.signatures.drain(..) { let ToPublish { - receipt_id, + request_id, request, time_added, signature, @@ -717,7 +728,7 @@ impl SignatureManager { &signature.s, request.payload_hash.scalar, ) else { - tracing::error!(%receipt_id, "Failed to generate a recovery ID"); + tracing::error!(request_id = ?CryptoHash(*request_id), "Failed to generate a recovery ID"); continue; }; let response = match rpc_client @@ -733,7 +744,7 @@ impl SignatureManager { { Ok(response) => response, Err(err) => { - tracing::error!(%receipt_id, error = ?err, "Failed to publish the signature"); + tracing::error!(request_id = ?CryptoHash(*request_id), request = ?request, error = ?err, "Failed to publish the signature"); crate::metrics::SIGNATURE_PUBLISH_FAILURES .with_label_values(&[self.my_account_id.as_str()]) .inc(); @@ -748,10 +759,10 @@ impl SignatureManager { match response.json() { Ok(()) => { - tracing::info!(%receipt_id, bi_r = signature.big_r.affine_point.to_base58(), s = ?signature.s, "published signature sucessfully") + tracing::info!(request_id = ?CryptoHash(*request_id), request = ?request, bi_r = signature.big_r.affine_point.to_base58(), s = ?signature.s, "published signature sucessfully") } Err(err) => { - tracing::error!(%receipt_id, bi_r = signature.big_r.affine_point.to_base58(), s = ?signature.s, error = ?err, "smart contract threw error"); + tracing::error!(request_id = ?CryptoHash(*request_id), bi_r = signature.big_r.affine_point.to_base58(), s = ?signature.s, error = ?err, "smart contract threw error"); crate::metrics::SIGNATURE_PUBLISH_RESPONSE_ERRORS .with_label_values(&[self.my_account_id.as_str()]) .inc(); @@ -790,10 +801,10 @@ impl SignatureManager { } } - pub fn refresh_gc(&mut self, id: &ReceiptId) -> bool { + pub fn refresh_gc(&mut self, id: &SignRequestIdentifier) -> bool { let entry = self .completed - .entry(*id) + .entry(id.clone()) .and_modify(|e| *e = Instant::now()); matches!(entry, Entry::Occupied(_)) } diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index 798b4d350..cb9ef8baa 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -350,7 +350,7 @@ impl TripleManager { ))); } - tracing::info!(id, "starting protocol to generate a new triple"); + tracing::debug!(id, "starting protocol to generate a new triple"); let participants: Vec<_> = participants.keys().cloned().collect(); let protocol: TripleProtocol = Box::new(cait_sith::triples::generate_triple::( &participants, diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index f3a2ec6fb..a39a8d6e7 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -131,7 +131,7 @@ pub enum StateView { async fn state(Extension(state): Extension>) -> Result> { tracing::debug!("fetching state"); let latest_block_height = state.indexer.latest_block_height().await; - let is_stable = state.indexer.is_on_track().await; + let is_stable = state.indexer.is_stable().await; let protocol_state = state.protocol_state.read().await; match &*protocol_state { diff --git a/integration-tests/chain-signatures/Cargo.lock b/integration-tests/chain-signatures/Cargo.lock index 67e027189..621a91400 100644 --- a/integration-tests/chain-signatures/Cargo.lock +++ b/integration-tests/chain-signatures/Cargo.lock @@ -3746,6 +3746,7 @@ dependencies = [ "aws-types", "axum", "axum-extra", + "borsh", "cait-sith", "chrono", "clap", diff --git a/integration-tests/chain-signatures/tests/actions/mod.rs b/integration-tests/chain-signatures/tests/actions/mod.rs index fa2236ba4..478259efc 100644 --- a/integration-tests/chain-signatures/tests/actions/mod.rs +++ b/integration-tests/chain-signatures/tests/actions/mod.rs @@ -14,18 +14,20 @@ use k256::elliptic_curve::sec1::FromEncodedPoint; use k256::elliptic_curve::ProjectivePoint; use k256::{AffinePoint, EncodedPoint, Scalar, Secp256k1}; use mpc_contract::errors; +use mpc_contract::errors::SignError; use mpc_contract::primitives::SignRequest; use mpc_contract::primitives::SignatureRequest; use mpc_contract::RunningContractState; use mpc_node::kdf::into_eth_sig; use near_crypto::InMemorySigner; use near_fetch::ops::AsyncTransactionStatus; +use near_fetch::ops::Function; use near_workspaces::types::Gas; use near_workspaces::types::NearToken; use near_workspaces::Account; use rand::Rng; use secp256k1::XOnlyPublicKey; -use wait_for::WaitForError; +use wait_for::{SignatureError, WaitForError}; use std::time::Duration; @@ -71,6 +73,77 @@ pub async fn request_sign( Ok((payload, payload_hashed, account, status)) } +pub async fn request_batch_random_sign( + ctx: &MultichainTestContext<'_>, +) -> anyhow::Result<(Vec<([u8; 32], [u8; 32])>, Account, AsyncTransactionStatus)> { + let worker = &ctx.nodes.ctx().worker; + let account = worker.dev_create_account().await?; + let signer = InMemorySigner { + account_id: account.id().clone(), + public_key: account.secret_key().public_key().to_string().parse()?, + secret_key: account.secret_key().to_string().parse()?, + }; + + let mut payloads: Vec<([u8; 32], [u8; 32])> = vec![]; + let mut tx = ctx.rpc_client.batch(&signer, ctx.contract().id()); + for _ in 0..3 { + let payload: [u8; 32] = rand::thread_rng().gen(); + let payload_hashed = web3::signing::keccak256(&payload); + payloads.push((payload, payload_hashed)); + let request = SignRequest { + payload: payload_hashed, + path: "test".to_string(), + key_version: 0, + }; + let function = Function::new("sign") + .args_json(serde_json::json!({ + "request": request, + })) + .gas(Gas::from_tgas(50)) + .deposit(NearToken::from_yoctonear(1)); + tx = tx.call(function); + } + + let status = tx.transact_async().await?; + tokio::time::sleep(Duration::from_secs(3)).await; + Ok((payloads, account, status)) +} + +pub async fn request_batch_duplicate_sign( + ctx: &MultichainTestContext<'_>, +) -> anyhow::Result<([u8; 32], u32, Account, AsyncTransactionStatus)> { + let worker = &ctx.nodes.ctx().worker; + let account = worker.dev_create_account().await?; + let signer = InMemorySigner { + account_id: account.id().clone(), + public_key: account.secret_key().public_key().to_string().parse()?, + secret_key: account.secret_key().to_string().parse()?, + }; + + let mut tx = ctx.rpc_client.batch(&signer, ctx.contract().id()); + let payload: [u8; 32] = rand::thread_rng().gen(); + let payload_hashed = web3::signing::keccak256(&payload); + let sign_call_cnt = 2; + for _ in 0..sign_call_cnt { + let request = SignRequest { + payload: payload_hashed, + path: "test".to_string(), + key_version: 0, + }; + let function = Function::new("sign") + .args_json(serde_json::json!({ + "request": request, + })) + .gas(Gas::from_tgas(50)) + .deposit(NearToken::from_yoctonear(1)); + tx = tx.call(function); + } + + let status = tx.transact_async().await?; + tokio::time::sleep(Duration::from_secs(3)).await; + Ok((payload_hashed, sign_call_cnt, account, status)) +} + pub async fn assert_signature( account_id: &near_workspaces::AccountId, mpc_pk_bytes: &[u8], @@ -303,6 +376,40 @@ pub async fn clear_toxics() -> anyhow::Result<()> { Ok(()) } +pub async fn batch_random_signature_production( + ctx: &MultichainTestContext<'_>, + state: &RunningContractState, +) -> anyhow::Result<()> { + let (payloads, account, status) = request_batch_random_sign(ctx).await?; + let signatures = wait_for::batch_signature_responded(status).await?; + + let mut mpc_pk_bytes = vec![0x04]; + mpc_pk_bytes.extend_from_slice(&state.public_key.as_bytes()[1..]); + assert_eq!(payloads.len(), signatures.len()); + for i in 0..payloads.len() { + let (_, payload_hash) = payloads.get(i).unwrap(); + let signature = signatures.get(i).unwrap(); + assert_signature(account.id(), &mpc_pk_bytes, *payload_hash, signature).await; + } + + Ok(()) +} + +pub async fn batch_duplicate_signature_production( + ctx: &MultichainTestContext<'_>, + _state: &RunningContractState, +) -> anyhow::Result<()> { + let (_, _, _, status) = request_batch_duplicate_sign(ctx).await?; + let result = wait_for::batch_signature_responded(status).await; + match result { + Err(WaitForError::Signature(SignatureError::Failed(err_msg))) => { + assert!(err_msg.contains(&SignError::RequestCollision.to_string())); + } + _ => panic!("Should have failed with PayloadCollision"), + } + Ok(()) +} + // This test hardcodes the output of the signing process and checks that everything verifies as expected // If you find yourself changing the constants in this test you are likely breaking backwards compatibility #[tokio::test] diff --git a/integration-tests/chain-signatures/tests/actions/wait_for.rs b/integration-tests/chain-signatures/tests/actions/wait_for.rs index ac2e00693..19bfabc2d 100644 --- a/integration-tests/chain-signatures/tests/actions/wait_for.rs +++ b/integration-tests/chain-signatures/tests/actions/wait_for.rs @@ -14,9 +14,13 @@ use mpc_contract::ProtocolContractState; use mpc_contract::RunningContractState; use mpc_node::web::StateView; use near_fetch::ops::AsyncTransactionStatus; +use near_lake_primitives::CryptoHash; use near_primitives::errors::ActionErrorKind; +use near_primitives::views::ExecutionOutcomeWithIdView; +use near_primitives::views::ExecutionStatusView; use near_primitives::views::FinalExecutionStatus; use near_workspaces::Account; +use std::collections::HashMap; use url::Url; pub async fn running_mpc<'a>( @@ -256,6 +260,7 @@ pub enum WaitForError { enum Outcome { Signature(FullSignature), Failed(String), + Signatures(Vec>), } pub async fn signature_responded( @@ -290,6 +295,9 @@ pub async fn signature_responded( match is_tx_ready.retry(&strategy).await? { Outcome::Signature(signature) => Ok(signature), Outcome::Failed(err) => Err(WaitForError::Signature(SignatureError::Failed(err))), + _ => Err(WaitForError::Signature(SignatureError::Failed( + "Should not return more than one signature".to_string(), + ))), } } @@ -366,3 +374,91 @@ pub async fn rogue_message_responded(status: AsyncTransactionStatus) -> anyhow:: Ok(signature.clone()) } + +pub async fn batch_signature_responded( + status: AsyncTransactionStatus, +) -> Result>, WaitForError> { + let is_tx_ready = || async { + let Poll::Ready(outcome) = status + .status() + .await + .map_err(|err| WaitForError::JsonRpc(format!("{err:?}")))? + else { + return Err(WaitForError::Signature(SignatureError::NotYetAvailable)); + }; + + if !outcome.is_success() { + return Err(WaitForError::Signature(SignatureError::Failed(format!( + "status: {:?}", + outcome.status() + )))); + } + + let receipt_outcomes = outcome.details.receipt_outcomes(); + let mut result_receipts: HashMap> = HashMap::new(); + for receipt_outcome in receipt_outcomes { + result_receipts + .entry(receipt_outcome.id) + .or_insert(receipt_outcome.outcome.receipt_ids.clone()); + } + let mut receipt_outcomes_keyed: HashMap = + HashMap::new(); + for receipt_outcome in receipt_outcomes { + receipt_outcomes_keyed + .entry(receipt_outcome.id) + .or_insert(receipt_outcome); + } + + let starting_receipts = &receipt_outcomes.first().unwrap().outcome.receipt_ids; + + let mut signatures: Vec> = vec![]; + for receipt_id in starting_receipts { + if !result_receipts.contains_key(receipt_id) { + break; + } + let sign_receipt_id = receipt_id; + for receipt_id in result_receipts.get(sign_receipt_id).unwrap() { + let receipt_outcome = receipt_outcomes_keyed + .get(receipt_id) + .unwrap() + .outcome + .clone(); + if receipt_outcome + .logs + .contains(&"Signature is ready.".to_string()) + { + match receipt_outcome.status { + ExecutionStatusView::SuccessValue(value) => { + let result: SignatureResponse = serde_json::from_slice(&value) + .map_err(|err| WaitForError::SerdeJson(format!("{err:?}")))?; + let signature = cait_sith::FullSignature:: { + big_r: result.big_r.affine_point, + s: result.s.scalar, + }; + signatures.push(signature); + } + _ => { + return Err(WaitForError::Signature(SignatureError::Failed( + "one signature not done.".to_string(), + ))) + } + } + } + } + } + + Ok(Outcome::Signatures(signatures)) + }; + + let strategy = ConstantBuilder::default() + .with_delay(Duration::from_secs(20)) + .with_max_times(5); + + match is_tx_ready.retry(&strategy).await? { + Outcome::Signature(_) => Err(WaitForError::Signature(SignatureError::Failed( + "Should not return just 1 signature".to_string(), + ))), + Outcome::Failed(err) => Err(WaitForError::Signature(SignatureError::Failed(err))), + Outcome::Signatures(signatures) => Ok(signatures), + } +} diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 99736231d..2f696b0b1 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -564,3 +564,29 @@ async fn test_multichain_update_contract() -> anyhow::Result<()> { }) .await } + +#[test(tokio::test)] +async fn test_batch_random_signature() -> anyhow::Result<()> { + with_multichain_nodes(MultichainConfig::default(), |ctx| { + Box::pin(async move { + let state_0 = wait_for::running_mpc(&ctx, Some(0)).await?; + assert_eq!(state_0.participants.len(), 3); + actions::batch_random_signature_production(&ctx, &state_0).await?; + Ok(()) + }) + }) + .await +} + +#[test(tokio::test)] +async fn test_batch_duplicate_signature() -> anyhow::Result<()> { + with_multichain_nodes(MultichainConfig::default(), |ctx| { + Box::pin(async move { + let state_0 = wait_for::running_mpc(&ctx, Some(0)).await?; + assert_eq!(state_0.participants.len(), 3); + actions::batch_duplicate_signature_production(&ctx, &state_0).await?; + Ok(()) + }) + }) + .await +} From db18173fc23f12339aa40f20d1428eb5c3489970 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 30 Oct 2024 21:14:20 +0200 Subject: [PATCH 48/64] in progress --- chain-signatures/node/src/gcp/mod.rs | 287 +----------------- chain-signatures/node/src/indexer.rs | 73 ++--- .../node/src/storage/app_data_storage.rs | 45 +++ chain-signatures/node/src/storage/mod.rs | 7 +- chain-signatures/node/src/types.rs | 108 ------- integration-tests/chain-signatures/out.txt | 94 ++++++ integration-tests/chain-signatures/src/lib.rs | 1 - 7 files changed, 175 insertions(+), 440 deletions(-) create mode 100644 chain-signatures/node/src/storage/app_data_storage.rs create mode 100644 integration-tests/chain-signatures/out.txt diff --git a/chain-signatures/node/src/gcp/mod.rs b/chain-signatures/node/src/gcp/mod.rs index 5293d9d57..d011c4adc 100644 --- a/chain-signatures/node/src/gcp/mod.rs +++ b/chain-signatures/node/src/gcp/mod.rs @@ -79,16 +79,6 @@ impl SecretManagerService { } } -#[derive(Clone)] -pub struct DatastoreService { - datastore: Datastore>, - project_id: String, - env: String, - is_emulator: bool, -} - -pub type DatastoreResult = std::result::Result; - pub trait Keyable: KeyKind { fn key(&self) -> Key; } @@ -97,268 +87,9 @@ pub trait KeyKind { fn kind() -> String; } -impl DatastoreService { - pub fn is_emulator(&self) -> bool { - self.is_emulator - } - - #[tracing::instrument(level = "debug", skip_all, fields(key = name_key.to_string()))] - pub async fn get( - &self, - name_key: K, - ) -> DatastoreResult { - let request = LookupRequest { - keys: Some(vec![Key { - path: Some(vec![PathElement { - // We can't create multiple datastore databases in GCP, so we have to suffix - // type kinds with env (`dev`, `prod`). - kind: Some(format!("{}-{}", T::kind(), self.env)), - name: Some(name_key.to_string()), - id: None, - }]), - partition_id: None, - }]), - read_options: None, - database_id: Some("".to_string()), - }; - let (_, response) = self - .datastore - .projects() - .lookup(request, &self.project_id) - .doit() - .await - .map_err(|e| { - tracing::error!(%e, "failed to lookup entity in data store"); - e - })?; - match response - .found - .and_then(|mut results| results.pop()) - .and_then(|result| result.entity) - { - Some(found_entity) => Ok(T::from_value(found_entity.into_value())?), - None => Err(DatastoreStorageError::EntityNotFound(name_key.to_string())), - } - } - - #[tracing::instrument(level = "debug", skip_all)] - pub async fn insert(&self, value: T) -> DatastoreResult<()> { - let mut entity = Entity::from_value(value.into_value())?; - let path_element = entity - .key - .as_mut() - .and_then(|k| k.path.as_mut()) - .and_then(|p| p.first_mut()); - if let Some(path_element) = path_element { - // We can't create multiple datastore databases in GCP, so we have to suffix - // type kinds with env (`dev`, `prod`). - path_element.kind = Some(format!("{}-{}", T::kind(), self.env)) - } - - let request = CommitRequest { - database_id: Some("".to_string()), - mode: Some(String::from("NON_TRANSACTIONAL")), - mutations: Some(vec![Mutation { - insert: Some(entity), - delete: None, - update: None, - base_version: None, - upsert: None, - update_time: None, - }]), - single_use_transaction: None, - transaction: None, - }; - let (_, _) = self - .datastore - .projects() - .commit(request, &self.project_id) - .doit() - .await - .map_err(|e| { - tracing::error!(%e, "failed to insert entity to data store"); - e - })?; - Ok(()) - } - - #[tracing::instrument(level = "debug", skip_all)] - pub async fn update(&self, value: T) -> DatastoreResult<()> { - let mut entity = Entity::from_value(value.into_value())?; - let path_element = entity - .key - .as_mut() - .and_then(|k| k.path.as_mut()) - .and_then(|p| p.first_mut()); - if let Some(path_element) = path_element { - // We can't create multiple datastore databases in GCP, so we have to suffix - // type kinds with env (`dev`, `prod`). - path_element.kind = Some(format!("{}-{}", T::kind(), self.env)) - } - - let request = CommitRequest { - database_id: Some("".to_string()), - mode: Some(String::from("NON_TRANSACTIONAL")), - mutations: Some(vec![Mutation { - insert: None, - delete: None, - update: Some(entity), - base_version: None, - upsert: None, - update_time: None, - }]), - single_use_transaction: None, - transaction: None, - }; - let (_, _) = self - .datastore - .projects() - .commit(request, &self.project_id) - .doit() - .await - .map_err(|e| { - tracing::error!(%e, "failed to update entity in data store"); - e - })?; - - Ok(()) - } - - pub async fn upsert(&self, value: T) -> DatastoreResult<()> { - let mut entity = Entity::from_value(value.into_value())?; - let path_element = entity - .key - .as_mut() - .and_then(|k| k.path.as_mut()) - .and_then(|p| p.first_mut()); - if let Some(path_element) = path_element { - // We can't create multiple datastore databases in GCP, so we have to suffix - // type kinds with env (`dev`, `prod`). - path_element.kind = Some(format!("{}-{}", T::kind(), self.env)) - } - - let request = CommitRequest { - database_id: Some("".to_string()), - mode: Some(String::from("NON_TRANSACTIONAL")), - mutations: Some(vec![Mutation { - insert: None, - delete: None, - update: None, - base_version: None, - upsert: Some(entity), - update_time: None, - }]), - single_use_transaction: None, - transaction: None, - }; - - let (_, _) = self - .datastore - .projects() - .commit(request, &self.project_id) - .doit() - .await - .map_err(|e| { - tracing::error!(%e, "failed to upsert entity in data store"); - e - })?; - - Ok(()) - } - - pub async fn fetch_entities( - &self, - filter: Option, - ) -> DatastoreResult> { - let kind: String = format!("{}-{}", T::kind(), self.env); - let req = RunQueryRequest { - database_id: Some("".to_string()), - partition_id: Default::default(), - read_options: Default::default(), - query: Some(Query { - projection: None, - kind: Some(vec![KindExpression { name: Some(kind) }]), - filter, - order: None, - distinct_on: Some(vec![]), - start_cursor: None, - end_cursor: None, - offset: None, - limit: None, - }), - gql_query: None, - }; - let (_hyper_resp, query_resp) = self - .datastore - .projects() - .run_query(req, &self.project_id) - .doit() - .await - .map_err(|e| { - tracing::error!(%e, "failed to fetch entities from data store"); - e - })?; - let batch = query_resp.batch.ok_or_else(|| { - DatastoreStorageError::FetchEntitiesError( - "Could not retrieve batch while fetching entities".to_string(), - ) - })?; - - // NOTE: if entity_results is None, we return an empty Vec since the fetch query - // could not find any entities in the DB. - Ok(batch.entity_results.unwrap_or_default()) - } - - #[tracing::instrument(level = "debug", skip_all)] - pub async fn delete(&self, keyable: T) -> DatastoreResult<()> { - self.delete_many(&[keyable]).await - } - - #[tracing::instrument(level = "debug", skip_all)] - pub async fn delete_many(&self, keyables: &[T]) -> DatastoreResult<()> { - let mutations = keyables - .iter() - .map(|keyable| { - let mut key = keyable.key(); - if let Some(path) = key.path.as_mut().and_then(|p| p.first_mut()) { - path.kind = Some(format!("{}-{}", T::kind(), self.env)); - } - Mutation { - insert: None, - delete: Some(key), - update: None, - base_version: None, - upsert: None, - update_time: None, - } - }) - .collect::>(); - - let request = CommitRequest { - database_id: Some("".to_string()), - mode: Some(String::from("NON_TRANSACTIONAL")), - mutations: Some(mutations), - single_use_transaction: None, - transaction: None, - }; - let (_, _) = self - .datastore - .projects() - .commit(request, &self.project_id) - .doit() - .await - .map_err(|e| { - tracing::error!(%e, "failed to delete entities in data store"); - e - })?; - Ok(()) - } -} - #[derive(Clone)] pub struct GcpService { pub project_id: String, - pub datastore: DatastoreService, pub secret_manager: SecretManagerService, pub account_id: AccountId, } @@ -370,7 +101,8 @@ impl GcpService { ) -> anyhow::Result { let project_id = storage_options.gcp_project_id.clone(); let secret_manager; - let datastore = if let Some(gcp_datastore_url) = storage_options.gcp_datastore_url.clone() { + if storage_options.env == "local-test" { + // TODO: check string let client = hyper::Client::builder().build( hyper_rustls::HttpsConnectorBuilder::new() .with_native_roots() @@ -379,15 +111,11 @@ impl GcpService { .enable_http2() .build(), ); - // Assuming custom GCP URL points to an emulator, so the token does not matter + // Assuming we are in a test environment, token does not matter let authenticator = AccessTokenAuthenticator::builder("TOKEN".to_string()) .build() .await?; secret_manager = SecretManager::new(client.clone(), authenticator.clone()); - let mut datastore = Datastore::new(client, authenticator); - datastore.base_url(gcp_datastore_url.clone()); - datastore.root_url(gcp_datastore_url); - datastore } else { // restring client to use https in production let client = hyper::Client::builder().build( @@ -406,17 +134,10 @@ impl GcpService { ApplicationDefaultCredentialsTypes::ServiceAccount(auth) => auth.build().await?, }; secret_manager = SecretManager::new(client.clone(), authenticator.clone()); - Datastore::new(client, authenticator) - }; + } Ok(Self { account_id: account_id.clone(), - datastore: DatastoreService { - datastore, - project_id: project_id.clone(), - env: storage_options.env.clone(), - is_emulator: storage_options.gcp_datastore_url.is_some(), - }, secret_manager: SecretManagerService { secret_manager, project_id: project_id.clone(), diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index a744b69d5..1618a12b5 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -1,7 +1,6 @@ -use crate::gcp::error::DatastoreStorageError; use crate::gcp::GcpService; use crate::protocol::{SignQueue, SignRequest}; -use crate::types::LatestBlockHeight; +use crate::storage::app_data_storage::AppDataRedisStorage; use crypto_shared::{derive_epsilon, ScalarExt}; use k256::Scalar; use near_account_id::AccountId; @@ -83,6 +82,7 @@ struct SignArguments { request: UnvalidatedContractSignRequest, } +// TODO: why do we need this type? /// What is recieved when sign is called #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] struct UnvalidatedContractSignRequest { @@ -99,9 +99,8 @@ pub struct ContractSignRequest { pub key_version: u32, } -#[derive(Debug, Clone)] pub struct Indexer { - latest_block_height: Arc>, + storage: AppDataRedisStorage, last_updated_timestamp: Arc>, latest_block_timestamp_nanosec: Arc>>, running_threshold: Duration, @@ -109,13 +108,10 @@ pub struct Indexer { } impl Indexer { - fn new(latest_block_height: LatestBlockHeight, options: &Options) -> Self { - tracing::info!( - "creating new indexer, latest block height: {}", - latest_block_height.block_height - ); + async fn new(storage: AppDataRedisStorage, options: &Options) -> Self { + // TODO: log latest block height Self { - latest_block_height: Arc::new(RwLock::new(latest_block_height)), + storage, last_updated_timestamp: Arc::new(RwLock::new(Instant::now())), latest_block_timestamp_nanosec: Arc::new(RwLock::new(None)), running_threshold: Duration::from_secs(options.running_threshold), @@ -123,9 +119,22 @@ impl Indexer { } } - /// Get the latest block height from the chain. + /// Get the latest processed block height pub async fn latest_block_height(&self) -> BlockHeight { - self.latest_block_height.read().await.block_height + let height = match self.storage.get_last_processed_block().await { + Ok(Some(height)) => height, + Ok(None) => { + tracing::warn!("block height was not set"); + return 0; + } + Err(e) => { + // TODO: make it error in triples and presignatures + tracing::error!(?e, "failed to get block height"); + return 0; + } + }; + tracing::debug!(height, "latest block height"); + height } /// Check whether the indexer is on track with the latest block height from the chain. @@ -155,25 +164,24 @@ impl Indexer { &self, block_height: BlockHeight, block_timestamp_nanosec: u64, - gcp: &GcpService, - ) -> Result<(), DatastoreStorageError> { + ) { tracing::debug!(block_height, "update_block_height_and_timestamp"); *self.last_updated_timestamp.write().await = Instant::now(); *self.latest_block_timestamp_nanosec.write().await = Some(block_timestamp_nanosec); - self.latest_block_height - .write() - .await - .set(block_height) - .store(gcp) + self.storage + .set_last_processed_block(block_height) .await + .map_err(|e| { + tracing::error!(?e, "failed to set last processed block"); + }); } } +// TODO: why do we need this type? Why not use the `Indexer` type directly? #[derive(Clone, LakeContext)] struct Context { mpc_contract_id: AccountId, node_account_id: AccountId, - gcp_service: GcpService, queue: Arc>, indexer: Indexer, } @@ -263,12 +271,8 @@ async fn handle_block( } ctx.indexer - .update_block_height_and_timestamp( - block.block_height(), - block.header().timestamp_nanosec(), - &ctx.gcp_service, - ) - .await?; + .update_block_height_and_timestamp(block.block_height(), block.header().timestamp_nanosec()) + .await; crate::metrics::LATEST_BLOCK_HEIGHT .with_label_values(&[ctx.gcp_service.account_id.as_str()]) @@ -302,7 +306,6 @@ pub fn run( mpc_contract_id: &AccountId, node_account_id: &AccountId, queue: &Arc>, - gcp_service: &crate::gcp::GcpService, rt: &tokio::runtime::Runtime, ) -> anyhow::Result<(JoinHandle>, Indexer)> { tracing::info!( @@ -314,24 +317,10 @@ pub fn run( "starting indexer" ); - let latest_block_height = rt.block_on(async { - match LatestBlockHeight::fetch(gcp_service).await { - Ok(latest) => latest, - Err(err) => { - tracing::warn!(%err, "failed to fetch latest block height; using start_block_height={} instead", options.start_block_height); - LatestBlockHeight { - account_id: node_account_id.clone(), - block_height: options.start_block_height, - } - } - } - }); - - let indexer = Indexer::new(latest_block_height, options); + let indexer = Indexer::new(options).await; let context = Context { mpc_contract_id: mpc_contract_id.clone(), node_account_id: node_account_id.clone(), - gcp_service: gcp_service.clone(), queue: queue.clone(), indexer: indexer.clone(), }; diff --git a/chain-signatures/node/src/storage/app_data_storage.rs b/chain-signatures/node/src/storage/app_data_storage.rs new file mode 100644 index 000000000..a0d340a76 --- /dev/null +++ b/chain-signatures/node/src/storage/app_data_storage.rs @@ -0,0 +1,45 @@ +use anyhow::Ok; +use deadpool_redis::Pool; +use near_primitives::types::BlockHeight; +use near_sdk::AccountId; +use redis::AsyncCommands; + +type AppDataResult = std::result::Result; + +const APP_DATA_PREFIX: &str = "app_data"; +const APP_DATA_STORAGE_VERSION: &str = "v1"; + +pub fn init(pool: &Pool, node_account_id: &AccountId) -> AppDataRedisStorage { + AppDataRedisStorage { + redis_pool: pool.clone(), + node_account_id: node_account_id.clone(), + } +} + +#[derive(Clone)] +pub struct AppDataRedisStorage { + redis_pool: Pool, + node_account_id: AccountId, +} + +impl AppDataRedisStorage { + pub async fn set_last_processed_block(&self, height: BlockHeight) -> AppDataResult<()> { + let mut conn = self.redis_pool.get().await?; + conn.set::<&str, BlockHeight, ()>(&self.last_block_key(), height) + .await?; + Ok(()) + } + + pub async fn get_last_processed_block(&self) -> AppDataResult> { + let mut conn = self.redis_pool.get().await?; + let result: Option = conn.get(self.last_block_key()).await?; + Ok(result) + } + + fn last_block_key(&self) -> String { + format!( + "{}:{}:{}:last_block", + APP_DATA_PREFIX, APP_DATA_STORAGE_VERSION, self.node_account_id + ) + } +} diff --git a/chain-signatures/node/src/storage/mod.rs b/chain-signatures/node/src/storage/mod.rs index 550fe2378..c5230121c 100644 --- a/chain-signatures/node/src/storage/mod.rs +++ b/chain-signatures/node/src/storage/mod.rs @@ -1,3 +1,4 @@ +pub mod app_data_storage; pub mod presignature_storage; pub mod secret_storage; pub mod triple_storage; @@ -16,9 +17,6 @@ pub struct Options { #[clap(long, env("MPC_SK_SHARE_SECRET_ID"), requires_all=["gcp_project_id"])] pub sk_share_secret_id: Option, /// Mostly for integration tests. - /// GCP Datastore URL that will be used to load/store the node's triples and presignatures. - #[arg(long, env("MPC_GCP_DATASTORE_URL"))] - pub gcp_datastore_url: Option, #[arg(long, env("MPC_SK_SHARE_LOCAL_PATH"))] pub sk_share_local_path: Option, #[arg(long, env("MPC_REDIS_URL"))] @@ -36,9 +34,6 @@ impl Options { if let Some(sk_share_secret_id) = self.sk_share_secret_id { opts.extend(vec!["--sk-share-secret-id".to_string(), sk_share_secret_id]); } - if let Some(gcp_datastore_url) = self.gcp_datastore_url { - opts.extend(vec!["--gcp-datastore-url".to_string(), gcp_datastore_url]); - } if let Some(sk_share_local_path) = self.sk_share_local_path { opts.extend(vec![ "--sk-share-local-path".to_string(), diff --git a/chain-signatures/node/src/types.rs b/chain-signatures/node/src/types.rs index 704bba090..f190c34ab 100644 --- a/chain-signatures/node/src/types.rs +++ b/chain-signatures/node/src/types.rs @@ -8,13 +8,8 @@ use crypto_shared::PublicKey; use k256::{elliptic_curve::CurveArithmetic, Secp256k1}; use tokio::sync::{RwLock, RwLockWriteGuard}; -use crate::gcp::error::ConvertError; -use crate::gcp::value::{FromValue, IntoValue, Value}; -use crate::gcp::{DatastoreResult, GcpService, KeyKind}; use crate::protocol::contract::ResharingContractState; -use near_account_id::AccountId; - pub type SecretKeyShare = ::Scalar; pub type TripleProtocol = Box> + Send + Sync>; @@ -133,106 +128,3 @@ impl ReshareProtocol { self.protocol.write().await } } - -#[derive(Clone, Debug)] -pub struct LatestBlockHeight { - pub account_id: AccountId, - pub block_height: near_primitives::types::BlockHeight, -} - -impl LatestBlockHeight { - pub async fn fetch(gcp: &GcpService) -> DatastoreResult { - gcp.datastore - .get(format!("{}/latest-block-height", gcp.account_id)) - .await - } - - pub fn set(&mut self, block_height: near_primitives::types::BlockHeight) -> &mut Self { - self.block_height = block_height; - self - } - - pub async fn store(&self, gcp: &GcpService) -> DatastoreResult<()> { - gcp.datastore.upsert(self).await - } -} - -impl IntoValue for LatestBlockHeight { - fn into_value(self) -> Value { - (&self).into_value() - } -} - -impl IntoValue for &LatestBlockHeight { - fn into_value(self) -> Value { - let properties = { - let mut properties = std::collections::HashMap::new(); - properties.insert( - "account_id".to_string(), - Value::StringValue(self.account_id.to_string()), - ); - properties.insert( - "block_height".to_string(), - Value::IntegerValue(self.block_height as i64), - ); - properties - }; - Value::EntityValue { - key: google_datastore1::api::Key { - path: Some(vec![google_datastore1::api::PathElement { - kind: Some(LatestBlockHeight::kind()), - name: Some(format!("{}/latest-block-height", self.account_id)), - id: None, - }]), - partition_id: None, - }, - properties, - } - } -} - -impl FromValue for LatestBlockHeight { - fn from_value(value: Value) -> Result { - match value { - Value::EntityValue { - key: _, - mut properties, - } => { - let account_id = properties - .remove("account_id") - .ok_or_else(|| ConvertError::MissingProperty("account_id".to_string()))?; - let account_id = String::from_value(account_id)?.parse().map_err(|err| { - ConvertError::MalformedProperty(format!( - "LatestBlockHeight failed to parse account_id: {err:?}", - )) - })?; - - let block_height = properties - .remove("block_height") - .ok_or_else(|| ConvertError::MissingProperty("block_height".to_string()))?; - let block_height = i64::from_value(block_height)? as u64; - - Ok(LatestBlockHeight { - account_id, - block_height, - }) - } - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("integer"), - got: String::from(value.type_name()), - }), - } - } -} - -impl KeyKind for LatestBlockHeight { - fn kind() -> String { - "LatestBlockHeight".to_string() - } -} - -impl KeyKind for &LatestBlockHeight { - fn kind() -> String { - "LatestBlockHeight".to_string() - } -} diff --git a/integration-tests/chain-signatures/out.txt b/integration-tests/chain-signatures/out.txt new file mode 100644 index 000000000..2e5b5e798 --- /dev/null +++ b/integration-tests/chain-signatures/out.txt @@ -0,0 +1,94 @@ + Compiling mpc-node v1.0.0-rc.5 (/Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node) +error[E0432]: unresolved import `crate::gcp::DatastoreResult` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/types.rs:13:18 + | +13 | use crate::gcp::{DatastoreResult, GcpService, KeyKind}; + | ^^^^^^^^^^^^^^^ no `DatastoreResult` in `gcp` + +warning: unused imports: `FromValue` and `IntoValue` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:4:19 + | +4 | use self::value::{FromValue, IntoValue}; + | ^^^^^^^^^ ^^^^^^^^^ + | + = note: `#[warn(unused_imports)]` on by default + +warning: unused import: `crate::gcp::error::DatastoreStorageError` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:5:5 + | +5 | use crate::gcp::error::DatastoreStorageError; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused import: `google_datastore1::api::Filter` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:8:5 + | +8 | use google_datastore1::api::Filter; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: unused imports: `CommitRequest`, `EntityResult`, `Entity`, `KindExpression`, `LookupRequest`, `Mutation`, `PathElement`, `Query`, and `RunQueryRequest` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:10:5 + | +10 | CommitRequest, Entity, EntityResult, Key, KindExpression, LookupRequest, Mutation, PathElement, + | ^^^^^^^^^^^^^ ^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^ +11 | Query, RunQueryRequest, + | ^^^^^ ^^^^^^^^^^^^^^^ + +warning: unused imports: `FromRedisValue`, `RedisWrite`, and `ToRedisArgs` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/storage/app_data_storage.rs:4:28 + | +4 | use redis::{AsyncCommands, FromRedisValue, RedisWrite, ToRedisArgs}; + | ^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^ + +warning: unused variable: `datastore` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:104:13 + | +104 | let datastore = if let Some(gcp_datastore_url) = storage_options.gcp_datastore_url.clone() { + | ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_datastore` + | + = note: `#[warn(unused_variables)]` on by default + +error[E0599]: no method named `presig_key` found for reference `&AppDataRedisStorage` in the current scope + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/storage/app_data_storage.rs:28:23 + | +28 | &self.presig_key(), + | ^^^^^^^^^^ method not found in `&AppDataRedisStorage` + +error[E0599]: no method named `presig_key` found for reference `&AppDataRedisStorage` in the current scope + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/storage/app_data_storage.rs:38:65 + | +38 | let result: Option = connection.hget(self.presig_key(), id).await?; + | ^^^^^^^^^^ method not found in `&AppDataRedisStorage` + +error[E0308]: mismatched types + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/storage/app_data_storage.rs:36:110 + | +36 | pub async fn get_last_processed_block(&self, id: &PresignatureId) -> AppDataResult> { + | ______________________________________________________________________________________________________________^ +37 | | let mut connection = self.redis_pool.get().await?; +38 | | let result: Option = connection.hget(self.presig_key(), id).await?; +39 | | } + | |_____^ expected `Result, Error>`, found `()` + | + = note: expected enum `std::result::Result, anyhow::Error>` + found unit type `()` + +error[E0609]: no field `datastore` on type `&GcpService` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/types.rs:145:13 + | +145 | gcp.datastore + | ^^^^^^^^^ unknown field + | + = note: available fields are: `project_id`, `secret_manager`, `account_id` + +error[E0609]: no field `datastore` on type `&GcpService` + --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/types.rs:156:13 + | +156 | gcp.datastore.upsert(self).await + | ^^^^^^^^^ unknown field + | + = note: available fields are: `project_id`, `secret_manager`, `account_id` + +Some errors have detailed explanations: E0308, E0432, E0599, E0609. +For more information about an error, try `rustc --explain E0308`. +warning: `mpc-node` (lib) generated 6 warnings +error: could not compile `mpc-node` (lib) due to 6 previous errors; 6 warnings emitted diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 54f470d4b..37d66c01d 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -243,7 +243,6 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> env: "local-test".to_string(), gcp_project_id: "multichain-integration".to_string(), sk_share_secret_id: None, - gcp_datastore_url: Some(datastore.local_address.clone()), sk_share_local_path: Some(sk_share_local_path), redis_url, }; From f82cb380a9543f966973ffc229202258014327d4 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 1 Nov 2024 12:59:42 +0200 Subject: [PATCH 49/64] remove test output --- integration-tests/chain-signatures/out.txt | 94 ---------------------- 1 file changed, 94 deletions(-) delete mode 100644 integration-tests/chain-signatures/out.txt diff --git a/integration-tests/chain-signatures/out.txt b/integration-tests/chain-signatures/out.txt deleted file mode 100644 index 2e5b5e798..000000000 --- a/integration-tests/chain-signatures/out.txt +++ /dev/null @@ -1,94 +0,0 @@ - Compiling mpc-node v1.0.0-rc.5 (/Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node) -error[E0432]: unresolved import `crate::gcp::DatastoreResult` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/types.rs:13:18 - | -13 | use crate::gcp::{DatastoreResult, GcpService, KeyKind}; - | ^^^^^^^^^^^^^^^ no `DatastoreResult` in `gcp` - -warning: unused imports: `FromValue` and `IntoValue` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:4:19 - | -4 | use self::value::{FromValue, IntoValue}; - | ^^^^^^^^^ ^^^^^^^^^ - | - = note: `#[warn(unused_imports)]` on by default - -warning: unused import: `crate::gcp::error::DatastoreStorageError` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:5:5 - | -5 | use crate::gcp::error::DatastoreStorageError; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused import: `google_datastore1::api::Filter` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:8:5 - | -8 | use google_datastore1::api::Filter; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: unused imports: `CommitRequest`, `EntityResult`, `Entity`, `KindExpression`, `LookupRequest`, `Mutation`, `PathElement`, `Query`, and `RunQueryRequest` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:10:5 - | -10 | CommitRequest, Entity, EntityResult, Key, KindExpression, LookupRequest, Mutation, PathElement, - | ^^^^^^^^^^^^^ ^^^^^^ ^^^^^^^^^^^^ ^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^ -11 | Query, RunQueryRequest, - | ^^^^^ ^^^^^^^^^^^^^^^ - -warning: unused imports: `FromRedisValue`, `RedisWrite`, and `ToRedisArgs` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/storage/app_data_storage.rs:4:28 - | -4 | use redis::{AsyncCommands, FromRedisValue, RedisWrite, ToRedisArgs}; - | ^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^ - -warning: unused variable: `datastore` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/gcp/mod.rs:104:13 - | -104 | let datastore = if let Some(gcp_datastore_url) = storage_options.gcp_datastore_url.clone() { - | ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_datastore` - | - = note: `#[warn(unused_variables)]` on by default - -error[E0599]: no method named `presig_key` found for reference `&AppDataRedisStorage` in the current scope - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/storage/app_data_storage.rs:28:23 - | -28 | &self.presig_key(), - | ^^^^^^^^^^ method not found in `&AppDataRedisStorage` - -error[E0599]: no method named `presig_key` found for reference `&AppDataRedisStorage` in the current scope - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/storage/app_data_storage.rs:38:65 - | -38 | let result: Option = connection.hget(self.presig_key(), id).await?; - | ^^^^^^^^^^ method not found in `&AppDataRedisStorage` - -error[E0308]: mismatched types - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/storage/app_data_storage.rs:36:110 - | -36 | pub async fn get_last_processed_block(&self, id: &PresignatureId) -> AppDataResult> { - | ______________________________________________________________________________________________________________^ -37 | | let mut connection = self.redis_pool.get().await?; -38 | | let result: Option = connection.hget(self.presig_key(), id).await?; -39 | | } - | |_____^ expected `Result, Error>`, found `()` - | - = note: expected enum `std::result::Result, anyhow::Error>` - found unit type `()` - -error[E0609]: no field `datastore` on type `&GcpService` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/types.rs:145:13 - | -145 | gcp.datastore - | ^^^^^^^^^ unknown field - | - = note: available fields are: `project_id`, `secret_manager`, `account_id` - -error[E0609]: no field `datastore` on type `&GcpService` - --> /Users/serhii/Projects/NEAR/mpc-recovery/chain-signatures/node/src/types.rs:156:13 - | -156 | gcp.datastore.upsert(self).await - | ^^^^^^^^^ unknown field - | - = note: available fields are: `project_id`, `secret_manager`, `account_id` - -Some errors have detailed explanations: E0308, E0432, E0599, E0609. -For more information about an error, try `rustc --explain E0308`. -warning: `mpc-node` (lib) generated 6 warnings -error: could not compile `mpc-node` (lib) due to 6 previous errors; 6 warnings emitted From d7314e3c306a79f5c10fa21b0e1cfa4cca2e55b6 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 7 Nov 2024 14:43:48 +0200 Subject: [PATCH 50/64] redis app storage removed --- chain-signatures/node/src/cli.rs | 1 - chain-signatures/node/src/gcp/error.rs | 22 --------- chain-signatures/node/src/gcp/mod.rs | 11 +---- chain-signatures/node/src/indexer.rs | 38 ++++------------ .../node/src/protocol/consensus.rs | 9 ---- .../node/src/storage/app_data_storage.rs | 45 ------------------- chain-signatures/node/src/storage/mod.rs | 1 - 7 files changed, 11 insertions(+), 116 deletions(-) delete mode 100644 chain-signatures/node/src/storage/app_data_storage.rs diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 83131e2df..3d7710f79 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -200,7 +200,6 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { &mpc_contract_id, &account_id, &sign_queue, - &gcp_service, &rt, )?; diff --git a/chain-signatures/node/src/gcp/error.rs b/chain-signatures/node/src/gcp/error.rs index 8818a07f3..42463611d 100644 --- a/chain-signatures/node/src/gcp/error.rs +++ b/chain-signatures/node/src/gcp/error.rs @@ -19,25 +19,3 @@ pub enum SecretStorageError { #[error("(de)serialization error: {0}")] SerdeError(#[from] serde_json::Error), } - -#[derive(thiserror::Error, Debug)] -pub enum DatastoreStorageError { - #[error("GCP error: {0}")] - GcpError(#[from] google_datastore1::Error), - #[error("IO error: {0}")] - IoError(#[from] std::io::Error), - #[error("(de)serialization error: {0}")] - SerdeError(#[from] serde_json::Error), - #[error("datastore value conversion error: {0}")] - ConvertError(ConvertError), - #[error("fetch_entities error: `{0}`")] - FetchEntitiesError(String), - #[error("could not find entity: {0}")] - EntityNotFound(String), -} - -impl From for DatastoreStorageError { - fn from(err: ConvertError) -> Self { - DatastoreStorageError::ConvertError(err) - } -} diff --git a/chain-signatures/node/src/gcp/mod.rs b/chain-signatures/node/src/gcp/mod.rs index d011c4adc..17d791f40 100644 --- a/chain-signatures/node/src/gcp/mod.rs +++ b/chain-signatures/node/src/gcp/mod.rs @@ -1,17 +1,10 @@ pub mod error; pub mod value; -use self::value::{FromValue, IntoValue}; -use crate::gcp::error::DatastoreStorageError; use crate::storage; -use google_datastore1::api::Filter; -use google_datastore1::api::{ - CommitRequest, Entity, EntityResult, Key, KindExpression, LookupRequest, Mutation, PathElement, - Query, RunQueryRequest, -}; +use google_datastore1::api::Key; use google_datastore1::oauth2::AccessTokenAuthenticator; -use google_datastore1::Datastore; use google_secretmanager1::api::{AddSecretVersionRequest, SecretPayload}; use google_secretmanager1::oauth2::authenticator::ApplicationDefaultCredentialsTypes; use google_secretmanager1::oauth2::{ @@ -101,8 +94,8 @@ impl GcpService { ) -> anyhow::Result { let project_id = storage_options.gcp_project_id.clone(); let secret_manager; + // TODO: check string if storage_options.env == "local-test" { - // TODO: check string let client = hyper::Client::builder().build( hyper_rustls::HttpsConnectorBuilder::new() .with_native_roots() diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index 1618a12b5..826a07f43 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -1,6 +1,4 @@ -use crate::gcp::GcpService; use crate::protocol::{SignQueue, SignRequest}; -use crate::storage::app_data_storage::AppDataRedisStorage; use crypto_shared::{derive_epsilon, ScalarExt}; use k256::Scalar; use near_account_id::AccountId; @@ -99,8 +97,8 @@ pub struct ContractSignRequest { pub key_version: u32, } +#[derive(Debug, Clone)] pub struct Indexer { - storage: AppDataRedisStorage, last_updated_timestamp: Arc>, latest_block_timestamp_nanosec: Arc>>, running_threshold: Duration, @@ -108,10 +106,9 @@ pub struct Indexer { } impl Indexer { - async fn new(storage: AppDataRedisStorage, options: &Options) -> Self { + fn new(options: &Options) -> Self { // TODO: log latest block height Self { - storage, last_updated_timestamp: Arc::new(RwLock::new(Instant::now())), latest_block_timestamp_nanosec: Arc::new(RwLock::new(None)), running_threshold: Duration::from_secs(options.running_threshold), @@ -121,20 +118,8 @@ impl Indexer { /// Get the latest processed block height pub async fn latest_block_height(&self) -> BlockHeight { - let height = match self.storage.get_last_processed_block().await { - Ok(Some(height)) => height, - Ok(None) => { - tracing::warn!("block height was not set"); - return 0; - } - Err(e) => { - // TODO: make it error in triples and presignatures - tracing::error!(?e, "failed to get block height"); - return 0; - } - }; - tracing::debug!(height, "latest block height"); - height + // TODO: fetch latest block using RPC + 0 as BlockHeight } /// Check whether the indexer is on track with the latest block height from the chain. @@ -168,12 +153,7 @@ impl Indexer { tracing::debug!(block_height, "update_block_height_and_timestamp"); *self.last_updated_timestamp.write().await = Instant::now(); *self.latest_block_timestamp_nanosec.write().await = Some(block_timestamp_nanosec); - self.storage - .set_last_processed_block(block_height) - .await - .map_err(|e| { - tracing::error!(?e, "failed to set last processed block"); - }); + // TODO: update the block height in the indexer (add in memoru variable?) } } @@ -275,7 +255,7 @@ async fn handle_block( .await; crate::metrics::LATEST_BLOCK_HEIGHT - .with_label_values(&[ctx.gcp_service.account_id.as_str()]) + .with_label_values(&[ctx.node_account_id.as_str()]) .set(block.block_height() as i64); // Add the requests after going through the whole block to avoid partial processing if indexer fails somewhere. @@ -284,7 +264,7 @@ async fn handle_block( for request in pending_requests { queue.add(request); crate::metrics::NUM_SIGN_REQUESTS - .with_label_values(&[ctx.gcp_service.account_id.as_str()]) + .with_label_values(&[ctx.node_account_id.as_str()]) .inc(); } drop(queue); @@ -306,7 +286,7 @@ pub fn run( mpc_contract_id: &AccountId, node_account_id: &AccountId, queue: &Arc>, - rt: &tokio::runtime::Runtime, + _rt: &tokio::runtime::Runtime, ) -> anyhow::Result<(JoinHandle>, Indexer)> { tracing::info!( s3_bucket = options.s3_bucket, @@ -317,7 +297,7 @@ pub fn run( "starting indexer" ); - let indexer = Indexer::new(options).await; + let indexer = Indexer::new(options); let context = Context { mpc_contract_id: mpc_contract_id.clone(), node_account_id: node_account_id.clone(), diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index d50fd0317..40f30e4a0 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -4,7 +4,6 @@ use super::state::{ WaitingForConsensusState, }; use super::{Config, SignQueue}; -use crate::gcp::error::DatastoreStorageError; use crate::gcp::error::SecretStorageError; use crate::http_client::MessageQueue; use crate::protocol::contract::primitives::Participants; @@ -68,8 +67,6 @@ pub enum ConsensusError { CaitSithInitializationError(#[from] InitializationError), #[error("secret storage error: {0}")] SecretStorageError(SecretStorageError), - #[error("datastore storage error: {0}")] - DatastoreStorageError(DatastoreStorageError), } impl From for ConsensusError { @@ -78,12 +75,6 @@ impl From for ConsensusError { } } -impl From for ConsensusError { - fn from(err: DatastoreStorageError) -> Self { - ConsensusError::DatastoreStorageError(err) - } -} - #[async_trait] pub trait ConsensusProtocol { async fn advance( diff --git a/chain-signatures/node/src/storage/app_data_storage.rs b/chain-signatures/node/src/storage/app_data_storage.rs deleted file mode 100644 index a0d340a76..000000000 --- a/chain-signatures/node/src/storage/app_data_storage.rs +++ /dev/null @@ -1,45 +0,0 @@ -use anyhow::Ok; -use deadpool_redis::Pool; -use near_primitives::types::BlockHeight; -use near_sdk::AccountId; -use redis::AsyncCommands; - -type AppDataResult = std::result::Result; - -const APP_DATA_PREFIX: &str = "app_data"; -const APP_DATA_STORAGE_VERSION: &str = "v1"; - -pub fn init(pool: &Pool, node_account_id: &AccountId) -> AppDataRedisStorage { - AppDataRedisStorage { - redis_pool: pool.clone(), - node_account_id: node_account_id.clone(), - } -} - -#[derive(Clone)] -pub struct AppDataRedisStorage { - redis_pool: Pool, - node_account_id: AccountId, -} - -impl AppDataRedisStorage { - pub async fn set_last_processed_block(&self, height: BlockHeight) -> AppDataResult<()> { - let mut conn = self.redis_pool.get().await?; - conn.set::<&str, BlockHeight, ()>(&self.last_block_key(), height) - .await?; - Ok(()) - } - - pub async fn get_last_processed_block(&self) -> AppDataResult> { - let mut conn = self.redis_pool.get().await?; - let result: Option = conn.get(self.last_block_key()).await?; - Ok(result) - } - - fn last_block_key(&self) -> String { - format!( - "{}:{}:{}:last_block", - APP_DATA_PREFIX, APP_DATA_STORAGE_VERSION, self.node_account_id - ) - } -} diff --git a/chain-signatures/node/src/storage/mod.rs b/chain-signatures/node/src/storage/mod.rs index c5230121c..d4bb21bab 100644 --- a/chain-signatures/node/src/storage/mod.rs +++ b/chain-signatures/node/src/storage/mod.rs @@ -1,4 +1,3 @@ -pub mod app_data_storage; pub mod presignature_storage; pub mod secret_storage; pub mod triple_storage; From b2335191beb6546c187fa0ac7985edbbd93bee5d Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 7 Nov 2024 15:02:23 +0200 Subject: [PATCH 51/64] remove starting block parameter --- chain-signatures/node/src/indexer.rs | 12 ------------ infra/modules/multichain/main.tf | 4 ---- infra/multichain-dev/variables.tf | 4 ---- infra/multichain-mainnet/variables.tf | 4 ---- infra/multichain-testnet/variables.tf | 4 ---- infra/partner-mainnet/variables.tf | 4 ---- infra/partner-testnet/variables.tf | 4 ---- integration-tests/chain-signatures/src/containers.rs | 1 - integration-tests/chain-signatures/src/local.rs | 2 -- 9 files changed, 39 deletions(-) diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index 826a07f43..b0fa01dfc 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -34,15 +34,6 @@ pub struct Options { #[clap(long, env("MPC_INDEXER_S3_URL"))] pub s3_url: Option, - /// The block height to start indexing from. - // Defaults to the latest block on 2023-11-14 07:40:22 AM UTC - #[clap( - long, - env("MPC_INDEXER_START_BLOCK_HEIGHT"), - default_value = "145964826" - )] - pub start_block_height: u64, - /// The amount of time before we should that our indexer is behind. #[clap(long, env("MPC_INDEXER_BEHIND_THRESHOLD"), default_value = "200")] pub behind_threshold: u64, @@ -59,8 +50,6 @@ impl Options { self.s3_bucket, "--s3-region".to_string(), self.s3_region, - "--start-block-height".to_string(), - self.start_block_height.to_string(), "--behind-threshold".to_string(), self.behind_threshold.to_string(), "--running-threshold".to_string(), @@ -292,7 +281,6 @@ pub fn run( s3_bucket = options.s3_bucket, s3_region = options.s3_region, s3_url = options.s3_url, - start_block_height = options.start_block_height, %mpc_contract_id, "starting indexer" ); diff --git a/infra/modules/multichain/main.tf b/infra/modules/multichain/main.tf index 91b0dbc1f..08a98b34f 100644 --- a/infra/modules/multichain/main.tf +++ b/infra/modules/multichain/main.tf @@ -57,10 +57,6 @@ resource "google_cloud_run_v2_service" "node" { value = var.indexer_options.s3_url } } - env { - name = "MPC_INDEXER_START_BLOCK_HEIGHT" - value = var.indexer_options.start_block_height - } env { name = "MPC_ACCOUNT_SK" value_source { diff --git a/infra/multichain-dev/variables.tf b/infra/multichain-dev/variables.tf index d712fc960..54ecdecce 100644 --- a/infra/multichain-dev/variables.tf +++ b/infra/multichain-dev/variables.tf @@ -102,10 +102,6 @@ variable "static_env" { name = "MPC_INDEXER_S3_BUCKET" value = "near-lake-data-testnet" }, - { - name = "MPC_INDEXER_START_BLOCK_HEIGHT" - value = 177069137 - }, { name = "AWS_DEFAULT_REGION" value = "eu-central-1" diff --git a/infra/multichain-mainnet/variables.tf b/infra/multichain-mainnet/variables.tf index 7316242e9..1c5ee9054 100644 --- a/infra/multichain-mainnet/variables.tf +++ b/infra/multichain-mainnet/variables.tf @@ -99,10 +99,6 @@ variable "static_env" { name = "MPC_INDEXER_S3_BUCKET" value = "near-lake-data-mainnet" }, - { - name = "MPC_INDEXER_START_BLOCK_HEIGHT" - value = 124092099 - }, { name = "AWS_DEFAULT_REGION" value = "eu-central-1" diff --git a/infra/multichain-testnet/variables.tf b/infra/multichain-testnet/variables.tf index 136b9e482..03deb753b 100644 --- a/infra/multichain-testnet/variables.tf +++ b/infra/multichain-testnet/variables.tf @@ -96,10 +96,6 @@ variable "static_env" { name = "MPC_INDEXER_S3_BUCKET" value = "near-lake-data-testnet" }, - { - name = "MPC_INDEXER_START_BLOCK_HEIGHT" - value = 158767549 - }, { name = "AWS_DEFAULT_REGION" value = "eu-central-1" diff --git a/infra/partner-mainnet/variables.tf b/infra/partner-mainnet/variables.tf index da8c63d12..101323f13 100644 --- a/infra/partner-mainnet/variables.tf +++ b/infra/partner-mainnet/variables.tf @@ -99,10 +99,6 @@ variable "static_env" { name = "MPC_INDEXER_S3_BUCKET" value = "near-lake-data-mainnet" }, - { - name = "MPC_INDEXER_START_BLOCK_HEIGHT" - value = 124647189 - }, { name = "AWS_DEFAULT_REGION" value = "eu-central-1" diff --git a/infra/partner-testnet/variables.tf b/infra/partner-testnet/variables.tf index 6eee28d77..0f6ae3272 100644 --- a/infra/partner-testnet/variables.tf +++ b/infra/partner-testnet/variables.tf @@ -96,10 +96,6 @@ variable "static_env" { name = "MPC_INDEXER_S3_BUCKET" value = "near-lake-data-testnet" }, - { - name = "MPC_INDEXER_START_BLOCK_HEIGHT" - value = 158767549 - }, { name = "AWS_DEFAULT_REGION" value = "eu-central-1" diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 460d51d23..3ee76f161 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -96,7 +96,6 @@ impl<'a> Node<'a> { s3_bucket: ctx.localstack.s3_bucket.clone(), s3_region: ctx.localstack.s3_region.clone(), s3_url: Some(ctx.localstack.s3_host_address.clone()), - start_block_height: 0, running_threshold: 120, behind_threshold: 120, }; diff --git a/integration-tests/chain-signatures/src/local.rs b/integration-tests/chain-signatures/src/local.rs index 923ccb155..fca763ed6 100644 --- a/integration-tests/chain-signatures/src/local.rs +++ b/integration-tests/chain-signatures/src/local.rs @@ -52,7 +52,6 @@ impl Node { s3_bucket: ctx.localstack.s3_bucket.clone(), s3_region: ctx.localstack.s3_region.clone(), s3_url: Some(ctx.localstack.s3_host_address.clone()), - start_block_height: 0, running_threshold: 120, behind_threshold: 120, }; @@ -147,7 +146,6 @@ impl Node { s3_bucket: ctx.localstack.s3_bucket.clone(), s3_region: ctx.localstack.s3_region.clone(), s3_url: Some(ctx.localstack.s3_host_address.clone()), - start_block_height: 0, running_threshold: 120, behind_threshold: 120, }; From e3241c0287008a3a31b3ed25ad3ad1149c4c7336 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 7 Nov 2024 22:01:34 +0200 Subject: [PATCH 52/64] remove redundant datastore setup --- chain-signatures/node/src/gcp/mod.rs | 1 - chain-signatures/node/src/gcp/value.rs | 383 ------------------ .../chain-signatures/src/main.rs | 1 + .../chain-signatures/tests/cases/mod.rs | 32 -- 4 files changed, 1 insertion(+), 416 deletions(-) delete mode 100644 chain-signatures/node/src/gcp/value.rs diff --git a/chain-signatures/node/src/gcp/mod.rs b/chain-signatures/node/src/gcp/mod.rs index 17d791f40..ef5f37c56 100644 --- a/chain-signatures/node/src/gcp/mod.rs +++ b/chain-signatures/node/src/gcp/mod.rs @@ -1,5 +1,4 @@ pub mod error; -pub mod value; use crate::storage; diff --git a/chain-signatures/node/src/gcp/value.rs b/chain-signatures/node/src/gcp/value.rs deleted file mode 100644 index e4346ded3..000000000 --- a/chain-signatures/node/src/gcp/value.rs +++ /dev/null @@ -1,383 +0,0 @@ -use google_datastore1::api::{ArrayValue, Entity, Key, LatLng}; -use std::collections::HashMap; - -use super::error::ConvertError; - -#[derive(Debug, Clone)] -pub enum Value { - BooleanValue(bool), - IntegerValue(i64), - DoubleValue(f64), - KeyValue(Key), - StringValue(String), - BlobValue(Vec), - GeoPointValue(f64, f64), - EntityValue { - key: Key, - properties: HashMap, - }, - ArrayValue(Vec), -} - -impl Value { - pub fn type_name(&self) -> &'static str { - match self { - Value::BooleanValue(_) => "bool", - Value::IntegerValue(_) => "integer", - Value::DoubleValue(_) => "double", - Value::KeyValue(_) => "key", - Value::StringValue(_) => "string", - Value::BlobValue(_) => "blob", - Value::GeoPointValue(_, _) => "geopoint", - Value::EntityValue { .. } => "entity", - Value::ArrayValue(_) => "array", - } - } -} - -pub trait IntoValue { - fn into_value(self) -> Value; -} - -pub trait FromValue: Sized { - fn from_value(value: Value) -> Result; -} - -/* - * IntoValue implementations - */ - -impl IntoValue for Value { - fn into_value(self) -> Value { - self - } -} - -impl IntoValue for String { - fn into_value(self) -> Value { - Value::StringValue(self) - } -} - -impl IntoValue for &str { - fn into_value(self) -> Value { - String::from(self).into_value() - } -} - -impl IntoValue for i8 { - fn into_value(self) -> Value { - Value::IntegerValue(self as i64) - } -} - -impl IntoValue for i16 { - fn into_value(self) -> Value { - Value::IntegerValue(self as i64) - } -} - -impl IntoValue for i32 { - fn into_value(self) -> Value { - Value::IntegerValue(self as i64) - } -} - -impl IntoValue for i64 { - fn into_value(self) -> Value { - Value::IntegerValue(self) - } -} - -impl IntoValue for f32 { - fn into_value(self) -> Value { - Value::DoubleValue(self as f64) - } -} - -impl IntoValue for f64 { - fn into_value(self) -> Value { - Value::DoubleValue(self) - } -} - -impl IntoValue for bool { - fn into_value(self) -> Value { - Value::BooleanValue(self) - } -} - -impl IntoValue for Key { - fn into_value(self) -> Value { - Value::KeyValue(self) - } -} - -impl IntoValue for Vec { - fn into_value(self) -> Value { - Value::BlobValue(self.to_vec()) - } -} - -impl IntoValue for Vec -where - T: IntoValue, -{ - fn into_value(self) -> Value { - Value::ArrayValue(self.into_iter().map(IntoValue::into_value).collect()) - } -} - -impl From for Value { - fn from(value: google_datastore1::api::Value) -> Value { - if let Some(val) = value.boolean_value { - Value::BooleanValue(val) - } else if let Some(val) = value.integer_value { - Value::IntegerValue(val) - } else if let Some(val) = value.double_value { - Value::DoubleValue(val) - } else if let Some(val) = value.key_value { - Value::KeyValue(val) - } else if let Some(val) = value.string_value { - Value::StringValue(val) - } else if let Some(val) = value.blob_value { - Value::BlobValue(val) - } else if let Some(val) = value.geo_point_value { - Value::GeoPointValue( - val.latitude.unwrap_or_default(), - val.longitude.unwrap_or_default(), - ) - } else if let Some(val) = value.entity_value { - Value::EntityValue { - key: val.key.unwrap_or_default(), - properties: val - .properties - .unwrap_or_default() - .into_iter() - .map(|(k, v)| (k, Value::from(v))) - .collect(), - } - } else if let Some(val) = value.array_value { - Value::ArrayValue( - val.values - .unwrap_or_default() - .into_iter() - .map(Value::from) - .collect(), - ) - } else { - unimplemented!() - } - } -} - -impl IntoValue for google_datastore1::api::Value { - fn into_value(self) -> Value { - self.into() - } -} - -impl IntoValue for google_datastore1::api::Entity { - fn into_value(self) -> Value { - Value::EntityValue { - key: self.key.unwrap_or_default(), - properties: self - .properties - .unwrap_or_default() - .into_iter() - .map(|(k, v)| (k, v.into_value())) - .collect(), - } - } -} - -/* - * FromValue implementations - */ - -impl FromValue for Value { - fn from_value(value: Value) -> Result { - Ok(value) - } -} - -impl FromValue for String { - fn from_value(value: Value) -> Result { - match value { - Value::StringValue(value) => Ok(value), - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("string"), - got: String::from(value.type_name()), - }), - } - } -} - -impl FromValue for i64 { - fn from_value(value: Value) -> Result { - match value { - Value::IntegerValue(value) => Ok(value), - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("integer"), - got: String::from(value.type_name()), - }), - } - } -} - -impl FromValue for f64 { - fn from_value(value: Value) -> Result { - match value { - Value::DoubleValue(value) => Ok(value), - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("double"), - got: String::from(value.type_name()), - }), - } - } -} - -impl FromValue for bool { - fn from_value(value: Value) -> Result { - match value { - Value::BooleanValue(value) => Ok(value), - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("bool"), - got: String::from(value.type_name()), - }), - } - } -} - -impl FromValue for Key { - fn from_value(value: Value) -> Result { - match value { - Value::KeyValue(value) => Ok(value), - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("key"), - got: String::from(value.type_name()), - }), - } - } -} - -impl FromValue for Vec { - fn from_value(value: Value) -> Result, ConvertError> { - match value { - Value::BlobValue(value) => Ok(value), - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("blob"), - got: String::from(value.type_name()), - }), - } - } -} - -impl FromValue for Vec -where - T: FromValue, -{ - fn from_value(value: Value) -> Result, ConvertError> { - match value { - Value::ArrayValue(values) => { - let values = values - .into_iter() - .map(FromValue::from_value) - .collect::, ConvertError>>()?; - Ok(values) - } - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("array"), - got: String::from(value.type_name()), - }), - } - } -} - -impl FromValue for Entity { - fn from_value(value: Value) -> Result { - match value { - Value::EntityValue { key, properties } => { - let properties = properties - .into_iter() - .map(|(k, v)| { - let v = FromValue::from_value(v)?; - Ok((k, v)) - }) - .collect::, ConvertError>>()?; - Ok(Entity { - key: Some(key), - properties: Some(properties), - }) - } - _ => Err(ConvertError::UnexpectedPropertyType { - expected: String::from("entity"), - got: String::from(value.type_name()), - }), - } - } -} - -impl FromValue for google_datastore1::api::Value { - fn from_value(value: Value) -> Result { - let result = match value { - Value::BooleanValue(val) => google_datastore1::api::Value { - boolean_value: Some(val), - ..Default::default() - }, - Value::IntegerValue(val) => google_datastore1::api::Value { - integer_value: Some(val), - ..Default::default() - }, - Value::DoubleValue(val) => google_datastore1::api::Value { - double_value: Some(val), - ..Default::default() - }, - Value::KeyValue(val) => google_datastore1::api::Value { - key_value: Some(val), - ..Default::default() - }, - Value::StringValue(val) => google_datastore1::api::Value { - string_value: Some(val), - ..Default::default() - }, - Value::BlobValue(val) => google_datastore1::api::Value { - blob_value: Some(val), - ..Default::default() - }, - Value::GeoPointValue(latitude, longitude) => google_datastore1::api::Value { - geo_point_value: Some(LatLng { - latitude: Some(latitude), - longitude: Some(longitude), - }), - ..Default::default() - }, - Value::EntityValue { key, properties } => { - let properties = properties - .into_iter() - .map(|(k, v)| FromValue::from_value(v).map(|v| (k, v))) - .collect::, ConvertError>>()?; - google_datastore1::api::Value { - entity_value: Some(Entity { - key: Some(key), - properties: Some(properties), - }), - ..Default::default() - } - } - Value::ArrayValue(val) => { - let values = val - .into_iter() - .map(FromValue::from_value) - .collect::, ConvertError>>()?; - google_datastore1::api::Value { - array_value: Some(ArrayValue { - values: Some(values), - }), - ..Default::default() - } - } - }; - Ok(result) - } -} diff --git a/integration-tests/chain-signatures/src/main.rs b/integration-tests/chain-signatures/src/main.rs index 65e1548f1..e9cad9751 100644 --- a/integration-tests/chain-signatures/src/main.rs +++ b/integration-tests/chain-signatures/src/main.rs @@ -48,6 +48,7 @@ async fn main() -> anyhow::Result<()> { println!(" release: {}", ctx.release); println!("\nExternal services:"); + // TOOD: do we still need this container? Is it required for secret manager? println!(" datastore: {}", ctx.datastore.local_address); println!(" lake_indexer: {}", ctx.lake_indexer.rpc_host_address); println!(" redis: {}", ctx.redis.internal_address); diff --git a/integration-tests/chain-signatures/tests/cases/mod.rs b/integration-tests/chain-signatures/tests/cases/mod.rs index 2f696b0b1..4c352913e 100644 --- a/integration-tests/chain-signatures/tests/cases/mod.rs +++ b/integration-tests/chain-signatures/tests/cases/mod.rs @@ -19,7 +19,6 @@ use mpc_node::kdf::into_eth_sig; use mpc_node::protocol::presignature::{Presignature, PresignatureId, PresignatureManager}; use mpc_node::protocol::triple::{Triple, TripleManager}; use mpc_node::storage; -use mpc_node::types::LatestBlockHeight; use mpc_node::util::NearPublicKeyExt; use near_account_id::AccountId; use test_log::test; @@ -398,37 +397,6 @@ fn dummy_triple(id: u64) -> Triple { } } -#[test(tokio::test)] -async fn test_latest_block_height() -> anyhow::Result<()> { - with_multichain_nodes(MultichainConfig::default(), |ctx| { - Box::pin(async move { - let state_0 = wait_for::running_mpc(&ctx, Some(0)).await?; - assert_eq!(state_0.participants.len(), 3); - wait_for::has_at_least_triples(&ctx, 2).await?; - wait_for::has_at_least_presignatures(&ctx, 2).await?; - - let gcp_services = ctx.nodes.gcp_services().await?; - for gcp_service in &gcp_services { - let latest = LatestBlockHeight::fetch(gcp_service).await?; - assert!(latest.block_height > 10); - } - - // test manually updating the latest block height - let gcp_service = gcp_services[0].clone(); - let latest = LatestBlockHeight { - account_id: gcp_service.account_id.clone(), - block_height: 1000, - }; - latest.store(&gcp_service).await?; - let new_latest = LatestBlockHeight::fetch(&gcp_service).await?; - assert_eq!(new_latest.block_height, latest.block_height); - - Ok(()) - }) - }) - .await -} - #[test(tokio::test)] async fn test_signature_offline_node_back_online() -> anyhow::Result<()> { with_multichain_nodes(MultichainConfig::default(), |mut ctx| { From 382105c57f5667b86f6ffb7ec849f15563bb2051 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Thu, 7 Nov 2024 22:35:42 +0200 Subject: [PATCH 53/64] add in memory variable for latest processed block --- chain-signatures/node/src/indexer.rs | 16 ++++++++-------- chain-signatures/node/src/web/mod.rs | 3 ++- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index b0fa01dfc..92a3316f4 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -88,6 +88,7 @@ pub struct ContractSignRequest { #[derive(Debug, Clone)] pub struct Indexer { + last_processed_block: Arc>, last_updated_timestamp: Arc>, latest_block_timestamp_nanosec: Arc>>, running_threshold: Duration, @@ -96,8 +97,8 @@ pub struct Indexer { impl Indexer { fn new(options: &Options) -> Self { - // TODO: log latest block height Self { + last_processed_block: Arc::new(RwLock::new(0)), last_updated_timestamp: Arc::new(RwLock::new(Instant::now())), latest_block_timestamp_nanosec: Arc::new(RwLock::new(None)), running_threshold: Duration::from_secs(options.running_threshold), @@ -105,10 +106,8 @@ impl Indexer { } } - /// Get the latest processed block height - pub async fn latest_block_height(&self) -> BlockHeight { - // TODO: fetch latest block using RPC - 0 as BlockHeight + pub async fn last_processed_block(&self) -> BlockHeight { + *self.last_processed_block.read().await } /// Check whether the indexer is on track with the latest block height from the chain. @@ -140,13 +139,12 @@ impl Indexer { block_timestamp_nanosec: u64, ) { tracing::debug!(block_height, "update_block_height_and_timestamp"); + *self.last_processed_block.write().await = block_height; *self.last_updated_timestamp.write().await = Instant::now(); *self.latest_block_timestamp_nanosec.write().await = Some(block_timestamp_nanosec); - // TODO: update the block height in the indexer (add in memoru variable?) } } -// TODO: why do we need this type? Why not use the `Indexer` type directly? #[derive(Clone, LakeContext)] struct Context { mpc_contract_id: AccountId, @@ -285,6 +283,8 @@ pub fn run( "starting indexer" ); + // TODO: fetch here or in the loop the latest block height from the chain. + let indexer = Indexer::new(options); let context = Context { mpc_contract_id: mpc_contract_id.clone(), @@ -308,7 +308,7 @@ pub fn run( i += 1; let Ok(lake) = rt.block_on(async { - let latest = context.indexer.latest_block_height().await; + let latest = context.indexer.last_processed_block().await; if i > 0 { tracing::warn!("indexer latest height {latest}, restart count={i}"); } diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index a39a8d6e7..e1e818e0b 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -130,7 +130,8 @@ pub enum StateView { #[tracing::instrument(level = "debug", skip_all)] async fn state(Extension(state): Extension>) -> Result> { tracing::debug!("fetching state"); - let latest_block_height = state.indexer.latest_block_height().await; + // TODO: rename to last_processed_block when making other breaking changes + let latest_block_height = state.indexer.last_processed_block().await; let is_stable = state.indexer.is_stable().await; let protocol_state = state.protocol_state.read().await; From f904e54aa763fd3f4863b3f400901e42746ae2e3 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 8 Nov 2024 12:48:52 +0200 Subject: [PATCH 54/64] remove datastore users and roles from tf --- chain-signatures/node/src/storage/mod.rs | 2 +- infra/mpc-recovery-dev/main.tf | 6 ------ infra/mpc-recovery-prod/main.tf | 7 ------- infra/mpc-recovery-testnet/main.tf | 7 ------- infra/multichain-dev/main.tf | 1 - infra/multichain-mainnet/main.tf | 2 +- infra/multichain-testnet/main.tf | 1 - infra/partner-mainnet/main.tf | 1 - infra/partner-testnet/main.tf | 1 - integration-tests/chain-signatures/src/containers.rs | 1 + 10 files changed, 3 insertions(+), 26 deletions(-) diff --git a/chain-signatures/node/src/storage/mod.rs b/chain-signatures/node/src/storage/mod.rs index d4bb21bab..69fee247c 100644 --- a/chain-signatures/node/src/storage/mod.rs +++ b/chain-signatures/node/src/storage/mod.rs @@ -6,7 +6,7 @@ pub mod triple_storage; #[derive(Debug, Clone, clap::Parser)] #[group(id = "storage_options")] pub struct Options { - /// env used to suffix datastore table names to differentiate among environments. + /// env used to differentiate among environments. #[clap(long, env("MPC_ENV"))] pub env: String, /// GCP project ID. diff --git a/infra/mpc-recovery-dev/main.tf b/infra/mpc-recovery-dev/main.tf index 21f2f3d3b..e87873f76 100644 --- a/infra/mpc-recovery-dev/main.tf +++ b/infra/mpc-recovery-dev/main.tf @@ -64,12 +64,6 @@ resource "google_service_account_iam_binding" "serivce-account-iam" { ] } -resource "google_project_iam_member" "service-account-datastore-user" { - project = var.project - role = "roles/datastore.user" - member = "serviceAccount:${google_service_account.service_account.email}" -} - /* * Ensure service account has access to Secret Manager variables */ diff --git a/infra/mpc-recovery-prod/main.tf b/infra/mpc-recovery-prod/main.tf index 0e76fd5df..a62ea69fd 100644 --- a/infra/mpc-recovery-prod/main.tf +++ b/infra/mpc-recovery-prod/main.tf @@ -39,13 +39,6 @@ resource "google_service_account" "service_account" { display_name = "MPC Recovery mainnet Account" } - -resource "google_project_iam_member" "service-account-datastore-user" { - project = var.project - role = "roles/datastore.user" - member = "serviceAccount:${google_service_account.service_account.email}" -} - /* * Ensure service account has access to Secret Manager variables */ diff --git a/infra/mpc-recovery-testnet/main.tf b/infra/mpc-recovery-testnet/main.tf index 3314d8ad6..0ba4b909f 100644 --- a/infra/mpc-recovery-testnet/main.tf +++ b/infra/mpc-recovery-testnet/main.tf @@ -39,13 +39,6 @@ resource "google_service_account" "service_account" { display_name = "MPC Recovery testnet Account" } - -resource "google_project_iam_member" "service-account-datastore-user" { - project = var.project - role = "roles/datastore.user" - member = "serviceAccount:${google_service_account.service_account.email}" -} - /* * Ensure service account has access to Secret Manager variables */ diff --git a/infra/multichain-dev/main.tf b/infra/multichain-dev/main.tf index e78ece0f5..c4d7843a5 100644 --- a/infra/multichain-dev/main.tf +++ b/infra/multichain-dev/main.tf @@ -98,7 +98,6 @@ resource "google_service_account" "service_account" { resource "google_project_iam_member" "sa-roles" { for_each = toset([ - "roles/datastore.user", "roles/secretmanager.admin", "roles/storage.objectAdmin", "roles/iam.serviceAccountAdmin", diff --git a/infra/multichain-mainnet/main.tf b/infra/multichain-mainnet/main.tf index d0af8c538..ad8c4fbf0 100644 --- a/infra/multichain-mainnet/main.tf +++ b/infra/multichain-mainnet/main.tf @@ -74,7 +74,7 @@ resource "google_service_account" "service_account" { resource "google_project_iam_member" "sa-roles" { for_each = toset([ - "roles/datastore.user", + "roles/.user", "roles/secretmanager.admin", "roles/storage.objectAdmin", "roles/iam.serviceAccountAdmin", diff --git a/infra/multichain-testnet/main.tf b/infra/multichain-testnet/main.tf index 27b6a032e..c7c3f00ff 100644 --- a/infra/multichain-testnet/main.tf +++ b/infra/multichain-testnet/main.tf @@ -78,7 +78,6 @@ resource "google_service_account" "service_account" { resource "google_project_iam_member" "sa-roles" { for_each = toset([ - "roles/datastore.user", "roles/secretmanager.admin", "roles/storage.objectAdmin", "roles/iam.serviceAccountAdmin", diff --git a/infra/partner-mainnet/main.tf b/infra/partner-mainnet/main.tf index 8f15b1bb0..2c6127a06 100644 --- a/infra/partner-mainnet/main.tf +++ b/infra/partner-mainnet/main.tf @@ -75,7 +75,6 @@ resource "google_service_account" "service_account" { resource "google_project_iam_member" "sa-roles" { for_each = toset([ - "roles/datastore.user", "roles/secretmanager.admin", "roles/storage.objectAdmin", "roles/iam.serviceAccountAdmin", diff --git a/infra/partner-testnet/main.tf b/infra/partner-testnet/main.tf index 28367b919..9facd23e8 100644 --- a/infra/partner-testnet/main.tf +++ b/infra/partner-testnet/main.tf @@ -75,7 +75,6 @@ resource "google_service_account" "service_account" { resource "google_project_iam_member" "sa-roles" { for_each = toset([ - "roles/datastore.user", "roles/secretmanager.admin", "roles/storage.objectAdmin", "roles/iam.serviceAccountAdmin", diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index 3ee76f161..d1e96e883 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -562,6 +562,7 @@ impl Default for DockerClient { } } +// TODO: remove or rename this struct and other mentions of datastore pub struct Datastore<'a> { pub container: Container<'a, GenericImage>, pub address: String, From 2ae0bf65034920e4dc6c5744d6d9393268939d9b Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 8 Nov 2024 14:49:40 +0200 Subject: [PATCH 55/64] datastore docker estup removed --- chain-signatures/node/src/gcp/mod.rs | 1 - chain-signatures/node/src/http_client.rs | 2 +- .../chain-signatures/src/containers.rs | 61 ------------------- integration-tests/chain-signatures/src/lib.rs | 6 -- .../chain-signatures/src/main.rs | 2 - 5 files changed, 1 insertion(+), 71 deletions(-) diff --git a/chain-signatures/node/src/gcp/mod.rs b/chain-signatures/node/src/gcp/mod.rs index ef5f37c56..0fa62b972 100644 --- a/chain-signatures/node/src/gcp/mod.rs +++ b/chain-signatures/node/src/gcp/mod.rs @@ -93,7 +93,6 @@ impl GcpService { ) -> anyhow::Result { let project_id = storage_options.gcp_project_id.clone(); let secret_manager; - // TODO: check string if storage_options.env == "local-test" { let client = hyper::Client::builder().build( hyper_rustls::HttpsConnectorBuilder::new() diff --git a/chain-signatures/node/src/http_client.rs b/chain-signatures/node/src/http_client.rs index 4620a805f..807305239 100644 --- a/chain-signatures/node/src/http_client.rs +++ b/chain-signatures/node/src/http_client.rs @@ -203,7 +203,7 @@ impl MessageQueue { } if uncompacted > 0 { - tracing::info!( + tracing::debug!( uncompacted, compacted, "{from:?} sent messages in {:?};", diff --git a/integration-tests/chain-signatures/src/containers.rs b/integration-tests/chain-signatures/src/containers.rs index d1e96e883..3c449cc63 100644 --- a/integration-tests/chain-signatures/src/containers.rs +++ b/integration-tests/chain-signatures/src/containers.rs @@ -562,67 +562,6 @@ impl Default for DockerClient { } } -// TODO: remove or rename this struct and other mentions of datastore -pub struct Datastore<'a> { - pub container: Container<'a, GenericImage>, - pub address: String, - pub local_address: String, -} - -impl<'a> Datastore<'a> { - pub const CONTAINER_PORT: u16 = 3000; - - pub async fn run( - docker_client: &'a DockerClient, - network: &str, - project_id: &str, - ) -> anyhow::Result> { - tracing::info!("Running datastore container..."); - let image = GenericImage::new( - "gcr.io/google.com/cloudsdktool/google-cloud-cli", - "464.0.0-emulators", - ) - .with_wait_for(WaitFor::message_on_stderr("Dev App Server is now running.")) - .with_exposed_port(Self::CONTAINER_PORT) - .with_entrypoint("gcloud") - .with_env_var( - "DATASTORE_EMULATOR_HOST", - format!("0.0.0.0:{}", Self::CONTAINER_PORT), - ) - .with_env_var("DATASTORE_PROJECT_ID", project_id); - let image: RunnableImage = ( - image, - vec![ - "beta".to_string(), - "emulators".to_string(), - "datastore".to_string(), - "start".to_string(), - format!("--project={project_id}"), - "--host-port".to_string(), - format!("0.0.0.0:{}", Self::CONTAINER_PORT), - "--no-store-on-disk".to_string(), - "--consistency=1.0".to_string(), - ], - ) - .into(); - let image = image.with_network(network); - let container = docker_client.cli.run(image); - let ip_address = docker_client - .get_network_ip_address(&container, network) - .await?; - let host_port = container.get_host_port_ipv4(Self::CONTAINER_PORT); - - let full_address = format!("http://{}:{}/", ip_address, Self::CONTAINER_PORT); - let local_address = format!("http://127.0.0.1:{}/", host_port); - tracing::info!("Datastore container is running at {}", full_address); - Ok(Datastore { - container, - local_address, - address: full_address, - }) - } -} - pub struct Redis<'a> { pub container: Container<'a, GenericImage>, pub internal_address: String, diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index 37d66c01d..c79d83739 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -204,7 +204,6 @@ pub struct Context<'a> { pub lake_indexer: crate::containers::LakeIndexer<'a>, pub worker: Worker, pub mpc_contract: Contract, - pub datastore: crate::containers::Datastore<'a>, pub redis: crate::containers::Redis<'a>, pub storage_options: storage::Options, pub mesh_options: mesh::Options, @@ -231,10 +230,6 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> .await?; tracing::info!(contract_id = %mpc_contract.id(), "deployed mpc contract"); - let gcp_project_id = "multichain-integration"; - let datastore = - crate::containers::Datastore::run(docker_client, docker_network, gcp_project_id).await?; - let redis = crate::containers::Redis::run(docker_client, docker_network).await?; let redis_url = redis.internal_address.clone(); @@ -262,7 +257,6 @@ pub async fn setup(docker_client: &DockerClient) -> anyhow::Result> lake_indexer, worker, mpc_contract, - datastore, redis, storage_options, mesh_options, diff --git a/integration-tests/chain-signatures/src/main.rs b/integration-tests/chain-signatures/src/main.rs index e9cad9751..549af728e 100644 --- a/integration-tests/chain-signatures/src/main.rs +++ b/integration-tests/chain-signatures/src/main.rs @@ -48,8 +48,6 @@ async fn main() -> anyhow::Result<()> { println!(" release: {}", ctx.release); println!("\nExternal services:"); - // TOOD: do we still need this container? Is it required for secret manager? - println!(" datastore: {}", ctx.datastore.local_address); println!(" lake_indexer: {}", ctx.lake_indexer.rpc_host_address); println!(" redis: {}", ctx.redis.internal_address); From 669373d621238253609139a33f7123c495b88bcc Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 8 Nov 2024 14:54:42 +0200 Subject: [PATCH 56/64] fix tf mistake --- infra/multichain-mainnet/main.tf | 1 - 1 file changed, 1 deletion(-) diff --git a/infra/multichain-mainnet/main.tf b/infra/multichain-mainnet/main.tf index ad8c4fbf0..2a654d722 100644 --- a/infra/multichain-mainnet/main.tf +++ b/infra/multichain-mainnet/main.tf @@ -74,7 +74,6 @@ resource "google_service_account" "service_account" { resource "google_project_iam_member" "sa-roles" { for_each = toset([ - "roles/.user", "roles/secretmanager.admin", "roles/storage.objectAdmin", "roles/iam.serviceAccountAdmin", From 404ddbe2273317f803a4f4e9af510184a77472c3 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 8 Nov 2024 18:26:16 +0200 Subject: [PATCH 57/64] fetch latest block using RPC --- chain-signatures/node/src/cli.rs | 32 +++-- chain-signatures/node/src/indexer.rs | 129 ++++++++++++++---- .../node/src/storage/app_data_storage.rs | 45 ++++++ chain-signatures/node/src/storage/mod.rs | 1 + chain-signatures/node/src/web/mod.rs | 2 +- 5 files changed, 165 insertions(+), 44 deletions(-) create mode 100644 chain-signatures/node/src/storage/app_data_storage.rs diff --git a/chain-signatures/node/src/cli.rs b/chain-signatures/node/src/cli.rs index 3d7710f79..1cd0d295c 100644 --- a/chain-signatures/node/src/cli.rs +++ b/chain-signatures/node/src/cli.rs @@ -1,6 +1,7 @@ use crate::config::{Config, LocalConfig, NetworkConfig, OverrideConfig}; use crate::gcp::GcpService; use crate::protocol::{MpcSignProtocol, SignQueue}; +use crate::storage::app_data_storage; use crate::{http_client, indexer, mesh, storage, web}; use clap::Parser; use deadpool_redis::Runtime; @@ -195,13 +196,6 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { .build()?; let gcp_service = rt.block_on(async { GcpService::init(&account_id, &storage_options).await })?; - let (indexer_handle, indexer) = indexer::run( - &indexer_options, - &mpc_contract_id, - &account_id, - &sign_queue, - &rt, - )?; let key_storage = storage::secret_storage::init(Some(&gcp_service), &storage_options, &account_id); @@ -213,6 +207,23 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let triple_storage = storage::triple_storage::init(&redis_pool, &account_id); let presignature_storage = storage::presignature_storage::init(&redis_pool, &account_id); + let app_data_storage = app_data_storage::init(&redis_pool, &account_id); + + let mut rpc_client = near_fetch::Client::new(&near_rpc); + if let Some(referer_param) = client_header_referer { + let client_headers = rpc_client.inner_mut().headers_mut(); + client_headers.insert(http::header::REFERER, referer_param.parse().unwrap()); + } + tracing::info!(rpc_addr = rpc_client.rpc_addr(), "rpc client initialized"); + + let (indexer_handle, indexer) = indexer::run( + &indexer_options, + &mpc_contract_id, + &account_id, + &sign_queue, + app_data_storage, + rpc_client.clone(), + )?; let sign_sk = sign_sk.unwrap_or_else(|| account_sk.clone()); let my_address = my_address @@ -228,13 +239,6 @@ pub fn run(cmd: Cli) -> anyhow::Result<()> { let (sender, receiver) = mpsc::channel(16384); tracing::info!(%my_address, "address detected"); - let mut rpc_client = near_fetch::Client::new(&near_rpc); - if let Some(referer_param) = client_header_referer { - let client_headers = rpc_client.inner_mut().headers_mut(); - client_headers.insert(http::header::REFERER, referer_param.parse().unwrap()); - } - - tracing::info!(rpc_addr = rpc_client.rpc_addr(), "rpc client initialized"); let signer = InMemorySigner::from_secret_key(account_id.clone(), account_sk); let (protocol, protocol_state) = MpcSignProtocol::init( my_address, diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index 92a3316f4..2fa3eae35 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -1,4 +1,5 @@ use crate::protocol::{SignQueue, SignRequest}; +use crate::storage::app_data_storage::AppDataRedisStorage; use crypto_shared::{derive_epsilon, ScalarExt}; use k256::Scalar; use near_account_id::AccountId; @@ -69,7 +70,6 @@ struct SignArguments { request: UnvalidatedContractSignRequest, } -// TODO: why do we need this type? /// What is recieved when sign is called #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] struct UnvalidatedContractSignRequest { @@ -86,9 +86,9 @@ pub struct ContractSignRequest { pub key_version: u32, } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Indexer { - last_processed_block: Arc>, + app_data_storage: AppDataRedisStorage, last_updated_timestamp: Arc>, latest_block_timestamp_nanosec: Arc>>, running_threshold: Duration, @@ -96,9 +96,9 @@ pub struct Indexer { } impl Indexer { - fn new(options: &Options) -> Self { + fn new(app_data_storage: AppDataRedisStorage, options: &Options) -> Self { Self { - last_processed_block: Arc::new(RwLock::new(0)), + app_data_storage: app_data_storage.clone(), last_updated_timestamp: Arc::new(RwLock::new(Instant::now())), latest_block_timestamp_nanosec: Arc::new(RwLock::new(None)), running_threshold: Duration::from_secs(options.running_threshold), @@ -106,8 +106,28 @@ impl Indexer { } } - pub async fn last_processed_block(&self) -> BlockHeight { - *self.last_processed_block.read().await + pub async fn get_last_processed_block(&self) -> Option { + match self.app_data_storage.get_last_processed_block().await { + Ok(Some(block_height)) => Some(block_height), + Ok(None) => { + tracing::warn!("no last processed block found"); + None + } + Err(err) => { + tracing::warn!(%err, "failed to get last processed block"); + None + } + } + } + + pub async fn set_last_processed_block(&self, block_height: BlockHeight) { + if let Err(err) = self + .app_data_storage + .set_last_processed_block(block_height) + .await + { + tracing::error!(%err, "failed to set last processed block"); + } } /// Check whether the indexer is on track with the latest block height from the chain. @@ -139,7 +159,7 @@ impl Indexer { block_timestamp_nanosec: u64, ) { tracing::debug!(block_height, "update_block_height_and_timestamp"); - *self.last_processed_block.write().await = block_height; + self.set_last_processed_block(block_height).await; *self.last_updated_timestamp.write().await = Instant::now(); *self.latest_block_timestamp_nanosec.write().await = Some(block_timestamp_nanosec); } @@ -273,7 +293,8 @@ pub fn run( mpc_contract_id: &AccountId, node_account_id: &AccountId, queue: &Arc>, - _rt: &tokio::runtime::Runtime, + app_data_storage: AppDataRedisStorage, + rpc_client: near_fetch::Client, ) -> anyhow::Result<(JoinHandle>, Indexer)> { tracing::info!( s3_bucket = options.s3_bucket, @@ -283,9 +304,7 @@ pub fn run( "starting indexer" ); - // TODO: fetch here or in the loop the latest block height from the chain. - - let indexer = Indexer::new(options); + let indexer = Indexer::new(app_data_storage.clone(), options); let context = Context { mpc_contract_id: mpc_contract_id.clone(), node_account_id: node_account_id.clone(), @@ -308,24 +327,30 @@ pub fn run( i += 1; let Ok(lake) = rt.block_on(async { - let latest = context.indexer.last_processed_block().await; - if i > 0 { - tracing::warn!("indexer latest height {latest}, restart count={i}"); - } - let mut lake_builder = LakeBuilder::default() - .s3_bucket_name(&options.s3_bucket) - .s3_region_name(&options.s3_region) - .start_block_height(latest); - - if let Some(s3_url) = &options.s3_url { - let aws_config = aws_config::from_env().load().await; - let s3_config = aws_sdk_s3::config::Builder::from(&aws_config) - .endpoint_url(s3_url) - .build(); - lake_builder = lake_builder.s3_config(s3_config); + update_last_processed_block(rpc_client.clone(), app_data_storage.clone()).await?; + + if let Some(latest) = context.indexer.get_last_processed_block().await { + if i > 0 { + tracing::warn!("indexer latest height {latest}, restart count={i}"); + } + let mut lake_builder = LakeBuilder::default() + .s3_bucket_name(&options.s3_bucket) + .s3_region_name(&options.s3_region) + .start_block_height(latest); + + if let Some(s3_url) = &options.s3_url { + let aws_config = aws_config::from_env().load().await; + let s3_config = aws_sdk_s3::config::Builder::from(&aws_config) + .endpoint_url(s3_url) + .build(); + lake_builder = lake_builder.s3_config(s3_config); + } + let lake = lake_builder.build()?; + return anyhow::Ok(lake); + } else { + tracing::warn!("indexer failed to get last processed block"); + return Err(anyhow::anyhow!("failed to get last processed block")); } - let lake = lake_builder.build()?; - anyhow::Ok(lake) }) else { tracing::error!(?options, "indexer failed to build"); backoff(i, 1, 120); @@ -384,6 +409,52 @@ pub fn run( Ok((join_handle, indexer)) } +/// This function ensures we do not go back in time a lot when restarting the node +async fn update_last_processed_block( + rpc_client: near_fetch::Client, + app_data_storage: AppDataRedisStorage, +) -> anyhow::Result<()> { + let last_processed_block = match app_data_storage.get_last_processed_block().await { + Ok(Some(block_height)) => block_height, + Ok(None) => 0, + Err(err) => { + tracing::warn!(%err, "failed to get last processed block"); + return Err(err.into()); + } + }; + + let latest_block: u64 = rpc_client.view_block().await?.header.height; + + if last_processed_block > latest_block { + let error_message = format!( + "last processed block is greater than latest block: last_processed_block={}, latest_block={}", + last_processed_block, latest_block + ); + tracing::error!("{}", error_message); + Err(anyhow::anyhow!(error_message))?; + } + + const MAX_YIELD_RESUME_BLOCKS: u64 = 200; + let starting_block: u64 = { + if latest_block - last_processed_block < MAX_YIELD_RESUME_BLOCKS { + last_processed_block + } else { + latest_block.saturating_sub(MAX_YIELD_RESUME_BLOCKS) + } + }; + app_data_storage + .set_last_processed_block(starting_block) + .await?; + + tracing::info!( + "set last processed block to {} to start indexer with, previous last processed: {}, latest block: {}", + last_processed_block, + latest_block, + starting_block, + ); + Ok(()) +} + fn backoff(i: u32, multiplier: u32, max: u64) { // Exponential backoff with max delay of max seconds let delay: u64 = std::cmp::min(2u64.pow(i).mul(multiplier as u64), max); diff --git a/chain-signatures/node/src/storage/app_data_storage.rs b/chain-signatures/node/src/storage/app_data_storage.rs new file mode 100644 index 000000000..a0d340a76 --- /dev/null +++ b/chain-signatures/node/src/storage/app_data_storage.rs @@ -0,0 +1,45 @@ +use anyhow::Ok; +use deadpool_redis::Pool; +use near_primitives::types::BlockHeight; +use near_sdk::AccountId; +use redis::AsyncCommands; + +type AppDataResult = std::result::Result; + +const APP_DATA_PREFIX: &str = "app_data"; +const APP_DATA_STORAGE_VERSION: &str = "v1"; + +pub fn init(pool: &Pool, node_account_id: &AccountId) -> AppDataRedisStorage { + AppDataRedisStorage { + redis_pool: pool.clone(), + node_account_id: node_account_id.clone(), + } +} + +#[derive(Clone)] +pub struct AppDataRedisStorage { + redis_pool: Pool, + node_account_id: AccountId, +} + +impl AppDataRedisStorage { + pub async fn set_last_processed_block(&self, height: BlockHeight) -> AppDataResult<()> { + let mut conn = self.redis_pool.get().await?; + conn.set::<&str, BlockHeight, ()>(&self.last_block_key(), height) + .await?; + Ok(()) + } + + pub async fn get_last_processed_block(&self) -> AppDataResult> { + let mut conn = self.redis_pool.get().await?; + let result: Option = conn.get(self.last_block_key()).await?; + Ok(result) + } + + fn last_block_key(&self) -> String { + format!( + "{}:{}:{}:last_block", + APP_DATA_PREFIX, APP_DATA_STORAGE_VERSION, self.node_account_id + ) + } +} diff --git a/chain-signatures/node/src/storage/mod.rs b/chain-signatures/node/src/storage/mod.rs index 69fee247c..55231df93 100644 --- a/chain-signatures/node/src/storage/mod.rs +++ b/chain-signatures/node/src/storage/mod.rs @@ -1,3 +1,4 @@ +pub mod app_data_storage; pub mod presignature_storage; pub mod secret_storage; pub mod triple_storage; diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index e1e818e0b..c72ae9724 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -131,7 +131,7 @@ pub enum StateView { async fn state(Extension(state): Extension>) -> Result> { tracing::debug!("fetching state"); // TODO: rename to last_processed_block when making other breaking changes - let latest_block_height = state.indexer.last_processed_block().await; + let latest_block_height = state.indexer.get_last_processed_block().await.unwrap_or(0); let is_stable = state.indexer.is_stable().await; let protocol_state = state.protocol_state.read().await; From 358a7d16d17572efaab10a0bc1ea01d9b75ee1e3 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 8 Nov 2024 19:11:51 +0200 Subject: [PATCH 58/64] clippy --- chain-signatures/node/src/indexer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index 2fa3eae35..ee0033e99 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -346,10 +346,10 @@ pub fn run( lake_builder = lake_builder.s3_config(s3_config); } let lake = lake_builder.build()?; - return anyhow::Ok(lake); + anyhow::Ok(lake) } else { tracing::warn!("indexer failed to get last processed block"); - return Err(anyhow::anyhow!("failed to get last processed block")); + Err(anyhow::anyhow!("failed to get last processed block")) } }) else { tracing::error!(?options, "indexer failed to build"); @@ -419,7 +419,7 @@ async fn update_last_processed_block( Ok(None) => 0, Err(err) => { tracing::warn!(%err, "failed to get last processed block"); - return Err(err.into()); + return Err(err); } }; From 5b7ab8fae43e7397c267ff8ebaebcd7c8b4ffb4e Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Fri, 8 Nov 2024 21:26:06 +0200 Subject: [PATCH 59/64] change log order --- chain-signatures/node/src/indexer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index ee0033e99..2001a9016 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -448,9 +448,9 @@ async fn update_last_processed_block( tracing::info!( "set last processed block to {} to start indexer with, previous last processed: {}, latest block: {}", + starting_block, last_processed_block, latest_block, - starting_block, ); Ok(()) } From 80501906028a813206e5218ebee35740a6eb03c7 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Sat, 9 Nov 2024 00:58:13 +0200 Subject: [PATCH 60/64] revert mpc recovery tf changes --- infra/mpc-recovery-dev/main.tf | 6 ++++++ infra/mpc-recovery-prod/main.tf | 6 ++++++ infra/mpc-recovery-testnet/main.tf | 7 +++++++ 3 files changed, 19 insertions(+) diff --git a/infra/mpc-recovery-dev/main.tf b/infra/mpc-recovery-dev/main.tf index e87873f76..21f2f3d3b 100644 --- a/infra/mpc-recovery-dev/main.tf +++ b/infra/mpc-recovery-dev/main.tf @@ -64,6 +64,12 @@ resource "google_service_account_iam_binding" "serivce-account-iam" { ] } +resource "google_project_iam_member" "service-account-datastore-user" { + project = var.project + role = "roles/datastore.user" + member = "serviceAccount:${google_service_account.service_account.email}" +} + /* * Ensure service account has access to Secret Manager variables */ diff --git a/infra/mpc-recovery-prod/main.tf b/infra/mpc-recovery-prod/main.tf index a62ea69fd..3adcb33a3 100644 --- a/infra/mpc-recovery-prod/main.tf +++ b/infra/mpc-recovery-prod/main.tf @@ -39,6 +39,12 @@ resource "google_service_account" "service_account" { display_name = "MPC Recovery mainnet Account" } + +resource "google_project_iam_member" "service-account-datastore-user" { + project = var.project + role = "roles/datastore.user" + member = "serviceAccount:${google_service_account.service_account.email}" +} /* * Ensure service account has access to Secret Manager variables */ diff --git a/infra/mpc-recovery-testnet/main.tf b/infra/mpc-recovery-testnet/main.tf index 0ba4b909f..3314d8ad6 100644 --- a/infra/mpc-recovery-testnet/main.tf +++ b/infra/mpc-recovery-testnet/main.tf @@ -39,6 +39,13 @@ resource "google_service_account" "service_account" { display_name = "MPC Recovery testnet Account" } + +resource "google_project_iam_member" "service-account-datastore-user" { + project = var.project + role = "roles/datastore.user" + member = "serviceAccount:${google_service_account.service_account.email}" +} + /* * Ensure service account has access to Secret Manager variables */ From 00bbd966315006d07adfa109f7fa2ea04f1250de Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Sat, 9 Nov 2024 01:00:05 +0200 Subject: [PATCH 61/64] revert mpc recovery tf changes --- infra/mpc-recovery-prod/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/infra/mpc-recovery-prod/main.tf b/infra/mpc-recovery-prod/main.tf index 3adcb33a3..0e76fd5df 100644 --- a/infra/mpc-recovery-prod/main.tf +++ b/infra/mpc-recovery-prod/main.tf @@ -45,6 +45,7 @@ resource "google_project_iam_member" "service-account-datastore-user" { role = "roles/datastore.user" member = "serviceAccount:${google_service_account.service_account.email}" } + /* * Ensure service account has access to Secret Manager variables */ From 89f981a2a4336e7333bf6ca2825a37e2b6f6142b Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Wed, 20 Nov 2024 16:58:47 +0200 Subject: [PATCH 62/64] renamings --- chain-signatures/node/src/indexer.rs | 18 +++++++++--------- .../node/src/protocol/consensus.rs | 8 ++++---- chain-signatures/node/src/protocol/mod.rs | 16 ++++++++-------- .../node/src/protocol/presignature.rs | 6 +++--- chain-signatures/node/src/protocol/triple.rs | 6 +++--- .../node/src/storage/app_data_storage.rs | 14 ++++++-------- .../node/src/storage/presignature_storage.rs | 8 ++++---- .../node/src/storage/triple_storage.rs | 8 ++++---- chain-signatures/node/src/web/mod.rs | 2 +- integration-tests/chain-signatures/src/lib.rs | 8 ++------ 10 files changed, 44 insertions(+), 50 deletions(-) diff --git a/chain-signatures/node/src/indexer.rs b/chain-signatures/node/src/indexer.rs index 2001a9016..bd15a3e7d 100644 --- a/chain-signatures/node/src/indexer.rs +++ b/chain-signatures/node/src/indexer.rs @@ -1,5 +1,5 @@ use crate::protocol::{SignQueue, SignRequest}; -use crate::storage::app_data_storage::AppDataRedisStorage; +use crate::storage::app_data_storage::AppDataStorage; use crypto_shared::{derive_epsilon, ScalarExt}; use k256::Scalar; use near_account_id::AccountId; @@ -88,7 +88,7 @@ pub struct ContractSignRequest { #[derive(Clone)] pub struct Indexer { - app_data_storage: AppDataRedisStorage, + app_data_storage: AppDataStorage, last_updated_timestamp: Arc>, latest_block_timestamp_nanosec: Arc>>, running_threshold: Duration, @@ -96,7 +96,7 @@ pub struct Indexer { } impl Indexer { - fn new(app_data_storage: AppDataRedisStorage, options: &Options) -> Self { + fn new(app_data_storage: AppDataStorage, options: &Options) -> Self { Self { app_data_storage: app_data_storage.clone(), last_updated_timestamp: Arc::new(RwLock::new(Instant::now())), @@ -106,8 +106,8 @@ impl Indexer { } } - pub async fn get_last_processed_block(&self) -> Option { - match self.app_data_storage.get_last_processed_block().await { + pub async fn last_processed_block(&self) -> Option { + match self.app_data_storage.last_processed_block().await { Ok(Some(block_height)) => Some(block_height), Ok(None) => { tracing::warn!("no last processed block found"); @@ -293,7 +293,7 @@ pub fn run( mpc_contract_id: &AccountId, node_account_id: &AccountId, queue: &Arc>, - app_data_storage: AppDataRedisStorage, + app_data_storage: AppDataStorage, rpc_client: near_fetch::Client, ) -> anyhow::Result<(JoinHandle>, Indexer)> { tracing::info!( @@ -329,7 +329,7 @@ pub fn run( let Ok(lake) = rt.block_on(async { update_last_processed_block(rpc_client.clone(), app_data_storage.clone()).await?; - if let Some(latest) = context.indexer.get_last_processed_block().await { + if let Some(latest) = context.indexer.last_processed_block().await { if i > 0 { tracing::warn!("indexer latest height {latest}, restart count={i}"); } @@ -412,9 +412,9 @@ pub fn run( /// This function ensures we do not go back in time a lot when restarting the node async fn update_last_processed_block( rpc_client: near_fetch::Client, - app_data_storage: AppDataRedisStorage, + app_data_storage: AppDataStorage, ) -> anyhow::Result<()> { - let last_processed_block = match app_data_storage.get_last_processed_block().await { + let last_processed_block = match app_data_storage.last_processed_block().await { Ok(Some(block_height)) => block_height, Ok(None) => 0, Err(err) => { diff --git a/chain-signatures/node/src/protocol/consensus.rs b/chain-signatures/node/src/protocol/consensus.rs index 40f30e4a0..f1a1a0064 100644 --- a/chain-signatures/node/src/protocol/consensus.rs +++ b/chain-signatures/node/src/protocol/consensus.rs @@ -11,9 +11,9 @@ use crate::protocol::presignature::PresignatureManager; use crate::protocol::signature::SignatureManager; use crate::protocol::state::{GeneratingState, ResharingState}; use crate::protocol::triple::TripleManager; -use crate::storage::presignature_storage::PresignatureRedisStorage; +use crate::storage::presignature_storage::PresignatureStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::TripleRedisStorage; +use crate::storage::triple_storage::TripleStorage; use crate::types::{KeygenProtocol, ReshareProtocol, SecretKeyShare}; use crate::util::AffinePointExt; use crate::{http_client, rpc_client}; @@ -39,8 +39,8 @@ pub trait ConsensusCtx { fn my_address(&self) -> &Url; fn sign_queue(&self) -> Arc>; fn secret_storage(&self) -> &SecretNodeStorageBox; - fn triple_storage(&self) -> &TripleRedisStorage; - fn presignature_storage(&self) -> &PresignatureRedisStorage; + fn triple_storage(&self) -> &TripleStorage; + fn presignature_storage(&self) -> &PresignatureStorage; fn cfg(&self) -> &Config; fn message_options(&self) -> http_client::Options; } diff --git a/chain-signatures/node/src/protocol/mod.rs b/chain-signatures/node/src/protocol/mod.rs index 7109e7c4c..c7ea2cd8c 100644 --- a/chain-signatures/node/src/protocol/mod.rs +++ b/chain-signatures/node/src/protocol/mod.rs @@ -29,9 +29,9 @@ use crate::protocol::consensus::ConsensusProtocol; use crate::protocol::cryptography::CryptographicProtocol; use crate::protocol::message::{MessageHandler, MpcMessageQueue}; use crate::rpc_client; -use crate::storage::presignature_storage::PresignatureRedisStorage; +use crate::storage::presignature_storage::PresignatureStorage; use crate::storage::secret_storage::SecretNodeStorageBox; -use crate::storage::triple_storage::TripleRedisStorage; +use crate::storage::triple_storage::TripleStorage; use cait_sith::protocol::Participant; use near_account_id::AccountId; @@ -53,8 +53,8 @@ struct Ctx { http_client: reqwest::Client, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: TripleRedisStorage, - presignature_storage: PresignatureRedisStorage, + triple_storage: TripleStorage, + presignature_storage: PresignatureStorage, cfg: Config, mesh: Mesh, message_options: http_client::Options, @@ -97,11 +97,11 @@ impl ConsensusCtx for &mut MpcSignProtocol { &self.ctx.cfg } - fn triple_storage(&self) -> &TripleRedisStorage { + fn triple_storage(&self) -> &TripleStorage { &self.ctx.triple_storage } - fn presignature_storage(&self) -> &PresignatureRedisStorage { + fn presignature_storage(&self) -> &PresignatureStorage { &self.ctx.presignature_storage } @@ -177,8 +177,8 @@ impl MpcSignProtocol { receiver: mpsc::Receiver, sign_queue: Arc>, secret_storage: SecretNodeStorageBox, - triple_storage: TripleRedisStorage, - presignature_storage: PresignatureRedisStorage, + triple_storage: TripleStorage, + presignature_storage: PresignatureStorage, cfg: Config, mesh_options: mesh::Options, message_options: http_client::Options, diff --git a/chain-signatures/node/src/protocol/presignature.rs b/chain-signatures/node/src/protocol/presignature.rs index 6aecae80b..865df5197 100644 --- a/chain-signatures/node/src/protocol/presignature.rs +++ b/chain-signatures/node/src/protocol/presignature.rs @@ -1,7 +1,7 @@ use super::message::PresignatureMessage; use super::triple::{Triple, TripleId, TripleManager}; use crate::protocol::contract::primitives::Participants; -use crate::storage::presignature_storage::PresignatureRedisStorage; +use crate::storage::presignature_storage::PresignatureStorage; use crate::types::{PresignatureProtocol, SecretKeyShare}; use crate::util::AffinePointExt; @@ -150,7 +150,7 @@ pub enum GenerationError { /// Abstracts how triples are generated by providing a way to request a new triple that will be /// complete some time in the future and a way to take an already generated triple. pub struct PresignatureManager { - presignature_storage: PresignatureRedisStorage, + presignature_storage: PresignatureStorage, /// Ongoing presignature generation protocols. generators: HashMap, /// The set of presignatures that were introduced to the system by the current node. @@ -171,7 +171,7 @@ impl PresignatureManager { threshold: usize, epoch: u64, my_account_id: &AccountId, - storage: &PresignatureRedisStorage, + storage: &PresignatureStorage, ) -> Self { Self { presignature_storage: storage.clone(), diff --git a/chain-signatures/node/src/protocol/triple.rs b/chain-signatures/node/src/protocol/triple.rs index cb9ef8baa..2e80d3386 100644 --- a/chain-signatures/node/src/protocol/triple.rs +++ b/chain-signatures/node/src/protocol/triple.rs @@ -2,7 +2,7 @@ use super::contract::primitives::Participants; use super::cryptography::CryptographicError; use super::message::TripleMessage; use super::presignature::GenerationError; -use crate::storage::triple_storage::TripleRedisStorage; +use crate::storage::triple_storage::TripleStorage; use crate::types::TripleProtocol; use crate::util::AffinePointExt; @@ -80,7 +80,7 @@ impl TripleGenerator { /// complete some time in the future and a way to take an already generated triple. pub struct TripleManager { /// Triple Storage - pub triple_storage: TripleRedisStorage, + pub triple_storage: TripleStorage, /// The pool of triple protocols that have yet to be completed. pub generators: HashMap, @@ -128,7 +128,7 @@ impl TripleManager { threshold: usize, epoch: u64, my_account_id: &AccountId, - storage: &TripleRedisStorage, + storage: &TripleStorage, ) -> Self { Self { generators: HashMap::new(), diff --git a/chain-signatures/node/src/storage/app_data_storage.rs b/chain-signatures/node/src/storage/app_data_storage.rs index a0d340a76..30041ef6c 100644 --- a/chain-signatures/node/src/storage/app_data_storage.rs +++ b/chain-signatures/node/src/storage/app_data_storage.rs @@ -4,33 +4,31 @@ use near_primitives::types::BlockHeight; use near_sdk::AccountId; use redis::AsyncCommands; -type AppDataResult = std::result::Result; - const APP_DATA_PREFIX: &str = "app_data"; const APP_DATA_STORAGE_VERSION: &str = "v1"; -pub fn init(pool: &Pool, node_account_id: &AccountId) -> AppDataRedisStorage { - AppDataRedisStorage { +pub fn init(pool: &Pool, node_account_id: &AccountId) -> AppDataStorage { + AppDataStorage { redis_pool: pool.clone(), node_account_id: node_account_id.clone(), } } #[derive(Clone)] -pub struct AppDataRedisStorage { +pub struct AppDataStorage { redis_pool: Pool, node_account_id: AccountId, } -impl AppDataRedisStorage { - pub async fn set_last_processed_block(&self, height: BlockHeight) -> AppDataResult<()> { +impl AppDataStorage { + pub async fn set_last_processed_block(&self, height: BlockHeight) -> anyhow::Result<()> { let mut conn = self.redis_pool.get().await?; conn.set::<&str, BlockHeight, ()>(&self.last_block_key(), height) .await?; Ok(()) } - pub async fn get_last_processed_block(&self) -> AppDataResult> { + pub async fn last_processed_block(&self) -> anyhow::Result> { let mut conn = self.redis_pool.get().await?; let result: Option = conn.get(self.last_block_key()).await?; Ok(result) diff --git a/chain-signatures/node/src/storage/presignature_storage.rs b/chain-signatures/node/src/storage/presignature_storage.rs index 0f750185a..0138d27fe 100644 --- a/chain-signatures/node/src/storage/presignature_storage.rs +++ b/chain-signatures/node/src/storage/presignature_storage.rs @@ -10,20 +10,20 @@ type PresigResult = std::result::Result; // Can be used to "clear" redis storage in case of a breaking change const PRESIGNATURE_STORAGE_VERSION: &str = "v1"; -pub fn init(pool: &Pool, node_account_id: &AccountId) -> PresignatureRedisStorage { - PresignatureRedisStorage { +pub fn init(pool: &Pool, node_account_id: &AccountId) -> PresignatureStorage { + PresignatureStorage { redis_pool: pool.clone(), node_account_id: node_account_id.clone(), } } #[derive(Clone)] -pub struct PresignatureRedisStorage { +pub struct PresignatureStorage { redis_pool: Pool, node_account_id: AccountId, } -impl PresignatureRedisStorage { +impl PresignatureStorage { pub async fn insert(&self, presignature: Presignature) -> PresigResult<()> { let mut connection = self.redis_pool.get().await?; connection diff --git a/chain-signatures/node/src/storage/triple_storage.rs b/chain-signatures/node/src/storage/triple_storage.rs index 4a76c3365..ff5e39fe1 100644 --- a/chain-signatures/node/src/storage/triple_storage.rs +++ b/chain-signatures/node/src/storage/triple_storage.rs @@ -10,20 +10,20 @@ type TripleResult = std::result::Result; // Can be used to "clear" redis storage in case of a breaking change const TRIPLE_STORAGE_VERSION: &str = "v1"; -pub fn init(pool: &Pool, account_id: &AccountId) -> TripleRedisStorage { - TripleRedisStorage { +pub fn init(pool: &Pool, account_id: &AccountId) -> TripleStorage { + TripleStorage { redis_pool: pool.clone(), node_account_id: account_id.clone(), } } #[derive(Clone)] -pub struct TripleRedisStorage { +pub struct TripleStorage { redis_pool: Pool, node_account_id: AccountId, } -impl TripleRedisStorage { +impl TripleStorage { pub async fn insert(&self, triple: Triple) -> TripleResult<()> { let mut conn = self.redis_pool.get().await?; conn.hset::<&str, TripleId, Triple, ()>(&self.triple_key(), triple.id, triple) diff --git a/chain-signatures/node/src/web/mod.rs b/chain-signatures/node/src/web/mod.rs index c72ae9724..633267514 100644 --- a/chain-signatures/node/src/web/mod.rs +++ b/chain-signatures/node/src/web/mod.rs @@ -131,7 +131,7 @@ pub enum StateView { async fn state(Extension(state): Extension>) -> Result> { tracing::debug!("fetching state"); // TODO: rename to last_processed_block when making other breaking changes - let latest_block_height = state.indexer.get_last_processed_block().await.unwrap_or(0); + let latest_block_height = state.indexer.last_processed_block().await.unwrap_or(0); let is_stable = state.indexer.is_stable().await; let protocol_state = state.protocol_state.read().await; diff --git a/integration-tests/chain-signatures/src/lib.rs b/integration-tests/chain-signatures/src/lib.rs index c79d83739..08e4fd548 100644 --- a/integration-tests/chain-signatures/src/lib.rs +++ b/integration-tests/chain-signatures/src/lib.rs @@ -19,7 +19,7 @@ use mpc_node::gcp::GcpService; use mpc_node::http_client; use mpc_node::mesh; use mpc_node::storage; -use mpc_node::storage::triple_storage::TripleRedisStorage; +use mpc_node::storage::triple_storage::TripleStorage; use near_crypto::KeyFile; use near_workspaces::network::{Sandbox, ValidatorKey}; use near_workspaces::types::{KeyType, SecretKey}; @@ -156,11 +156,7 @@ impl Nodes<'_> { Ok(()) } - pub async fn triple_storage( - &self, - redis_pool: &Pool, - account_id: &AccountId, - ) -> TripleRedisStorage { + pub async fn triple_storage(&self, redis_pool: &Pool, account_id: &AccountId) -> TripleStorage { storage::triple_storage::init(redis_pool, account_id) } From dc892dfe158450334aaf337c738c82252bde7569 Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Mon, 25 Nov 2024 16:33:44 +0200 Subject: [PATCH 63/64] ignore RUSTSEC-2024-0399 --- .github/workflows/unit.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index 7fa884fe1..f6085cdd3 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -100,5 +100,6 @@ jobs: # RUSTSEC-2024-0344 and RUSTSEC-2022-0093 are both to do with ed25519 signatures in near-sdk, we don't sign things with this library so it's safe # RUSTSEC-2022-0054 wee-alloc is unmaintained, it's fine for now because we barely use an allocator and the contracts are short lived, but we should find a replacement/use the default allocator # RUSTSEC-2021-0145 atty can do an unallocated read with a custom allocator in windows. We don't run this in windows and we don't use a custom allocator. + # RUSTSEC-2024-0399 according to the description, this is not affecting us since we are not using Acceptor run: | - cargo audit --ignore RUSTSEC-2022-0093 --ignore RUSTSEC-2024-0344 --ignore RUSTSEC-2022-0054 --ignore RUSTSEC-2021-0145 + cargo audit --ignore RUSTSEC-2022-0093 --ignore RUSTSEC-2024-0344 --ignore RUSTSEC-2022-0054 --ignore RUSTSEC-2021-0145 --ignore RUSTSEC-2024-0399 From a825b66a196e58e23ebfe94a1061f0f22aeeb3ef Mon Sep 17 00:00:00 2001 From: Serhii Volovyk Date: Mon, 25 Nov 2024 22:52:47 +0200 Subject: [PATCH 64/64] merge mistake fix --- infra/multichain-dev/variables.tf | 7 ------- 1 file changed, 7 deletions(-) diff --git a/infra/multichain-dev/variables.tf b/infra/multichain-dev/variables.tf index 3f90a218f..dc0d70997 100644 --- a/infra/multichain-dev/variables.tf +++ b/infra/multichain-dev/variables.tf @@ -104,13 +104,6 @@ variable "static_env" { value = "near-lake-data-testnet" }, { -<<<<<<< HEAD -======= - name = "MPC_INDEXER_START_BLOCK_HEIGHT" - value = 180133172 - }, - { ->>>>>>> develop name = "AWS_DEFAULT_REGION" value = "eu-central-1" },