Skip to content

Commit d27a7f4

Browse files
authored
refactor + validator voting power threshold (#6)
* refactor + validator voting power threshold * improve threshold metrics * minors
1 parent ec16a5f commit d27a7f4

File tree

4 files changed

+102
-35
lines changed

4 files changed

+102
-35
lines changed

src/main.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,16 @@ async fn main() -> anyhow::Result<()> {
8484
.query_future_bonds_and_unbonds(epoch)
8585
.await
8686
.into_retry_error()?;
87+
let validators = rpc.query_validators(epoch).await.into_retry_error()?;
8788

8889
let mut post_state_lock = state.write().await;
89-
post_state_lock.update(block, total_supply_native, future_bonds, future_unbonds);
90+
post_state_lock.update(
91+
block,
92+
total_supply_native,
93+
future_bonds,
94+
future_unbonds,
95+
validators,
96+
);
9097
let post_state = post_state_lock.clone();
9198
drop(post_state_lock);
9299

src/rpc.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use tendermint_rpc::{HttpClient, Url};
1010

1111
use crate::shared::{
1212
checksums::Checksums,
13-
namada::{Address, Block, Epoch, Height},
13+
namada::{Address, Block, Epoch, Height, Validator},
1414
};
1515

1616
pub struct Rpc {
@@ -78,6 +78,26 @@ impl Rpc {
7878
.context("Should be able to query for block")
7979
}
8080

81+
pub async fn query_validators(&self, epoch: Epoch) -> anyhow::Result<Vec<Validator>> {
82+
let futures = self
83+
.clients
84+
.iter()
85+
.map(|client| rpc::get_all_consensus_validators(client, NamadaEpoch(epoch)).boxed());
86+
87+
let (res, _ready_future_index, _remaining_futures) =
88+
futures::future::select_all(futures).await;
89+
90+
res.context("Should be able to query native token")
91+
.map(|set| {
92+
set.into_iter()
93+
.map(|validator| Validator {
94+
address: validator.address.to_string(),
95+
voting_power: validator.bonded_stake.raw_amount().as_u64(),
96+
})
97+
.collect()
98+
})
99+
}
100+
81101
pub async fn query_native_token(&self) -> anyhow::Result<Address> {
82102
let futures = self
83103
.clients

src/shared/namada.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ pub type Epoch = u64;
1818
pub type TxId = String;
1919
pub type Address = String;
2020

21+
#[derive(Clone, Debug)]
22+
pub struct Validator {
23+
pub address: String,
24+
pub voting_power: u64,
25+
}
26+
2127
#[derive(Clone, Debug)]
2228
pub struct Block {
2329
pub height: Height,

src/state.rs

Lines changed: 67 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ use std::num::NonZeroUsize;
33
use lru::LruCache;
44
use prometheus_exporter::prometheus::{
55
core::{AtomicU64, GenericCounter, GenericCounterVec},
6-
Histogram, HistogramOpts, IntCounterVec, Opts, Registry,
6+
GaugeVec, Histogram, HistogramOpts, IntCounterVec, Opts, Registry,
77
};
88

99
use crate::shared::{
1010
checksums::Checksums,
11-
namada::{Block, Height},
11+
namada::{Block, Height, Validator},
1212
};
1313

1414
#[derive(Debug, Clone)]
@@ -26,10 +26,11 @@ pub struct PrometheusMetrics {
2626
pub block_height_counter: GenericCounter<AtomicU64>,
2727
pub epoch_counter: GenericCounter<AtomicU64>,
2828
pub total_supply_native_token: GenericCounter<AtomicU64>,
29+
pub one_third_threshold: GaugeVec,
30+
pub two_third_threshold: GaugeVec,
2931
pub transaction_size: Histogram,
30-
pub transaction_inner_size: Histogram,
31-
pub bonds_per_epoch: GenericCounterVec<AtomicU64>,
32-
pub unbonds_per_epoch: GenericCounterVec<AtomicU64>,
32+
pub bonds_per_epoch: GaugeVec,
33+
pub unbonds_per_epoch: GaugeVec,
3334
pub transaction_kind: GenericCounterVec<AtomicU64>,
3435
registry: Registry,
3536
}
@@ -51,34 +52,40 @@ impl PrometheusMetrics {
5152
let epoch_counter = GenericCounter::<AtomicU64>::new("epoch", "the latest epoch recorded")
5253
.expect("unable to create counter epoch");
5354

55+
let one_third_threshold_opts = Opts::new(
56+
"one_third_threshold",
57+
"The number of validators to reach 1/3 of the voting power",
58+
);
59+
let one_third_threshold = GaugeVec::new(one_third_threshold_opts, &["epoch"])
60+
.expect("unable to create counter one third threshold");
61+
62+
let two_third_threshold_opts = Opts::new(
63+
"two_third_threshold",
64+
"The number of validators to reach 2/3 of the voting power",
65+
);
66+
let two_third_threshold = GaugeVec::new(two_third_threshold_opts, &["epoch"])
67+
.expect("unable to create counter two third threshold");
68+
5469
let total_supply_native_token = GenericCounter::<AtomicU64>::new(
5570
"total_supply_native_token",
5671
"the latest total supply native token recorded",
5772
)
5873
.expect("unable to create counter total supply");
5974

6075
let transaction_size_opts = HistogramOpts::new(
61-
"transaction_size_bytes",
62-
"The sizes of transactions in bytes",
76+
"transaction_batch_size",
77+
"The number of inner transactions in a batch",
6378
)
64-
.buckets(vec![
65-
10.0, 50.0, 100.0, 500.0, 1000.0, 5000.0, 10000.0, 50000.0,
66-
]);
79+
.buckets(vec![1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0]);
6780
let transaction_size = Histogram::with_opts(transaction_size_opts)
6881
.expect("unable to create histogram transaction sizes");
6982

70-
let transaction_inner_size_opts =
71-
HistogramOpts::new("transaction_inners", "The number of inner tx for a wrapper")
72-
.buckets(vec![2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0]);
73-
let transaction_inner_size = Histogram::with_opts(transaction_inner_size_opts)
74-
.expect("unable to create histogram transaction sizes");
75-
7683
let bonds_per_epoch_opts = Opts::new("bonds_per_epoch", "Total bonds per epoch");
77-
let bonds_per_epoch = IntCounterVec::new(bonds_per_epoch_opts, &["epoch"])
84+
let bonds_per_epoch = GaugeVec::new(bonds_per_epoch_opts, &["epoch"])
7885
.expect("unable to create histogram transaction sizes");
7986

8087
let unbonds_per_epoch_opts = Opts::new("unbonds_per_epoch", "Total unbonds per epoch");
81-
let unbonds_per_epoch = IntCounterVec::new(unbonds_per_epoch_opts, &["epoch"])
88+
let unbonds_per_epoch = GaugeVec::new(unbonds_per_epoch_opts, &["epoch"])
8289
.expect("unable to create histogram transaction sizes");
8390

8491
let transaction_kind_opts =
@@ -94,6 +101,12 @@ impl PrometheusMetrics {
94101
registry
95102
.register(Box::new(total_supply_native_token.clone()))
96103
.unwrap();
104+
registry
105+
.register(Box::new(one_third_threshold.clone()))
106+
.unwrap();
107+
registry
108+
.register(Box::new(two_third_threshold.clone()))
109+
.unwrap();
97110
registry
98111
.register(Box::new(transaction_size.clone()))
99112
.unwrap();
@@ -111,8 +124,9 @@ impl PrometheusMetrics {
111124
block_height_counter,
112125
epoch_counter,
113126
total_supply_native_token,
127+
one_third_threshold,
128+
two_third_threshold,
114129
transaction_size,
115-
transaction_inner_size,
116130
bonds_per_epoch,
117131
unbonds_per_epoch,
118132
transaction_kind,
@@ -153,6 +167,7 @@ impl State {
153167
total_supply_native: u64,
154168
future_bonds: u64,
155169
future_unbonds: u64,
170+
mut validators: Vec<Validator>,
156171
) {
157172
if let Some(height) = self.latest_block_height {
158173
self.metrics
@@ -185,7 +200,7 @@ impl State {
185200

186201
for tx in &block.transactions {
187202
self.metrics
188-
.transaction_inner_size
203+
.transaction_size
189204
.observe(tx.inners.len() as f64);
190205
}
191206

@@ -201,30 +216,49 @@ impl State {
201216
&block.height.to_string(),
202217
])
203218
.inc();
204-
205-
self.metrics
206-
.transaction_size
207-
.observe(inner.kind.size() as f64);
208219
}
209220
}
210221

222+
validators.sort_by_key(|validator| validator.voting_power);
223+
validators.reverse();
224+
let total_voting_power = validators
225+
.iter()
226+
.map(|validator| validator.voting_power)
227+
.sum::<u64>();
228+
let one_third_voting_power = total_voting_power / 3;
229+
let two_third_voting_power = total_voting_power * 2 / 3;
230+
let (one_third_threshold, _) = validators.iter().fold((0, 0), |(index, acc), validator| {
231+
if acc >= one_third_voting_power {
232+
(index, acc)
233+
} else {
234+
(index + 1, acc + validator.voting_power)
235+
}
236+
});
237+
238+
let (two_third_threshold, _) = validators.iter().fold((0, 0), |(index, acc), validator| {
239+
if acc >= two_third_voting_power {
240+
(index, acc)
241+
} else {
242+
(index + 1, acc + validator.voting_power)
243+
}
244+
});
211245
self.metrics
212-
.bonds_per_epoch
213-
.with_label_values(&[&(block.epoch + 1).to_string()])
214-
.reset();
246+
.one_third_threshold
247+
.with_label_values(&[&block.epoch.to_string()])
248+
.set(one_third_threshold as f64);
215249
self.metrics
216-
.bonds_per_epoch
217-
.with_label_values(&[&(block.epoch + 1).to_string()])
218-
.inc_by(future_bonds);
250+
.two_third_threshold
251+
.with_label_values(&[&block.epoch.to_string()])
252+
.set(two_third_threshold as f64);
219253

220254
self.metrics
221-
.unbonds_per_epoch
255+
.bonds_per_epoch
222256
.with_label_values(&[&(block.epoch + 1).to_string()])
223-
.reset();
257+
.set(future_bonds as f64);
224258
self.metrics
225259
.unbonds_per_epoch
226260
.with_label_values(&[&(block.epoch + 1).to_string()])
227-
.inc_by(future_unbonds);
261+
.set(future_unbonds as f64);
228262

229263
self.blocks.put(block.height, block);
230264
}

0 commit comments

Comments
 (0)