Skip to content

Commit

Permalink
Merge pull request #25 from lidofinance/curation
Browse files Browse the repository at this point in the history
  • Loading branch information
xhjkl committed Aug 3, 2023
2 parents 3eaab33 + a03b3bc commit 7cfaa21
Show file tree
Hide file tree
Showing 34 changed files with 2,621 additions and 794 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
submodules: true
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.60.0
toolchain: 1.66.1
override: true
components: rustfmt

Expand Down Expand Up @@ -50,7 +50,7 @@ jobs:
submodules: true
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.60.0
toolchain: 1.66.1
override: true

- name: cache-build-artifacts
Expand Down Expand Up @@ -138,7 +138,7 @@ jobs:
submodules: true
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.60.0
toolchain: 1.66.1
override: true
components: rustfmt, clippy

Expand Down Expand Up @@ -183,4 +183,4 @@ jobs:
- name: Check license compatibility
run: |
scripts/check_licenses.py
scripts/check_licenses.py
9 changes: 8 additions & 1 deletion cli/common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use solana_client::client_error::{ClientError, ClientErrorKind};
use solana_client::rpc_request::{RpcError, RpcResponseErrorData};
use solana_program::instruction::InstructionError;
use solana_program::program_error::ProgramError;
use solana_program::pubkey::PubkeyError;
use solana_program::pubkey::{ParsePubkeyError, PubkeyError};
use solana_sdk::hash::ParseHashError;
use solana_sdk::pubkey::Pubkey;
use solana_sdk::signer::presigner::PresignerError;
Expand Down Expand Up @@ -88,6 +88,13 @@ impl AsPrettyError for MaintenanceError {
}
}

impl AsPrettyError for ParsePubkeyError {
fn print_pretty(&self) {
print_red("Could parse a Pubkey:");
println!(" {:?}", self);
}
}

/// Something went wrong either while reading CLI arguments, or while using them.
///
/// This can be a user error (e.g. an invalid Ledger path), or it can be something
Expand Down
1 change: 1 addition & 0 deletions cli/common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use snapshot::SnapshotError;

pub mod error;
pub mod per64;
pub mod prometheus;
pub mod snapshot;
pub mod validator_info_utils;
Expand Down
68 changes: 68 additions & 0 deletions cli/common/src/per64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::ops::{Div, Mul};

/// Scale the fraction of `numerator / denominator`
/// to the range of `[0..u64::MAX]` and return just the numerator.
pub fn per64(numerator: u64, denominator: u64) -> u64 {
let numerator = numerator as u128;
let denominator = denominator as u128;
let range_max = u64::MAX as u128;
let result = numerator.mul(range_max).div(denominator);
assert!(result <= range_max);
result as u64
}

/// `per64` equal to `percentage` percents.
pub fn from_percentage(percentage: u64) -> u64 {
per64(percentage, 100)
}

/// Fraction equal to the given `per64`.
pub fn to_f64(x: u64) -> f64 {
let per64 = x as f64;
let range_max = u64::MAX as f64;
per64 / range_max
}

/// Parse a string like "50.5" into a `per64`.
pub fn parse_from_fractional_percentage(s: &str) -> Result<u64, &'static str> {
let percentage = s
.parse::<f64>()
.map_err(|_| "expected a percentage, like `6.9`")?;
if !(0.0..=100.0).contains(&percentage) {
return Err("expected a percentage between 0 and 100");
}
let part = percentage / 100.0;
let range_max = u64::MAX as f64;
let x = part * range_max;
let x = x as u64;
Ok(x)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn roundtrip() {
assert_eq!(per64(0, 100), 0);
assert_eq!(per64(1, 100), 184467440737095516);
assert_eq!(per64(50, 100), 9223372036854775807);
assert_eq!(per64(100, 100), 18446744073709551615);
}

#[test]
fn percentage() {
assert_eq!(from_percentage(0), 0);
assert_eq!(from_percentage(1), 184467440737095516);
assert_eq!(from_percentage(50), 9223372036854775807);
assert_eq!(from_percentage(100), 18446744073709551615);
}

#[test]
fn floats() {
assert!((to_f64(0) - 0.00).abs() < 0.001);
assert!((to_f64(184467440737095516) - 0.01).abs() < 0.001);
assert!((to_f64(9223372036854775807) - 0.5).abs() < 0.001);
assert!((to_f64(18446744073709551615) - 1.0).abs() < 0.001);
}
}
40 changes: 40 additions & 0 deletions cli/common/src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ use spl_token::solana_program::hash::Hash;
use crate::error::{
self, Error, MissingAccountError, MissingValidatorInfoError, SerializationError,
};
use crate::per64::per64;
use crate::validator_info_utils::ValidatorInfo;

pub enum SnapshotError {
Expand Down Expand Up @@ -216,6 +217,45 @@ impl<'a> Snapshot<'a> {
}
}

/// Get a map of validator identities to a numerator of their block production rate.
/// It's like percentage, but it's per-2^64.
pub fn get_all_block_production_rates(&self) -> crate::Result<HashMap<Pubkey, u64>> {
assert!(std::mem::size_of::<u64>() >= std::mem::size_of::<usize>());

let response = self
.rpc_client
.get_block_production()
.map_err(|err| {
let wrapped_err = Error::from(err);
let result: Error = Box::new(wrapped_err);
result
})?
.value;

// Map the keys from textual form returned by the RPC to the decoded `Pubkey`,
// and the values to the rate.
let rates_of = response
.by_identity
.into_iter()
.map(|(key, (leader_slots, blocks_produced))| {
Pubkey::from_str(&key).map(|key| {
let rate = if blocks_produced > 0 {
per64(leader_slots as u64, blocks_produced as u64)
} else {
0
};
(key, rate)
})
})
.collect::<Result<HashMap<_, _>, _>>()
.map_err(|err| {
let result: Error = Box::new(err);
result
})?;

Ok(rates_of)
}

/// Get list of accounts of type T from Solido
pub fn get_account_list<T: ListEntry>(
&mut self,
Expand Down
2 changes: 1 addition & 1 deletion cli/listener/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ fn start_http_server(opts: &Opts, metrics_mutex: Arc<MetricsMutex>) -> Vec<JoinH
for request in server_clone.incoming_requests() {
// Ignore any errors; if we fail to respond, then there's little
// we can do about it here ... the client should just retry.
let _ = serve_request(&conn, request, &*snapshot_mutex_clone);
let _ = serve_request(&conn, request, &snapshot_mutex_clone);
}
})
.expect("Failed to spawn http handler thread.")
Expand Down
1 change: 1 addition & 0 deletions cli/maintainer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ description = "Solido Command-line Utility"
license = "GPL-3.0"
edition = "2018"
name = "solido-cli"
default-run = "solido"
version = "1.3.6"

[dependencies]
Expand Down
39 changes: 23 additions & 16 deletions cli/maintainer/src/commands_multisig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,10 @@ use solana_sdk::sysvar;

use lido::{
instruction::{
AddMaintainerMetaV2, AddValidatorMetaV2, ChangeRewardDistributionMeta,
AddMaintainerMetaV2, AddValidatorMetaV2, ChangeCriteriaMeta, ChangeRewardDistributionMeta,
DeactivateValidatorMetaV2, LidoInstruction, MigrateStateToV2Meta, RemoveMaintainerMetaV2,
SetMaxValidationCommissionMeta,
},
state::{FeeRecipients, Lido, RewardDistribution},
state::{Criteria, FeeRecipients, Lido, RewardDistribution},
util::{serialize_b58, serialize_b58_slice},
};
use solido_cli_common::error::Abort;
Expand Down Expand Up @@ -472,11 +471,11 @@ enum SolidoInstruction {

fee_recipients: FeeRecipients,
},
SetMaxValidationCommission {
ChangeCriteria {
#[serde(serialize_with = "serialize_b58")]
solido_instance: Pubkey,

max_commission_percentage: u8,
criteria: Criteria,

#[serde(serialize_with = "serialize_b58")]
manager: Pubkey,
Expand Down Expand Up @@ -668,18 +667,28 @@ impl fmt::Display for ShowTransactionOutput {
print_changed_reward_distribution(f, current_solido, reward_distribution)?;
print_changed_recipients(f, current_solido, fee_recipients)?;
}
SolidoInstruction::SetMaxValidationCommission {
SolidoInstruction::ChangeCriteria {
solido_instance,
max_commission_percentage,
criteria,
manager,
} => {
writeln!(f, "It sets the maximum validation commission")?;
writeln!(f, "It sets the curation criteria")?;
writeln!(f, " Solido instance: {}", solido_instance)?;
writeln!(f, " Manager: {}", manager)?;
writeln!(
f,
" Max validation commission: {}%",
max_commission_percentage
" Max commission for validators: {}%",
criteria.max_commission,
)?;
writeln!(
f,
" Min vote success rate: {}%",
criteria.min_vote_success_rate,
)?;
writeln!(
f,
" Min block production rate: {}%",
criteria.min_block_production_rate,
)?;
}
SolidoInstruction::MigrateStateToV2 {
Expand Down Expand Up @@ -1065,13 +1074,11 @@ fn try_parse_solido_instruction(
maintainer_index,
})
}
LidoInstruction::SetMaxValidationCommission {
max_commission_percentage,
} => {
let accounts = SetMaxValidationCommissionMeta::try_from_slice(&instr.accounts)?;
ParsedInstruction::SolidoInstruction(SolidoInstruction::SetMaxValidationCommission {
LidoInstruction::ChangeCriteria { new_criteria } => {
let accounts = ChangeCriteriaMeta::try_from_slice(&instr.accounts)?;
ParsedInstruction::SolidoInstruction(SolidoInstruction::ChangeCriteria {
solido_instance: accounts.lido,
max_commission_percentage,
criteria: new_criteria,
manager: accounts.manager,
})
}
Expand Down

0 comments on commit 7cfaa21

Please sign in to comment.