-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make sure triples and presignatures are not reused #931
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -187,6 +187,17 @@ impl PresignatureManager { | |
|
||
pub async fn insert(&mut self, presignature: Presignature) { | ||
tracing::debug!(id = ?presignature.id, "inserting presignature"); | ||
if self.contains(&presignature.id).await { | ||
tracing::error!(id = presignature.id, "mine presignature already inserted"); | ||
return; | ||
} | ||
if self.contains_used(&presignature.id).await { | ||
tracing::error!( | ||
id = presignature.id, | ||
"tried to insert used mine presignature" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
); | ||
return; | ||
} | ||
// Remove from taken list if it was there | ||
self.gc.remove(&presignature.id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. gc field is actually not necessary in PresignatureManager now that you add the used presignatures to storage. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GC is used for multiple purposes. I want to discuss that with @ChaoticTempest |
||
if let Err(e) = self.presignature_storage.insert(presignature).await { | ||
|
@@ -196,13 +207,31 @@ impl PresignatureManager { | |
|
||
pub async fn insert_mine(&mut self, presignature: Presignature) { | ||
tracing::debug!(id = ?presignature.id, "inserting mine presignature"); | ||
if self.contains(&presignature.id).await { | ||
tracing::error!(id = presignature.id, "mine presignature already inserted"); | ||
return; | ||
} | ||
if self.contains_used(&presignature.id).await { | ||
tracing::error!( | ||
id = presignature.id, | ||
"tried to insert used mine presignature" | ||
); | ||
return; | ||
} | ||
// Remove from taken list if it was there | ||
self.gc.remove(&presignature.id); | ||
if let Err(e) = self.presignature_storage.insert_mine(presignature).await { | ||
tracing::error!(?e, "failed to insert mine presignature"); | ||
} | ||
} | ||
|
||
pub async fn insert_used(&mut self, id: PresignatureId) { | ||
tracing::debug!(id, "inserting presignature to used"); | ||
if let Err(e) = self.presignature_storage.insert_used(id).await { | ||
tracing::error!(?e, "failed to insert presignature to used"); | ||
} | ||
} | ||
|
||
/// Returns true if the presignature with the given id is already generated | ||
pub async fn contains(&self, id: &PresignatureId) -> bool { | ||
self.presignature_storage | ||
|
@@ -225,11 +254,20 @@ impl PresignatureManager { | |
.unwrap_or(false) | ||
} | ||
|
||
pub async fn contains_used(&self, id: &PresignatureId) -> bool { | ||
self.presignature_storage | ||
.contains_used(id) | ||
.await | ||
.map_err(|e| tracing::warn!(?e, "failed to check if presignature was used")) | ||
.unwrap_or(false) | ||
} | ||
|
||
pub async fn take(&mut self, id: PresignatureId) -> Result<Presignature, GenerationError> { | ||
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.insert_used(presignature.id).await; | ||
self.gc.insert(id, Instant::now()); | ||
tracing::debug!(id, "took presignature"); | ||
return Ok(presignature); | ||
|
@@ -257,6 +295,7 @@ impl PresignatureManager { | |
}) | ||
.ok()? | ||
{ | ||
self.insert_used(presignature.id).await; | ||
tracing::debug!(id = ?presignature.id, "took presignature of mine"); | ||
return Some(presignature); | ||
} | ||
|
@@ -285,6 +324,16 @@ impl PresignatureManager { | |
.unwrap_or(0) | ||
} | ||
|
||
pub async fn len_used(&self) -> usize { | ||
self.presignature_storage | ||
.len_used() | ||
.await | ||
.map_err(|e| { | ||
tracing::error!(?e, "failed to count used presignatures"); | ||
}) | ||
.unwrap_or(0) | ||
} | ||
|
||
/// Returns if there are unspent presignatures available in the manager. | ||
pub async fn is_empty(&self) -> bool { | ||
self.len_generated().await == 0 | ||
|
@@ -433,11 +482,6 @@ impl PresignatureManager { | |
participants = ?presig_participants.keys_vec(), | ||
"running: the intersection of participants is less than the threshold" | ||
); | ||
|
||
// Insert back the triples to be used later since this active set of | ||
// participants were not able to make use of these triples. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think instead of wasting the triples, we can actually change the order of ```
if presig_participants.len() < self.threshold``` |
||
triple_manager.insert_mine(triple0).await; | ||
triple_manager.insert_mine(triple1).await; | ||
} else { | ||
self.generate( | ||
&presig_participants, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -626,7 +626,6 @@ impl SignatureManager { | |
); | ||
return; | ||
} | ||
let mut failed_presigs = Vec::new(); | ||
while let Some(mut presignature) = { | ||
if self.failed.is_empty() && my_requests.is_empty() { | ||
None | ||
|
@@ -640,7 +639,6 @@ impl SignatureManager { | |
participants = ?sig_participants.keys_vec(), | ||
"intersection of stable participants and presignature participants is less than threshold" | ||
); | ||
failed_presigs.push(presignature); | ||
continue; | ||
} | ||
let presig_id = presignature.id; | ||
|
@@ -650,7 +648,7 @@ impl SignatureManager { | |
// when the request made it into the NEAR network. | ||
// issue: https://github.com/near/mpc-recovery/issues/596 | ||
if let Some((sign_request_identifier, failed_req)) = self.failed.pop_front() { | ||
if let Err((presignature, InitializationError::BadParameters(err))) = self | ||
if let Err((_, InitializationError::BadParameters(err))) = self | ||
.retry_failed_generation( | ||
sign_request_identifier.clone(), | ||
failed_req, | ||
|
@@ -665,7 +663,6 @@ impl SignatureManager { | |
?err, | ||
"failed to retry signature generation: trashing presignature" | ||
); | ||
failed_presigs.push(presignature); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if the presignature is not pushed back into storage, then we should not run retry_failed_generation() with the same presignature at all. I think if we don't want to recycle the presignature, then we should pick another unused presignature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is possible |
||
continue; | ||
} | ||
|
||
|
@@ -677,11 +674,10 @@ impl SignatureManager { | |
} | ||
|
||
let Some(my_request) = my_requests.pop_front() else { | ||
failed_presigs.push(presignature); | ||
continue; | ||
}; | ||
|
||
if let Err((presignature, InitializationError::BadParameters(err))) = self.generate( | ||
if let Err((_, InitializationError::BadParameters(err))) = self.generate( | ||
&sig_participants, | ||
my_request.request_id, | ||
presignature, | ||
|
@@ -691,17 +687,10 @@ impl SignatureManager { | |
my_request.time_added, | ||
cfg, | ||
) { | ||
failed_presigs.push(presignature); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here. |
||
tracing::warn!(request_id = ?CryptoHash(my_request.request_id), presig_id, ?err, "failed to start signature generation: trashing presignature"); | ||
continue; | ||
} | ||
} | ||
|
||
// 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).await; | ||
} | ||
} | ||
|
||
pub async fn publish<T: SignerExt>( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ use crate::protocol::presignature::{Presignature, PresignatureId}; | |
type PresigResult<T> = std::result::Result<T, anyhow::Error>; | ||
|
||
// Can be used to "clear" redis storage in case of a breaking change | ||
const PRESIGNATURE_STORAGE_VERSION: &str = "v1"; | ||
const PRESIGNATURE_STORAGE_VERSION: &str = "v2"; | ||
|
||
pub fn init(pool: &Pool, node_account_id: &AccountId) -> PresignatureRedisStorage { | ||
PresignatureRedisStorage { | ||
|
@@ -45,6 +45,14 @@ impl PresignatureRedisStorage { | |
Ok(()) | ||
} | ||
|
||
pub async fn insert_used(&self, id: PresignatureId) -> PresigResult<()> { | ||
let mut connection = self.redis_pool.get().await?; | ||
connection | ||
.sadd::<&str, PresignatureId, ()>(&self.used_key(), id) | ||
.await?; | ||
Ok(()) | ||
} | ||
|
||
pub async fn contains(&self, id: &PresignatureId) -> PresigResult<bool> { | ||
let mut connection = self.redis_pool.get().await?; | ||
let result: bool = connection.hexists(self.presig_key(), id).await?; | ||
|
@@ -57,6 +65,12 @@ impl PresignatureRedisStorage { | |
Ok(result) | ||
} | ||
|
||
pub async fn contains_used(&self, id: &PresignatureId) -> PresigResult<bool> { | ||
let mut connection = self.redis_pool.get().await?; | ||
let result: bool = connection.sismember(self.used_key(), id).await?; | ||
Ok(result) | ||
} | ||
|
||
pub async fn take(&self, id: &PresignatureId) -> PresigResult<Option<Presignature>> { | ||
let mut connection = self.redis_pool.get().await?; | ||
if self.contains_mine(id).await? { | ||
|
@@ -96,10 +110,17 @@ impl PresignatureRedisStorage { | |
Ok(result) | ||
} | ||
|
||
pub async fn len_used(&self) -> PresigResult<usize> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seems like we never clear the used presignatures. So the used presignatures will grow indefinitely as we generate and use more presignatures. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redis allows to add time it will be stored in the DB, we can use that |
||
let mut connection = self.redis_pool.get().await?; | ||
let result: usize = connection.scard(self.used_key()).await?; | ||
Ok(result) | ||
} | ||
|
||
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?; | ||
connection.del::<&str, ()>(&self.used_key()).await?; | ||
Ok(()) | ||
} | ||
|
||
|
@@ -116,6 +137,13 @@ impl PresignatureRedisStorage { | |
PRESIGNATURE_STORAGE_VERSION, self.node_account_id | ||
) | ||
} | ||
|
||
fn used_key(&self) -> String { | ||
format!( | ||
"presignatures_used:{}:{}", | ||
PRESIGNATURE_STORAGE_VERSION, self.node_account_id | ||
) | ||
} | ||
} | ||
|
||
impl ToRedisArgs for Presignature { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ use near_account_id::AccountId; | |
type TripleResult<T> = std::result::Result<T, anyhow::Error>; | ||
|
||
// Can be used to "clear" redis storage in case of a breaking change | ||
const TRIPLE_STORAGE_VERSION: &str = "v1"; | ||
const TRIPLE_STORAGE_VERSION: &str = "v2"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incrementing the storage version here to start from scratch. |
||
|
||
pub fn init(pool: &Pool, account_id: &AccountId) -> TripleRedisStorage { | ||
TripleRedisStorage { | ||
|
@@ -39,6 +39,13 @@ impl TripleRedisStorage { | |
Ok(()) | ||
} | ||
|
||
pub async fn insert_used(&self, id: TripleId) -> TripleResult<()> { | ||
let mut conn = self.redis_pool.get().await?; | ||
conn.sadd::<&str, TripleId, ()>(&self.used_key(), id) | ||
.await?; | ||
Ok(()) | ||
} | ||
|
||
pub async fn contains(&self, id: &TripleId) -> TripleResult<bool> { | ||
let mut conn = self.redis_pool.get().await?; | ||
let result: bool = conn.hexists(self.triple_key(), id).await?; | ||
|
@@ -51,6 +58,12 @@ impl TripleRedisStorage { | |
Ok(result) | ||
} | ||
|
||
pub async fn contains_used(&self, id: &TripleId) -> TripleResult<bool> { | ||
let mut conn = self.redis_pool.get().await?; | ||
let result: bool = conn.sismember(self.used_key(), id).await?; | ||
Ok(result) | ||
} | ||
|
||
pub async fn take(&self, id: &TripleId) -> TripleResult<Option<Triple>> { | ||
let mut conn = self.redis_pool.get().await?; | ||
if self.contains_mine(id).await? { | ||
|
@@ -89,10 +102,17 @@ impl TripleRedisStorage { | |
Ok(result) | ||
} | ||
|
||
pub async fn len_used(&self) -> TripleResult<usize> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same problem as the used presignature. this will grow indefinitely |
||
let mut conn = self.redis_pool.get().await?; | ||
let result: usize = conn.scard(self.used_key()).await?; | ||
Ok(result) | ||
} | ||
|
||
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?; | ||
conn.del::<&str, ()>(&self.used_key()).await?; | ||
Ok(()) | ||
} | ||
|
||
|
@@ -109,6 +129,13 @@ impl TripleRedisStorage { | |
TRIPLE_STORAGE_VERSION, self.node_account_id | ||
) | ||
} | ||
|
||
fn used_key(&self) -> String { | ||
format!( | ||
"triples_used:{}:{}", | ||
TRIPLE_STORAGE_VERSION, self.node_account_id | ||
) | ||
} | ||
} | ||
|
||
impl ToRedisArgs for Triple { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not mine presignature?