Skip to content

Commit f6fc53d

Browse files
authored
ENG-624: Vote throttling (#646)
1 parent 5ade62b commit f6fc53d

4 files changed

Lines changed: 23 additions & 3 deletions

File tree

fendermint/app/config/default.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,10 @@ rate_limit_period = 0
193193

194194
# IPC related configuration parameters
195195
[ipc]
196+
# Default subnet ID, which basically means IPC is disabled.
196197
subnet_id = "/r0"
198+
# Voting interval about things such as the top-down finality, in seconds.
199+
# It's limited to avoid GossipSub throttling or banning the node for over production.
200+
# The minimum is 1 seconds which is about the minimum target block time as well;
201+
# ideally one round of gossip per block should be as frequent as we would go.
202+
vote_interval = 1

fendermint/app/settings/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ pub struct TopDownSettings {
141141
pub struct IpcSettings {
142142
#[serde_as(as = "IsHumanReadable")]
143143
pub subnet_id: SubnetID,
144+
/// Interval with which votes can be gossiped.
145+
#[serde_as(as = "DurationSeconds<u64>")]
146+
pub vote_interval: Duration,
144147
/// The config for top down checkpoint. It's None if subnet id is root or not activating
145148
/// any top down checkpoint related operations
146149
pub topdown: Option<TopDownSettings>,

fendermint/app/src/cmd/run.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ async fn run(settings: Settings) -> anyhow::Result<()> {
159159
tokio::spawn(async move {
160160
publish_vote_loop(
161161
parent_finality_votes,
162+
settings.ipc.vote_interval,
162163
key,
163164
own_subnet_id,
164165
client,

fendermint/vm/topdown/src/voting.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
use async_stm::{abort, atomically_or_err, retry, Stm, StmResult, TVar};
55
use serde::{de::DeserializeOwned, Serialize};
6-
use std::fmt::Debug;
76
use std::hash::Hash;
7+
use std::{fmt::Debug, time::Duration};
88

99
use crate::{BlockHash, BlockHeight};
1010

@@ -322,6 +322,7 @@ where
322322
/// Poll the vote tally for new finalized blocks and publish a vote about them if the validator is part of the power table.
323323
pub async fn publish_vote_loop<V, F>(
324324
vote_tally: VoteTally,
325+
vote_interval: Duration,
325326
key: libp2p::identity::Keypair,
326327
subnet_id: ipc_api::subnet_id::SubnetID,
327328
client: ipc_ipld_resolver::Client<V>,
@@ -331,7 +332,12 @@ pub async fn publish_vote_loop<V, F>(
331332
V: Serialize + DeserializeOwned,
332333
{
333334
let validator_key = ValidatorKey::from(key.public());
335+
336+
let mut vote_interval = tokio::time::interval(vote_interval);
337+
vote_interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
338+
334339
let mut prev_height = 0;
340+
335341
loop {
336342
let result = atomically_or_err(|| {
337343
let next_height = vote_tally.latest_height()?;
@@ -367,8 +373,6 @@ pub async fn publish_vote_loop<V, F>(
367373
}
368374
};
369375

370-
// TODO (ENG-624): Throttle vote gossiping at periods of fast syncing.
371-
372376
if has_power && prev_height > 0 {
373377
tracing::debug!(block_height = next_height, "publishing finality vote");
374378
match VoteRecord::signed(&key, subnet_id.clone(), to_vote(next_height, next_hash)) {
@@ -381,6 +385,12 @@ pub async fn publish_vote_loop<V, F>(
381385
tracing::error!(error = e.to_string(), "failed to sign vote");
382386
}
383387
}
388+
389+
// Throttle vote gossiping at periods of fast syncing. For example if we create a subnet contract on Friday
390+
// and bring up a local testnet on Monday, all nodes would be ~7000 blocks behind a Lotus parent. CometBFT
391+
// would be in-sync, and they could rapidly try to gossip votes on previous heights. GossipSub might not like
392+
// that, and we can just cast our votes every now and then to finalize multiple blocks.
393+
vote_interval.tick().await;
384394
}
385395

386396
prev_height = next_height;

0 commit comments

Comments
 (0)