Skip to content
This repository has been archived by the owner on Jul 1, 2021. It is now read-only.

Avoid unnecessary clamp on previous_epoch by genesis_epoch #398

Closed

Conversation

ralexstokes
Copy link
Member

What was wrong?

Fixes #382.

How was it fixed?

Updated the calculation hanging off the BeaconState.

Cute Animal Picture

put a cute animal picture link inside the parentheses

@hwwhww hwwhww mentioned this pull request Mar 12, 2019
@ralexstokes ralexstokes force-pushed the fix-previous-epoch-calculation branch from 84b6913 to d8a230e Compare March 12, 2019 20:27
@@ -142,16 +140,25 @@ def get_winning_root(
def get_epoch_boundary_attester_indices(
Copy link
Member Author

Choose a reason for hiding this comment

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

looks like @hwwhww and @ChihChengLiang were involved here -- would love your input on this...

don't exactly like getting the block root inside this function (mainly bc we then have to monkeypatch it later to test it) but the way the spec is written we don't want to call this function unless there are some attestations in attestations.

open to changing this bit if we can think of a nicer/cleaner way.... i'll update if i think of something i like better

Copy link
Contributor

Choose a reason for hiding this comment

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

We don't want to call this function again and again for every attestations, either.
Maybe something like:

if len(attestations)>0:
    root = helpers.get_block_root(...)

Copy link
Member Author

Choose a reason for hiding this comment

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

@ChihChengLiang i don't follow -- given that we are iterating over attestations then we only call helpers.get_block_root if len(attestations)>0 so that condition would always be true....

i think what will be nicer is if I trace up the call stack here and just avoid calling this entirely -- it seems like there is only one place it is being called in the function that determines if the various epochs are even justifiable.

@ralexstokes
Copy link
Member Author

@hwwhww @ChihChengLiang this became more involved than the spec change would suggest (surprise!) but is ready for review -- i called attention to the part i'm not super excited about and would love to hear any thoughts!

@ralexstokes
Copy link
Member Author

Ok, I took advantage of some fresh helpers from spec version v0.5.0 which handle things like "previous epoch to genesis" gracefully...

I deleted the prior test for the function that no longer explicitly exists, with the understanding that it is only used by the function that gets the balances for the given boundary attestations which is already tested (if there is a bug in this covered function then it will fail the wrapping function's tests)

Copy link
Contributor

@hwwhww hwwhww left a comment

Choose a reason for hiding this comment

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

Some suggestions of the type hintings, the rest of the refactorings/spec sync look good to me. 👍

slot,
config.LATEST_BLOCK_ROOTS_LENGTH
)
]
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we would try to avoid returning mutable List.

state: 'BeaconState',
config: 'BeaconConfig') -> Tuple[Gwei, Gwei]:

config: 'BeaconConfig') -> Sequence[PendingAttestationRecord]:
Copy link
Contributor

Choose a reason for hiding this comment

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

As https://github.com/ethereum/snake-charmers-tactical-manual/blob/master/style-guide.md#function-variance mentioned, we should narrow down the scope of return type:

  • Normally, use Sequence for the input parameters.
  • If it returns known tuple, use Tuple for the return type.
  • If there's @to_tuple + yield for output, use Iterable for the return type.

Copy link
Member Author

Choose a reason for hiding this comment

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

good call -- as long as Tuple is a subtype of Sequence here then I'm happy w/ it :)

i don't know mypy well enough to answer this question but I suspect the subtyping relation holds...

config.MAX_DEPOSIT_AMOUNT,
def _get_previous_epoch_boundary_attestations(
state: 'BeaconState',
config: 'BeaconConfig') -> Sequence[PendingAttestationRecord]:
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

@hwwhww hwwhww requested a review from NIC619 March 14, 2019 06:57
Copy link
Contributor

@NIC619 NIC619 left a comment

Choose a reason for hiding this comment

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

LGTM!

slot = get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH)
return [
a for a in attestations
if a.data.epoch_boundary_root == get_block_root(
Copy link
Contributor

Choose a reason for hiding this comment

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

We can compute the epoch boundary root beforehand.

Copy link
Member Author

Choose a reason for hiding this comment

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

if you are referring to the call to get_block_root i started having the same thought but then i remembered why i was doing this in the first place.... and it was because we end up w/ a call to this function for essentially slots before the genesis epoch (where get_block_root will explode)

we purposefully put the call inside the conditional so that it is lazily evaluated.... if this becomes a hotspot perf-wise then we can do something like

slot = # ....
if len(attestations) != 0:
    block_root = get_block_root(...)
return tuple(
    a for a in ... # rest of expression
)

or even just add some memoization to this function.... tbh i don't expect we will need to do this in this case :)

@ralexstokes
Copy link
Member Author

@hwwhww would love your thoughts on what I did here 03d3ddf to satisfy mypy... i feel like the @to_tuple + generator expression is less efficient than what I had before but mypy was saying I would have to otherwise cast to a Tuple[T] (as the inferred type w/ the prior implementation was Tuple[T,...]

@ralexstokes ralexstokes force-pushed the fix-previous-epoch-calculation branch from 03d3ddf to 56c2f84 Compare March 15, 2019 00:56
@hwwhww
Copy link
Contributor

hwwhww commented Mar 17, 2019

@ralexstokes (sorry for the late reply!)
Yes, it seems right about how to make mypy happy - either @to_tuple + yield + Iterable or tuple comprehension + Tuple. IMO they are both fine as we can avoid List in both approaches.

/cc @pipermerriam any other trade-off here?

@ralexstokes
Copy link
Member Author

this got out of date -- i'll rebase and then merge this in

@ralexstokes ralexstokes force-pushed the fix-previous-epoch-calculation branch from 56c2f84 to 3931060 Compare March 28, 2019 23:41
@ralexstokes
Copy link
Member Author

Closing in favor of #469.

@ralexstokes ralexstokes deleted the fix-previous-epoch-calculation branch March 29, 2019 23:44
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make get_previous_epoch return current_epoch - 1 in all cases
4 participants