Feature/validator api panics (#1520)

* Coconut unwraps

* Fail softly on epoch queries

* Update changelog

* Retry a few times before failing as before
This commit is contained in:
Bogdan-Ștefan Neacşu
2022-08-11 11:58:17 +03:00
committed by GitHub
parent a7afd2a1c7
commit 41ac866729
5 changed files with 66 additions and 19 deletions
+2
View File
@@ -53,6 +53,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
- All binaries and cosmwasm blobs are configured at runtime now; binaries are configured using environment variables or .env files and contracts keep the configuration parameters in storage ([#1463])
- gateway, network-statistics: include gateway id in the sent statistical data ([#1478])
- network explorer: tweak how active set probability is shown ([#1503])
- validator-api: rewarder set update fails without panicking on possible nymd queries ([#1520])
[#1249]: https://github.com/nymtech/nym/pull/1249
@@ -81,6 +82,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
[#1487]: https://github.com/nymtech/nym/pull/1487
[#1496]: https://github.com/nymtech/nym/pull/1496
[#1503]: https://github.com/nymtech/nym/pull/1503
[#1520]: https://github.com/nymtech/nym/pull/1520
## [nym-connect-v1.0.1](https://github.com/nymtech/nym/tree/nym-connect-v1.0.1) (2022-07-22)
+2 -2
View File
@@ -58,6 +58,7 @@ gateway-client = { path="../common/client-libs/gateway-client" }
mixnet-contract-common = { path= "../common/cosmwasm-smart-contracts/mixnet-contract" }
multisig-contract-common = { path = "../common/cosmwasm-smart-contracts/multisig-contract" }
nymsphinx = { path="../common/nymsphinx" }
nymcoconut = { path = "../common/nymcoconut", optional = true }
task = { path = "../common/task" }
topology = { path="../common/topology" }
validator-api-requests = { path = "validator-api-requests" }
@@ -71,7 +72,7 @@ console-subscriber = { version = "0.1.1", optional = true}
cfg-if = "1.0"
[features]
coconut = ["coconut-interface", "credentials", "gateway-client/coconut", "credentials/coconut", "validator-api-requests/coconut"]
coconut = ["coconut-interface", "credentials", "gateway-client/coconut", "credentials/coconut", "validator-api-requests/coconut", "nymcoconut"]
no-reward = []
generate-ts = []
@@ -82,6 +83,5 @@ vergen = { version = "5", default-features = false, features = ["build", "git",
[dev-dependencies]
attohttpc = {version = "0.18.0", features = ["json"]}
nymcoconut = { path = "../common/nymcoconut" }
cw3 = "0.13.2"
cw-utils = "0.13.2"
+3
View File
@@ -31,6 +31,9 @@ pub enum CoconutError {
#[error("Nymd error - {0}")]
NymdError(#[from] NymdError),
#[error("Coconut internal error - {0}")]
CoconutInternalError(#[from] nymcoconut::CoconutError),
#[error("Could not find a deposit event in the transaction provided")]
DepositEventNotFound,
+5 -6
View File
@@ -192,15 +192,14 @@ impl InternalSignRequest {
}
}
fn blind_sign(request: InternalSignRequest, key_pair: &KeyPair) -> BlindedSignature {
let params = Parameters::new(request.total_params()).unwrap();
coconut_interface::blind_sign(
fn blind_sign(request: InternalSignRequest, key_pair: &KeyPair) -> Result<BlindedSignature> {
let params = Parameters::new(request.total_params())?;
Ok(coconut_interface::blind_sign(
&params,
&key_pair.secret_key(),
request.blind_sign_request(),
request.public_attributes(),
)
.unwrap()
)?)
}
#[post("/blind-sign", data = "<blind_sign_request_body>")]
@@ -226,7 +225,7 @@ pub async fn post_blind_sign(
blind_sign_request_body.public_attributes(),
blind_sign_request_body.blind_sign_request().clone(),
);
let blinded_signature = blind_sign(internal_request, &state.key_pair);
let blinded_signature = blind_sign(internal_request, &state.key_pair)?;
let response = state
.encrypt_and_store(
+54 -11
View File
@@ -22,6 +22,7 @@ use mixnet_contract_common::{IdentityKey, Interval, MixNodeBond};
use rand::prelude::SliceRandom;
use rand::rngs::OsRng;
use std::collections::HashSet;
use std::ops::Deref;
use std::time::Duration;
use time::OffsetDateTime;
use tokio::time::sleep;
@@ -58,7 +59,44 @@ impl MixnodeToReward {
}
// Epoch has all the same semantics as interval, but has a lower set duration
type Epoch = Interval;
pub struct Epoch(Interval);
impl Epoch {
pub(crate) async fn update_to_latest(
&mut self,
rewarded_set_updater: &RewardedSetUpdater,
) -> Result<(), RewardingError> {
let mut wait_time = 2;
let mut ret = Ok(());
for _ in 0..3 {
match rewarded_set_updater.nymd_client.get_current_epoch().await {
Ok(epoch) => {
*self = Epoch(epoch);
return Ok(());
}
Err(e) => {
warn!(
"Could not update epoch: {:?}. Retrying again in {} seconds",
e, wait_time
);
ret = Err(e);
}
};
sleep(Duration::from_secs(wait_time)).await;
wait_time *= wait_time;
}
error!("Failed to update epoch. Exiting now");
Ok(ret?)
}
}
impl Deref for Epoch {
type Target = Interval;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub struct RewardedSetUpdater {
nymd_client: Client<SigningNymdClient>,
@@ -68,7 +106,7 @@ pub struct RewardedSetUpdater {
impl RewardedSetUpdater {
pub(crate) async fn epoch(&self) -> Result<Epoch, RewardingError> {
Ok(self.nymd_client.get_current_epoch().await?)
Ok(Epoch(self.nymd_client.get_current_epoch().await?))
}
pub(crate) async fn new(
@@ -120,9 +158,10 @@ impl RewardedSetUpdater {
async fn reward_current_rewarded_set(
&self,
epoch: &mut Epoch,
) -> Result<Vec<(ExecuteMsg, Vec<Coin>)>, RewardingError> {
let to_reward = self.nodes_to_reward().await?;
let epoch = self.epoch().await?;
let to_reward = self.nodes_to_reward(epoch).await?;
epoch.update_to_latest(self).await?;
// self.storage.insert_started_epoch_rewarding(epoch).await?;
@@ -157,8 +196,11 @@ impl RewardedSetUpdater {
}
}
async fn nodes_to_reward(&self) -> Result<Vec<MixnodeToReward>, RewardingError> {
let epoch = self.epoch().await?;
async fn nodes_to_reward(
&self,
epoch: &mut Epoch,
) -> Result<Vec<MixnodeToReward>, RewardingError> {
epoch.update_to_latest(self).await?;
let active_set = self
.validator_cache
.active_set_detailed()
@@ -200,8 +242,8 @@ impl RewardedSetUpdater {
}
// This is where the epoch gets advanced, and all epoch related transactions originate
async fn update(&self) -> Result<(), RewardingError> {
let epoch = self.epoch().await?;
async fn update(&self, epoch: &mut Epoch) -> Result<(), RewardingError> {
epoch.update_to_latest(self).await?;
log::info!("Starting rewarded set update");
// we know the entries are not stale, as a matter of fact they were JUST updated, since we got notified
let all_nodes = self.validator_cache.mixnodes().await;
@@ -218,7 +260,7 @@ impl RewardedSetUpdater {
// log::info!("Rewarded current rewarded set... SUCCESS");
// }
let reward_msgs = self.reward_current_rewarded_set().await?;
let reward_msgs = self.reward_current_rewarded_set(epoch).await?;
let rewarded_set_size = epoch_reward_params.rewarded_set_size() as u32;
let active_set_size = epoch_reward_params.active_set_size() as u32;
@@ -288,11 +330,12 @@ impl RewardedSetUpdater {
pub(crate) async fn run(&mut self) -> Result<(), RewardingError> {
self.validator_cache.wait_for_initial_values().await;
let mut epoch = self.epoch().await?;
loop {
// wait until the cache refresher determined its time to update the rewarded/active sets
let time = OffsetDateTime::now_utc().unix_timestamp();
let epoch = self.epoch().await?;
epoch.update_to_latest(self).await?;
let time_to_epoch_change = epoch.end_unix_timestamp() - time;
if time_to_epoch_change <= 0 {
self.update_blacklist(&epoch).await?;
@@ -300,7 +343,7 @@ impl RewardedSetUpdater {
"Time to epoch change is {}, updating rewarded set",
time_to_epoch_change
);
self.update().await?;
self.update(&mut epoch).await?;
} else {
log::info!(
"Waiting for epoch change, time to epoch change is {}",