Step duration map configuration parameter ported from the POA Network fork#10902
Conversation
|
It looks like @vkomenda signed our Contributor License Agreement. 👍 Many thanks, Parity Technologies CLA Bot |
| }; | ||
| let step_durations: BTreeMap<u64, u16> = match p.step_duration { | ||
| StepDuration::Single(u) => iter::once((0, map_step_duration(u))).collect(), | ||
| StepDuration::Transitions(tr) => { |
There was a problem hiding this comment.
Do we verify there is at least one transition?
There was a problem hiding this comment.
In fact, we should verify that there is a transition for time 0, i.e. an initial step duration.
Edit: We actualy do that, in the first line of AuthorityRound::new.
| let mut prev_time = 0u64; | ||
| let next_step = self.load().checked_add(1)?; | ||
| for (time, dur) in self.durations.iter().skip(1) { | ||
| let step_diff = time.checked_add(prev_dur)?.checked_sub(1)?.checked_sub(prev_time)?.checked_div(prev_dur)?; |
There was a problem hiding this comment.
Can't we precompute timestamp->step conversion and store them in the BTreeMap instead of calculating it every time?
| }) | ||
| } | ||
|
|
||
| fn opt_duration_remaining(&self) -> Option<Duration> { |
There was a problem hiding this comment.
Would be good to have a comment of what (and how) we actually try to achieve in this function. It's not super clear to me. I suspect we want to calculate the remaining duration of current step taking into account potential transitions.
| let mut prev_step = 0u64; | ||
| let mut prev_time = 0u64; | ||
| let next_step = self.load().checked_add(1)?; | ||
| for (time, dur) in self.durations.iter().skip(1) { |
There was a problem hiding this comment.
Is this loop supposed to find the transition timestamp and duration of current step? If so I think it could be greately simplified (and optimized) by:
- Converting timestamps into step transitions + keeping the timestamps
- Bin searching in the step transitions to find current which transition we fall into and just use the pre-computed starting timestamp.
Instead of bin-searching I think we should rather start from the end, as that's a most likely case that we will fall into.
So to summarize, we need:
Vec<(StepTransition, TimestampTransition, StepDuration)>
Then you start from the end and check if next_step > StepTransition if it is you use TimestampTransition + (next_step - StepTransition) * StepDuration to compute the expected timestamp of the next step.
| } | ||
| let time = prev_time.checked_add(next_step.checked_sub(prev_step)?.checked_mul(prev_dur)?)?; | ||
| let step_end = Duration::from_secs(time); | ||
| if step_end > now { |
There was a problem hiding this comment.
You can use saturating_sub instead of this if-else
There was a problem hiding this comment.
I think Duration has no saturating_sub. But we could convert now to seconds and back, if you prefer.
(Sorry, already obsolete.)
| let mut prev_dur = u64::from(self.durations[&0]); | ||
| let mut prev_step = 0u64; | ||
| let mut prev_time = 0u64; | ||
| for (time, dur) in self.durations.range(..now).skip(1) { |
There was a problem hiding this comment.
This logic seems convoluted and duplicated, please at least refactor it to a single place.
| panic!("authority_round: step duration can't be zero") | ||
| if !our_params.step_durations.contains_key(&0) { | ||
| error!(target: "engine", "Authority Round step 0 duration is undefined, aborting"); | ||
| panic!("authority_round: step 0 duration is undefined") |
There was a problem hiding this comment.
Why do we panic instead of returning a proper error?
There was a problem hiding this comment.
It's not a question I can answer because the panic is already there. I can change it to returning an error though.
| /// Deliberately typed as u16 as too high of a value leads | ||
| /// to slow block issuance. | ||
| pub step_duration: u16, | ||
| /// Wait times (durations) are deliberately typed as `u16` since larger values lead to slow |
There was a problem hiding this comment.
We can still store u64 to avoid casting in the functions that use it and just validate when creating the params or the engine.
There was a problem hiding this comment.
Yes, we are already checking that the durations are in the range when receiving AuthorityRoundParams. I don't mind storing u64 in the map.
There was a problem hiding this comment.
But then I wonder whether u16::MAX is a good upper bound. This has nothing to do with the number of bits and should just be a threshold above which step durations don't make sense anymore. u16::MAX corresponds to about 18 hours. Should we set the limit to 24 hours (86400 seconds)?
| let engine = build_aura(|p| { | ||
| p.validators = Box::new(SimpleList::new(accounts.clone())); | ||
| p.step_duration = 4; | ||
| p.step_durations = [(0, 4)].to_vec().into_iter().collect(); |
There was a problem hiding this comment.
We need more tests for the actual transitions.
There was a problem hiding this comment.
I've added a test. Please let me know if you require more.
c4716fa to
fd14e77
Compare
| prev_step = *step; | ||
| prev_time = *time; | ||
| prev_dur = *dur; | ||
| } |
There was a problem hiding this comment.
Maybe simpler:
let (prev_dur, prev_step, prev_time) = self.durations.iter()
.take_while(|(_, step, _)| step < next_step)
.last()
.expect("durations cannot be empty")
.clone();(Also in opt_calibrate.)
There was a problem hiding this comment.
Actually, it's (step, _, _), which brings the question: do you think there should be a struct instead of the triple?
There was a problem hiding this comment.
Ah, sorry! But then it should also be:
let (prev_step, prev_dur, prev_time) = …A struct would avoid that kind of confusion, yes, but it's also a bit more verbose. Your call.
There was a problem hiding this comment.
It's (step, time, dur) and I dropped prev_ as redundant.
| let (mut prev_step, mut prev_time, mut prev_dur) = | ||
| self.durations.first().expect("durations cannot be empty"); | ||
| for (step, time, dur) in self.durations.iter().skip(1) { | ||
| if *time >= now { |
There was a problem hiding this comment.
Should this actually be strict? If time == now, I imagine we consider the new step to have started?
There was a problem hiding this comment.
You are right. == works better for Vec.
|
Are you happy with the way comments have been addressed? Is there anything else that could be improved? |
|
|
||
| type TransitionStep = u64; | ||
| type TransitionTimestamp = u64; | ||
| type StepDuration = u64; |
There was a problem hiding this comment.
was it changed to u64 to avoid casts?
There was a problem hiding this comment.
We have triples of u64 which needed some explanation in https://github.com/paritytech/parity-ethereum/blob/7863f8381a3790a3e62c605b6fc27c6c6b7fc5fe/ethcore/src/engines/authority_round/mod.rs#L157.
@ordian Would you prefer a struct type instead of plain triples?
There was a problem hiding this comment.
@vkomenda not sure if the fields would be named like transition_step, transition_timestamp, step_duration, it would be any clearer, but I don't have a strong preference here.
There was a problem hiding this comment.
@vkomenda not sure if the fields would be named like
transition_step, transition_timestamp, step_duration, it would be any clearer, but I don't have a strong preference here.
That might actually help to avoid confusing different fields when using the triple. I'll add that struct.
7863f83 to
0295f43
Compare
5ebf3eb to
55d3d0d
Compare
|
I rebased on |
55d3d0d to
6d2bf3c
Compare
|
Something seems to be wrong with CI. |
|
@afck Most likely yes and caused by a docker-related change that is missing on this branch. If you merge in master it should be alright. Sorry for the hassle! |
6d2bf3c to
94830d7
Compare
|
Seems all checks now have passed. Could we merge it then? |
* master: (21 commits) ropsten #6631425 foundation #8798209 (#11201) Update list of bootnodes for xDai chain (#11236) ethcore/res: add mordor testnet configuration (#11200) [chain specs]: activate `Istanbul` on mainnet (#11228) [builtin]: support `multiple prices and activations` in chain spec (#11039) Insert explicit warning into the panic hook (#11225) Snapshot restoration overhaul (#11219) Fix docker centos build (#11226) retry on gitlab system failures (#11222) Update bootnodes. (#11203) Use provided usd-per-eth value if an endpoint is specified (#11209) Use a lock instead of atomics for snapshot Progress (#11197) [informant]: `MillisecondDuration` -> `as_millis()` (#11211) Step duration map configuration parameter ported from the POA Network fork (#10902) Upgrade jsonrpc to latest (#11206) [export hardcoded sync]: use debug for `H256` (#11204) Pause pruning while snapshotting (#11178) Type annotation for next_key() matching of json filter options (#11192) Crypto primitives removed from ethkey (#11174) Made ecrecover implementation trait public (#11188) ...
The original PR: poanetwork#152.
Summary: Instead of a single step duration, this PR allows specifying time intervals with given step durations.