Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,7 @@ impl pallet_conviction_voting::Config for Runtime {

parameter_types! {
pub const AlarmInterval: BlockNumber = 1;
pub const MinAlarmInterval: BlockNumber = 1;
pub const SubmissionDeposit: Balance = 100 * DOLLARS;
pub const UndecidingTimeout: BlockNumber = 28 * DAYS;
}
Expand Down Expand Up @@ -870,6 +871,7 @@ impl pallet_referenda::Config for Runtime {
type MaxQueued = ConstU32<100>;
type UndecidingTimeout = UndecidingTimeout;
type AlarmInterval = AlarmInterval;
type MinAlarmInterval = MinAlarmInterval;
type Tracks = TracksInfo;
type Preimages = Preimage;
}
Expand Down
84 changes: 50 additions & 34 deletions frame/referenda/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,12 +195,17 @@ pub mod pallet {
#[pallet::constant]
type UndecidingTimeout: Get<Self::BlockNumber>;

/// Quantization level for the referendum wakeup scheduler. A higher number will result in
/// fewer storage reads/writes needed for smaller voters, but also result in delays to the
/// automatic referendum status changes. Explicit servicing instructions are unaffected.
/// Quantization level for the referendum wakeup scheduler during the decision stage. A
/// higher number will result in fewer storage reads/writes needed for smaller voters, but
/// also result in delays to the automatic referendum status changes.
#[pallet::constant]
type AlarmInterval: Get<Self::BlockNumber>;

/// Minimum alarm period for the referendum wakeup scheduler during the decision stage.
/// Prevents wake up calls from being too frequent as a result of the quantization.
#[pallet::constant]
type MinAlarmPeriod: Get<Self::BlockNumber>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the actual use-case for this?


// The other stuff.
/// Information concerning the different referendum tracks.
#[pallet::constant]
Expand Down Expand Up @@ -754,9 +759,6 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
call: BoundedCallOf<T, I>,
when: T::BlockNumber,
) -> Option<(T::BlockNumber, ScheduleAddressOf<T, I>)> {
let alarm_interval = T::AlarmInterval::get().max(One::one());
let when = when.saturating_add(alarm_interval).saturating_sub(One::one()) /
(alarm_interval.saturating_mul(alarm_interval)).max(One::one());
Copy link
Contributor Author

@muharem muharem Nov 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its probably supposed to be calculated from the duration.

I moved this logic to decision_alarm, because we need the quantization only for the decision period.
The preparation and confirmation period has to pass fully for each stage, at least this how I understand it.

let maybe_result = T::Scheduler::schedule(
DispatchTime::At(when),
None,
Expand Down Expand Up @@ -802,19 +804,18 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
proposal: status.proposal.clone(),
track: status.track,
});
let confirming = if is_passing {
if is_passing {
Self::deposit_event(Event::<T, I>::ConfirmStarted { index });
Some(now.saturating_add(track.confirm_period))
let confirming = Some(now.saturating_add(track.confirm_period.max(One::one())));
status.deciding = Some(DecidingStatus { since: now, confirming });
(confirming, BeginDecidingBranch::Passing)
} else {
None
};
let deciding_status = DecidingStatus { since: now, confirming };
let alarm = Self::decision_time(&deciding_status, &status.tally, status.track, track)
.max(now.saturating_add(One::one()));
status.deciding = Some(deciding_status);
let branch =
if is_passing { BeginDecidingBranch::Passing } else { BeginDecidingBranch::Failing };
(Some(alarm), branch)
status.deciding = Some(DecidingStatus { since: now, confirming: None });
(
Some(Self::decision_alarm(now, now, &status.tally, status.track, track)),
BeginDecidingBranch::Failing,
)
}
}

/// If it returns `Some`, deciding has begun and it needs waking at the given block number. The
Expand Down Expand Up @@ -861,10 +862,9 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// overall more efficient), however the weights become rather less easy to measure.
fn note_one_fewer_deciding(track: TrackIdOf<T, I>) {
// Set an alarm call for the next block to nudge the track along.
let min_alarm_period = T::MinAlarmPeriod::get().max(One::one());
let now = frame_system::Pallet::<T>::block_number();
let next_block = now + One::one();
let alarm_interval = T::AlarmInterval::get().max(One::one());
let when = (next_block + alarm_interval - One::one()) / alarm_interval * alarm_interval;
let when = now.saturating_add(min_alarm_period);

let call = match T::Preimages::bound(CallOf::<T, I>::from(Call::one_fewer_deciding {
track,
Expand Down Expand Up @@ -1081,31 +1081,47 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
ServiceBranch::ContinueNotConfirming
}
};
alarm = Self::decision_time(deciding, &status.tally, status.track, track);
alarm = deciding.confirming.unwrap_or_else(|| {
Self::decision_alarm(now, deciding.since, &status.tally, status.track, track)
});
},
}

let dirty_alarm = Self::ensure_alarm_at(&mut status, index, alarm);
(ReferendumInfo::Ongoing(status), dirty_alarm || dirty, branch)
}

/// Determine the point at which a referendum will be accepted, move into confirmation with the
/// given `tally` or end with rejection (whichever happens sooner).
fn decision_time(
deciding: &DecidingStatusOf<T>,
/// Determine the block of the next alarm for a decision check based on the current voting,
/// total decision period and the alarm interval.
fn decision_alarm(
now: T::BlockNumber,
deciding_since: T::BlockNumber,
tally: &T::Tally,
track_id: TrackIdOf<T, I>,
track: &TrackInfoOf<T, I>,
) -> T::BlockNumber {
deciding.confirming.unwrap_or_else(|| {
// Set alarm to the point where the current voting would make it pass.
let approval = tally.approval(track_id);
let support = tally.support(track_id);
let until_approval = track.min_approval.delay(approval);
let until_support = track.min_support.delay(support);
let offset = until_support.max(until_approval);
deciding.since.saturating_add(offset * track.decision_period)
})
// find a period offset where the current voting would make it pass.
let approval = tally.approval(track_id);
let support = tally.support(track_id);
let until_approval = track.min_approval.delay(approval);
let until_support = track.min_support.delay(support);
// if never passing the offset is 1.
let offset = until_support.max(until_approval);
deciding_since
.saturating_add(now.saturating_sub(deciding_since))
.saturating_add(Self::decision_interval(
offset * track.decision_period.saturating_sub(now.saturating_sub(deciding_since)),
))
}

/// Determine the decision period interval based on the total period and the alarm interval.
fn decision_interval(decision_period: T::BlockNumber) -> T::BlockNumber {
let min_alarm_period = T::MinAlarmPeriod::get().max(One::one());
let alarm_interval = T::AlarmInterval::get().max(One::one());
let decision_period =
decision_period.saturating_add(alarm_interval).saturating_sub(One::one()) /
(alarm_interval.saturating_mul(alarm_interval)).max(One::one());
decision_period.max(min_alarm_period)
}

/// Cancel the alarm in `status`, if one exists.
Expand Down
2 changes: 2 additions & 0 deletions frame/referenda/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ impl pallet_balances::Config for Test {
}
parameter_types! {
pub static AlarmInterval: u64 = 1;
pub static MinAlarmInterval: u64 = 1;
}
ord_parameter_types! {
pub const One: u64 = 1;
Expand Down Expand Up @@ -226,6 +227,7 @@ impl Config for Test {
type MaxQueued = ConstU32<3>;
type UndecidingTimeout = ConstU64<20>;
type AlarmInterval = AlarmInterval;
type MinAlarmPeriod = MinAlarmInterval;
type Tracks = TestTracksInfo;
type Preimages = Preimage;
}
Expand Down