Feature/rewarding interval updates (#880)
* Introduced rewarding_interval_nonce to contract state * Queries for ibid. * Mixnode demanded set size * Routes for obtaining demanded/active mixnode sets * Testing only demanded nodes * Typo * Initial state * Feature-locking unused imports * Generating pseudorandom (with deterministic seed) demanded mixnodes set * cargo fmt * Fixed tauri state * Renamed network monitor address to the rewarding validator * [ci skip] Generate TS types * Notice for the future * Transactions to begin/finish mixnode rewarding + double rewarding protection * Validator API using new contract calls * Removed dead code from an old experiment * [ci skip] Generate TS types * Removed unused import * Renamed 'demanded' set to 'rewarded' set * Some renaming action * [ci skip] Generate TS types * Fixed post-merge dependency issue in tests * Post merge test fix Co-authored-by: jstuczyn <jstuczyn@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
04636a569a
commit
7e1cf2f105
@@ -23,10 +23,11 @@ pub enum Operation {
|
||||
|
||||
BondGateway,
|
||||
UnbondGateway,
|
||||
DelegateToGateway,
|
||||
UndelegateFromGateway,
|
||||
|
||||
UpdateStateParams,
|
||||
|
||||
BeginMixnodeRewarding,
|
||||
FinishMixnodeRewarding,
|
||||
}
|
||||
|
||||
pub(crate) fn calculate_fee(gas_price: &GasPrice, gas_limit: Gas) -> Coin {
|
||||
@@ -43,13 +44,13 @@ impl fmt::Display for Operation {
|
||||
Operation::Send => f.write_str("Send"),
|
||||
Operation::BondMixnode => f.write_str("BondMixnode"),
|
||||
Operation::UnbondMixnode => f.write_str("UnbondMixnode"),
|
||||
Operation::DelegateToMixnode => f.write_str("DelegateToMixnode"),
|
||||
Operation::UndelegateFromMixnode => f.write_str("UndelegateFromMixnode"),
|
||||
Operation::BondGateway => f.write_str("BondGateway"),
|
||||
Operation::UnbondGateway => f.write_str("UnbondGateway"),
|
||||
Operation::DelegateToGateway => f.write_str("DelegateToGateway"),
|
||||
Operation::UndelegateFromGateway => f.write_str("UndelegateFromGateway"),
|
||||
Operation::DelegateToMixnode => f.write_str("DelegateToMixnode"),
|
||||
Operation::UndelegateFromMixnode => f.write_str("UndelegateFromMixnode"),
|
||||
Operation::UpdateStateParams => f.write_str("UpdateStateParams"),
|
||||
Operation::BeginMixnodeRewarding => f.write_str("BeginMixnodeRewarding"),
|
||||
Operation::FinishMixnodeRewarding => f.write_str("FinishMixnodeRewarding"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,10 +72,10 @@ impl Operation {
|
||||
|
||||
Operation::BondGateway => 175_000u64.into(),
|
||||
Operation::UnbondGateway => 175_000u64.into(),
|
||||
Operation::DelegateToGateway => 175_000u64.into(),
|
||||
Operation::UndelegateFromGateway => 175_000u64.into(),
|
||||
|
||||
Operation::UpdateStateParams => 175_000u64.into(),
|
||||
Operation::BeginMixnodeRewarding => 175_000u64.into(),
|
||||
Operation::FinishMixnodeRewarding => 175_000u64.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -711,6 +711,54 @@ impl<C> NymdClient<C> {
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn begin_mixnode_rewarding(
|
||||
&self,
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> Result<ExecuteResult, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
let fee = self.get_fee(Operation::BeginMixnodeRewarding);
|
||||
|
||||
let req = ExecuteMsg::BeginMixnodeRewarding {
|
||||
rewarding_interval_nonce,
|
||||
};
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"Beginning mixnode rewarding procedure",
|
||||
Vec::new(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn finish_mixnode_rewarding(
|
||||
&self,
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> Result<ExecuteResult, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
let fee = self.get_fee(Operation::FinishMixnodeRewarding);
|
||||
|
||||
let req = ExecuteMsg::FinishMixnodeRewarding {
|
||||
rewarding_interval_nonce,
|
||||
};
|
||||
self.client
|
||||
.execute(
|
||||
self.address(),
|
||||
self.contract_address()?,
|
||||
&req,
|
||||
fee,
|
||||
"Finishing mixnode rewarding procedure",
|
||||
Vec::new(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
fn cosmwasm_coin_to_cosmos_coin(coin: Coin) -> CosmosCoin {
|
||||
|
||||
@@ -32,16 +32,32 @@ pub enum ExecuteMsg {
|
||||
mix_identity: IdentityKey,
|
||||
},
|
||||
|
||||
BeginMixnodeRewarding {
|
||||
// nonce of the current rewarding interval
|
||||
rewarding_interval_nonce: u32,
|
||||
},
|
||||
|
||||
RewardMixnode {
|
||||
identity: IdentityKey,
|
||||
// percentage value in range 0-100
|
||||
uptime: u32,
|
||||
|
||||
// nonce of the current rewarding interval
|
||||
rewarding_interval_nonce: u32,
|
||||
},
|
||||
|
||||
FinishMixnodeRewarding {
|
||||
// nonce of the current rewarding interval
|
||||
rewarding_interval_nonce: u32,
|
||||
},
|
||||
|
||||
RewardMixnodeV2 {
|
||||
identity: IdentityKey,
|
||||
// percentage value in range 0-100
|
||||
params: NodeRewardParams,
|
||||
|
||||
// nonce of the current rewarding interval
|
||||
rewarding_interval_nonce: u32,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ impl LayerDistribution {
|
||||
#[derive(Debug, Default, Serialize, Deserialize, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct RewardingIntervalResponse {
|
||||
pub current_rewarding_interval_starting_block: u64,
|
||||
pub current_rewarding_interval_nonce: u32,
|
||||
pub rewarding_in_progress: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ pub fn default_api_endpoints() -> Vec<Url> {
|
||||
}
|
||||
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = "punk10pyejy66429refv3g35g2t7am0was7yalwrzen";
|
||||
pub const NETWORK_MONITOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
|
||||
pub const REWARDING_VALIDATOR_ADDRESS: &str = "punk1v9qauwdq5terag6uvfsdytcs2d0sdmfdy7hgk3";
|
||||
|
||||
/// How much bandwidth (in bytes) one token can buy
|
||||
const BYTES_PER_TOKEN: u64 = 1024 * 1024 * 1024;
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::helpers::calculate_epoch_reward_rate;
|
||||
use crate::state::State;
|
||||
use crate::storage::{config, layer_distribution};
|
||||
use crate::{error::ContractError, queries, transactions};
|
||||
use config::defaults::NETWORK_MONITOR_ADDRESS;
|
||||
use config::defaults::REWARDING_VALIDATOR_ADDRESS;
|
||||
use cosmwasm_std::{
|
||||
entry_point, to_binary, Addr, Decimal, Deps, DepsMut, Env, MessageInfo, QueryResponse,
|
||||
Response, Uint128,
|
||||
@@ -42,7 +42,7 @@ fn default_initial_state(owner: Addr, env: Env) -> State {
|
||||
|
||||
State {
|
||||
owner,
|
||||
network_monitor_address: Addr::unchecked(NETWORK_MONITOR_ADDRESS), // we trust our hardcoded value
|
||||
rewarding_validator_address: Addr::unchecked(REWARDING_VALIDATOR_ADDRESS), // we trust our hardcoded value
|
||||
params: StateParams {
|
||||
epoch_length: INITIAL_DEFAULT_EPOCH_LENGTH,
|
||||
minimum_mixnode_bond: INITIAL_MIXNODE_BOND,
|
||||
@@ -53,6 +53,7 @@ fn default_initial_state(owner: Addr, env: Env) -> State {
|
||||
mixnode_active_set_size: INITIAL_MIXNODE_ACTIVE_SET_SIZE,
|
||||
},
|
||||
rewarding_interval_starting_block: env.block.height,
|
||||
latest_rewarding_interval_nonce: 0,
|
||||
rewarding_in_progress: false,
|
||||
mixnode_epoch_bond_reward: calculate_epoch_reward_rate(
|
||||
INITIAL_DEFAULT_EPOCH_LENGTH,
|
||||
@@ -104,18 +105,42 @@ pub fn execute(
|
||||
ExecuteMsg::UpdateStateParams(params) => {
|
||||
transactions::try_update_state_params(deps, info, params)
|
||||
}
|
||||
ExecuteMsg::RewardMixnode { identity, uptime } => {
|
||||
transactions::try_reward_mixnode(deps, env, info, identity, uptime)
|
||||
}
|
||||
ExecuteMsg::RewardMixnodeV2 { identity, params } => {
|
||||
transactions::try_reward_mixnode_v2(deps, env, info, identity, params)
|
||||
}
|
||||
ExecuteMsg::RewardMixnode {
|
||||
identity,
|
||||
uptime,
|
||||
rewarding_interval_nonce,
|
||||
} => transactions::try_reward_mixnode(
|
||||
deps,
|
||||
env,
|
||||
info,
|
||||
identity,
|
||||
uptime,
|
||||
rewarding_interval_nonce,
|
||||
),
|
||||
ExecuteMsg::RewardMixnodeV2 {
|
||||
identity,
|
||||
params,
|
||||
rewarding_interval_nonce,
|
||||
} => transactions::try_reward_mixnode_v2(
|
||||
deps,
|
||||
env,
|
||||
info,
|
||||
identity,
|
||||
params,
|
||||
rewarding_interval_nonce,
|
||||
),
|
||||
ExecuteMsg::DelegateToMixnode { mix_identity } => {
|
||||
transactions::try_delegate_to_mixnode(deps, env, info, mix_identity)
|
||||
}
|
||||
ExecuteMsg::UndelegateFromMixnode { mix_identity } => {
|
||||
transactions::try_remove_delegation_from_mixnode(deps, info, mix_identity)
|
||||
}
|
||||
ExecuteMsg::BeginMixnodeRewarding {
|
||||
rewarding_interval_nonce,
|
||||
} => transactions::try_begin_mixnode_rewarding(deps, env, info, rewarding_interval_nonce),
|
||||
ExecuteMsg::FinishMixnodeRewarding {
|
||||
rewarding_interval_nonce,
|
||||
} => transactions::try_finish_mixnode_rewarding(deps, info, rewarding_interval_nonce),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,4 +88,16 @@ pub enum ContractError {
|
||||
|
||||
#[error("Invalid ratio")]
|
||||
Ratio(#[from] mixnet_contract::error::MixnetContractError),
|
||||
|
||||
#[error("Received invalid rewarding interval nonce. Expected {expected}, received {received}")]
|
||||
InvalidRewardingIntervalNonce { received: u32, expected: u32 },
|
||||
|
||||
#[error("Rewarding distribution is currently in progress")]
|
||||
RewardingInProgress,
|
||||
|
||||
#[error("Rewarding distribution is currently not in progress")]
|
||||
RewardingNotInProgress,
|
||||
|
||||
#[error("Mixnode {identity} has already been rewarded during the current rewarding interval")]
|
||||
MixnodeAlreadyRewarded { identity: IdentityKey },
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ pub(crate) fn query_rewarding_interval(deps: Deps) -> RewardingIntervalResponse
|
||||
let state = config_read(deps.storage).load().unwrap();
|
||||
RewardingIntervalResponse {
|
||||
current_rewarding_interval_starting_block: state.rewarding_interval_starting_block,
|
||||
current_rewarding_interval_nonce: state.latest_rewarding_interval_nonce,
|
||||
rewarding_in_progress: state.rewarding_in_progress,
|
||||
}
|
||||
}
|
||||
@@ -578,7 +579,7 @@ pub(crate) mod tests {
|
||||
|
||||
let dummy_state = State {
|
||||
owner: Addr::unchecked("someowner"),
|
||||
network_monitor_address: Addr::unchecked("monitor"),
|
||||
rewarding_validator_address: Addr::unchecked("monitor"),
|
||||
params: StateParams {
|
||||
epoch_length: 1,
|
||||
minimum_mixnode_bond: 123u128.into(),
|
||||
@@ -589,6 +590,7 @@ pub(crate) mod tests {
|
||||
mixnode_active_set_size: 500,
|
||||
},
|
||||
rewarding_interval_starting_block: 123,
|
||||
latest_rewarding_interval_nonce: 0,
|
||||
rewarding_in_progress: false,
|
||||
mixnode_epoch_bond_reward: "1.23".parse().unwrap(),
|
||||
mixnode_epoch_delegation_reward: "7.89".parse().unwrap(),
|
||||
|
||||
@@ -9,13 +9,14 @@ use serde::{Deserialize, Serialize};
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||
pub struct State {
|
||||
pub owner: Addr, // only the owner account can update state
|
||||
pub network_monitor_address: Addr,
|
||||
pub rewarding_validator_address: Addr,
|
||||
pub params: StateParams,
|
||||
|
||||
// keep track of the changes to the current rewarding interval,
|
||||
// i.e. at which block has the latest rewarding occurred
|
||||
// and whether another run is already in progress
|
||||
pub rewarding_interval_starting_block: u64,
|
||||
pub latest_rewarding_interval_nonce: u32,
|
||||
pub rewarding_in_progress: bool,
|
||||
|
||||
// helper values to avoid having to recalculate them on every single payment operation
|
||||
|
||||
@@ -37,6 +37,8 @@ const PREFIX_GATEWAYS_OWNERS: &[u8] = b"go";
|
||||
const PREFIX_MIX_DELEGATION: &[u8] = b"md";
|
||||
const PREFIX_REVERSE_MIX_DELEGATION: &[u8] = b"dm";
|
||||
|
||||
const PREFIX_REWARDED_MIXNODES: &[u8] = b"rm";
|
||||
|
||||
// Contract-level stuff
|
||||
|
||||
// TODO Unify bucket and mixnode storage functions
|
||||
@@ -103,22 +105,6 @@ pub(crate) fn read_state_params(storage: &dyn Storage) -> StateParams {
|
||||
config_read(storage).load().unwrap().params
|
||||
}
|
||||
|
||||
pub(crate) fn read_mixnode_epoch_bond_reward_rate(storage: &dyn Storage) -> Decimal {
|
||||
// same justification as in `read_state_params` for the unwrap
|
||||
config_read(storage)
|
||||
.load()
|
||||
.unwrap()
|
||||
.mixnode_epoch_bond_reward
|
||||
}
|
||||
|
||||
pub(crate) fn read_mixnode_epoch_delegation_reward_rate(storage: &dyn Storage) -> Decimal {
|
||||
// same justification as in `read_state_params` for the unwrap
|
||||
config_read(storage)
|
||||
.load()
|
||||
.unwrap()
|
||||
.mixnode_epoch_delegation_reward
|
||||
}
|
||||
|
||||
pub fn layer_distribution(storage: &mut dyn Storage) -> Singleton<LayerDistribution> {
|
||||
singleton(storage, LAYER_DISTRIBUTION_KEY)
|
||||
}
|
||||
@@ -196,6 +182,35 @@ pub fn mixnodes_owners_read(storage: &dyn Storage) -> ReadonlyBucket<IdentityKey
|
||||
bucket_read(storage, PREFIX_MIXNODES_OWNERS)
|
||||
}
|
||||
|
||||
// we want to treat this bucket as a set so we don't really care about what type of data is being stored.
|
||||
// I went with u8 as after serialization it takes only a single byte of space, while if a `()` was used,
|
||||
// it would have taken 4 bytes (representation of 'null')
|
||||
pub fn rewarded_mixnodes(storage: &mut dyn Storage, rewarding_interval_nonce: u32) -> Bucket<u8> {
|
||||
Bucket::multilevel(
|
||||
storage,
|
||||
&[
|
||||
rewarding_interval_nonce.to_be_bytes().as_ref(),
|
||||
PREFIX_REWARDED_MIXNODES,
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
// we want to treat this bucket as a set so we don't really care about what type of data is being stored.
|
||||
// I went with u8 as after serialization it takes only a single byte of space, while if a `()` was used,
|
||||
// it would have taken 4 bytes (representation of 'null')
|
||||
pub fn rewarded_mixnodes_read(
|
||||
storage: &dyn Storage,
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> ReadonlyBucket<u8> {
|
||||
ReadonlyBucket::multilevel(
|
||||
storage,
|
||||
&[
|
||||
rewarding_interval_nonce.to_be_bytes().as_ref(),
|
||||
PREFIX_REWARDED_MIXNODES,
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
// helpers
|
||||
pub(crate) fn increase_mix_delegated_stakes(
|
||||
storage: &mut dyn Storage,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,6 @@ export type Operation =
|
||||
| "UndelegateFromMixnode"
|
||||
| "BondGateway"
|
||||
| "UnbondGateway"
|
||||
| "DelegateToGateway"
|
||||
| "UndelegateFromGateway"
|
||||
| "UpdateStateParams";
|
||||
| "UpdateStateParams"
|
||||
| "BeginMixnodeRewarding"
|
||||
| "FinishMixnodeRewarding";
|
||||
Vendored
+10
@@ -162,6 +162,16 @@ impl ValidatorCache {
|
||||
})
|
||||
}
|
||||
|
||||
// NOTE: this does not guarantee consistent results between multiple validator APIs, because
|
||||
// currently we do not guarantee the list of mixnodes (i.e. `mixnodes: &[MixNodeBond]`) will be the same -
|
||||
// somebody might bond/unbond a node or change delegation between different cache refreshes.
|
||||
//
|
||||
// I guess that's not a problem right now and we can resolve it later. My idea for that would be as follows:
|
||||
// since the demanded set changes only monthly, just write the identities of those nodes to the smart
|
||||
// contract upon finished rewarding (this works under assumption of rewards being distributed by a single validator)
|
||||
//
|
||||
// alternatively we could have some state locking mechanism for the duration of determining the demanded set
|
||||
// this could work with multiple validators via some multisig mechanism
|
||||
fn determine_rewarded_set(
|
||||
&self,
|
||||
mixnodes: &[MixNodeBond],
|
||||
|
||||
@@ -203,9 +203,42 @@ impl<C> Client<C> {
|
||||
.calculate_custom_fee(total_gas_limit)
|
||||
}
|
||||
|
||||
pub(crate) async fn begin_mixnode_rewarding(
|
||||
&self,
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> Result<(), RewardingError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
self.0
|
||||
.write()
|
||||
.await
|
||||
.nymd
|
||||
.begin_mixnode_rewarding(rewarding_interval_nonce)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn finish_mixnode_rewarding(
|
||||
&self,
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> Result<(), RewardingError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
{
|
||||
self.0
|
||||
.write()
|
||||
.await
|
||||
.nymd
|
||||
.finish_mixnode_rewarding(rewarding_interval_nonce)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn reward_mixnodes(
|
||||
&self,
|
||||
nodes: &[MixnodeToReward],
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> Result<(), RewardingError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
@@ -216,7 +249,7 @@ impl<C> Client<C> {
|
||||
.await;
|
||||
let msgs: Vec<(ExecuteMsg, _)> = nodes
|
||||
.iter()
|
||||
.map(Into::into)
|
||||
.map(|node| node.to_execute_msg(rewarding_interval_nonce))
|
||||
.zip(std::iter::repeat(Vec::new()))
|
||||
.collect();
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ pub(crate) struct MixnodeToReward {
|
||||
|
||||
impl MixnodeToReward {
|
||||
/// Somewhat clumsy way of feature gatting tokenomics payments. In a tokenomics scenario this will never be None at reward time. We levarage that to Into a different ExecuteMsg variant
|
||||
// TODO: to re-integrate in another PR that combines rewarded/active sets with tokenomics
|
||||
#[allow(dead_code)]
|
||||
fn params(&self) -> Option<NodeRewardParams> {
|
||||
if cfg!(feature = "tokenomics") {
|
||||
self.params
|
||||
@@ -64,6 +66,26 @@ impl MixnodeToReward {
|
||||
}
|
||||
}
|
||||
|
||||
impl MixnodeToReward {
|
||||
pub(crate) fn to_execute_msg(&self, rewarding_interval_nonce: u32) -> ExecuteMsg {
|
||||
ExecuteMsg::RewardMixnode {
|
||||
identity: self.identity.clone(),
|
||||
uptime: self.uptime.u8() as u32,
|
||||
rewarding_interval_nonce,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: to re-integrate in another PR that combines rewarded/active sets with tokenomics
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn to_execute_msg_v2(&self, rewarding_interval_nonce: u32) -> ExecuteMsg {
|
||||
ExecuteMsg::RewardMixnodeV2 {
|
||||
identity: self.identity.clone(),
|
||||
params: self.params().unwrap(),
|
||||
rewarding_interval_nonce,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct FailedMixnodeRewardChunkDetails {
|
||||
possibly_unrewarded: Vec<MixnodeToReward>,
|
||||
error_message: String,
|
||||
@@ -74,22 +96,6 @@ pub(crate) struct FailureData {
|
||||
mixnodes: Option<Vec<FailedMixnodeRewardChunkDetails>>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a MixnodeToReward> for ExecuteMsg {
|
||||
fn from(node: &MixnodeToReward) -> Self {
|
||||
if let Some(params) = node.params() {
|
||||
ExecuteMsg::RewardMixnodeV2 {
|
||||
identity: node.identity.clone(),
|
||||
params,
|
||||
}
|
||||
} else {
|
||||
ExecuteMsg::RewardMixnode {
|
||||
identity: node.identity.clone(),
|
||||
uptime: node.uptime.u8() as u32,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Rewarder {
|
||||
nymd_client: Client<SigningNymdClient>,
|
||||
validator_cache: ValidatorCache,
|
||||
@@ -285,14 +291,20 @@ impl Rewarder {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `eligible_mixnodes`: list of the nodes that are eligible to receive non-zero rewards.
|
||||
/// * `rewarding_interval_nonce`: nonce associated with the current rewarding interval
|
||||
async fn distribute_rewards_to_mixnodes(
|
||||
&self,
|
||||
eligible_mixnodes: &[MixnodeToReward],
|
||||
rewarding_interval_nonce: u32,
|
||||
) -> Option<Vec<FailedMixnodeRewardChunkDetails>> {
|
||||
let mut failed_chunks = Vec::new();
|
||||
|
||||
for (i, mix_chunk) in eligible_mixnodes.chunks(MAX_TO_REWARD_AT_ONCE).enumerate() {
|
||||
if let Err(err) = self.nymd_client.reward_mixnodes(mix_chunk).await {
|
||||
if let Err(err) = self
|
||||
.nymd_client
|
||||
.reward_mixnodes(mix_chunk, rewarding_interval_nonce)
|
||||
.await
|
||||
{
|
||||
// this is a super weird edge case that we didn't catch change to sequence and
|
||||
// resent rewards unnecessarily, but the mempool saved us from executing it again
|
||||
// however, still we want to wait until we're sure we're into the next block
|
||||
@@ -327,13 +339,13 @@ impl Rewarder {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `epoch_rewarding_id`: id of the current epoch rewarding.
|
||||
/// * `epoch_rewarding_id`: id of the current epoch rewarding as stored in the databse.
|
||||
///
|
||||
/// * `active_monitor_mixnodes`: list of the nodes that were tested at least once by the network monitor
|
||||
/// in the last epoch.
|
||||
async fn distribute_rewards(
|
||||
&self,
|
||||
epoch_rewarding_id: i64,
|
||||
epoch_rewarding_database_id: i64,
|
||||
active_monitor_mixnodes: &[MixnodeStatusReport],
|
||||
) -> Result<(RewardingReport, Option<FailureData>), RewardingError> {
|
||||
let mut failure_data = FailureData::default();
|
||||
@@ -345,12 +357,20 @@ impl Rewarder {
|
||||
return Err(RewardingError::NoMixnodesToReward);
|
||||
}
|
||||
|
||||
let current_rewarding_nonce = self
|
||||
.nymd_client
|
||||
.get_current_rewarding_interval()
|
||||
.await?
|
||||
.current_rewarding_interval_nonce;
|
||||
self.nymd_client
|
||||
.begin_mixnode_rewarding(current_rewarding_nonce + 1)
|
||||
.await?;
|
||||
failure_data.mixnodes = self
|
||||
.distribute_rewards_to_mixnodes(&eligible_mixnodes)
|
||||
.distribute_rewards_to_mixnodes(&eligible_mixnodes, current_rewarding_nonce + 1)
|
||||
.await;
|
||||
|
||||
let report = RewardingReport {
|
||||
epoch_rewarding_id,
|
||||
epoch_rewarding_id: epoch_rewarding_database_id,
|
||||
eligible_mixnodes: eligible_mixnodes.len() as i64,
|
||||
possibly_unrewarded_mixnodes: failure_data
|
||||
.mixnodes
|
||||
@@ -364,6 +384,10 @@ impl Rewarder {
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
|
||||
self.nymd_client
|
||||
.finish_mixnode_rewarding(current_rewarding_nonce + 1)
|
||||
.await?;
|
||||
|
||||
if failure_data.mixnodes.is_none() {
|
||||
Ok((report, None))
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user