Touches to StakingEscrow.sample()#1280
Conversation
| } | ||
| if (sumOfLockedTokens > point) { | ||
| uint256 stakerTokens = getLockedTokens(info, currentPeriod, nextPeriod); | ||
| if (sumOfLockedTokens + stakerTokens > point) { |
There was a problem hiding this comment.
Need to think if we need also sumOfLockedTokens <= point, otherwise all good
michwill
left a comment
There was a problem hiding this comment.
I think, it's almost off-WIP!
Codecov Report
@@ Coverage Diff @@
## master #1280 +/- ##
==========================================
+ Coverage 82.07% 82.36% +0.29%
==========================================
Files 72 72
Lines 9959 9948 -11
==========================================
+ Hits 8174 8194 +20
+ Misses 1785 1754 -31
Continue to review full report at Codecov.
|
| raise self.NotEnoughStakers(f'There are {stakers_population} published stakers, need a total of {quantity}.') | ||
| n_select = math.ceil(quantity * additional_ursulas) # Select more Ursulas | ||
| if n_select > stakers_population: | ||
| raise self.NotEnoughStakers(f'There are {stakers_population} active stakers, need at least {n_select}.') |
There was a problem hiding this comment.
Should we clarify that we need a sample that may be larger than the quantity specified. As a user I may be confused that I get a NotEnoughStakers exception if I specify n = 6 and there are 6 active stakers that randomly says some value eg. need at least 9 (assuming additional_ursulas is 1.5)
Perhaps our message could be:
| raise self.NotEnoughStakers(f'There are {stakers_population} active stakers, need at least {n_select}.') | |
| raise self.NotEnoughStakers(f'There are {stakers_population} active stakers - for {quantity} stakers we need a sample size of at least {n_select}.') |
There was a problem hiding this comment.
Yes, I think that's a good suggestion. Thanks @derekpierre !
There was a problem hiding this comment.
Does additional_ursulas still make sense as a static value? For such small m of n values, a proportional, smaller value might be more usable.
There was a problem hiding this comment.
@derekpierre sorry I didn't include this in #1280. I'll do that in #1259.
@KPrasch Although in the method signature there's a static default, in reality it's always called explicitly with the BlockchainPolicy.selection_buffer value as defined in BlockchainPolicy.sample_essential(). We however don't configure BlockchainPolicy.selection_buffer yet, so for the moment it always uses the default value of 1.5. That's why #1061 is still open.
| * For example: | ||
| * | ||
| * Stakes: |----- S0 ----|--------- S1 ---------|-- S2 --|---- S3 ---|-S4-|----- S5 -----| | ||
| * Points: ....R0.......................R1..................R2...............R3........... |
tuxxy
left a comment
There was a problem hiding this comment.
Great additions, especially the neat test. 🐧
| handpicked_ursulas = set() | ||
| else: | ||
| handpicked_ursulas = set(handpicked_ursulas) | ||
| selected_ursulas = set(handpicked_ursulas) if handpicked_ursulas else set() |
There was a problem hiding this comment.
I'm not a fan of these little one-liners, but this is readable enough. :)
| if target_sample_quantity > 0: | ||
| sampled_ursulas = self.sample_essential(quantity=target_sample_quantity, | ||
| handpicked_ursulas=handpicked_ursulas) | ||
| selected_ursulas.update(sampled_ursulas) |
| escrow.functions.sample([], 1).call() | ||
| with pytest.raises((TransactionFailed, ValueError)): |
There was a problem hiding this comment.
Just a note - By removing the handling of ValueError, the test suite is less compatible with other backends, like geth, since the exception is EthereumTester-specific. Unsure if this is a reasonable goal for us, but I'd like to remain open to the possibility of running the test suite without eth-tester.
There was a problem hiding this comment.
Oh so that's why! I always found weird those lines. In any case, if that's the reason, isn't it better that we have something like:
TransactionException = TransactionFailed if using_eth_tester() else ValueError
...
with pytest.raises(TransactionException):
foo.bar()Otherwise, there may be the case that in our current setting the method being tested is currently raising a legitimateValueError not caused by a failed transaction and we're accepting that as valid.
| SAMPLES = 100 | ||
| quantity = 3 | ||
| import random | ||
| from collections import Counter |
| uint256 nextSumValue = sumOfLockedTokens.add(stakerTokens); | ||
|
|
||
| uint256 point = _points[pointIndex]; | ||
| require(point >= previousPoint); // _points must be a sorted array |
|
I've reviewed this changeset, however I'd like to go through it with @szotov before giving approval. |
vzotova
left a comment
There was a problem hiding this comment.
I like those changes and tests!
from logic point of view everything is great,
from optimization part - for big stakers (multiple point in one staker) sample in contract will call getLockedTokens multiple times, so method will work sligtly slower, but off corse it's not a problem for external call function
| selected_ursulas = set(handpicked_ursulas) if handpicked_ursulas else set() | ||
|
|
||
| # Calculate the target sample quantity | ||
| ADDITIONAL_URSULAS = self.selection_buffer |
There was a problem hiding this comment.
Just to clarify - no more selection buffer for federated policy, right?
Corrects a minor bug in
StakingEscrow.sample()that was affecting sampling (Fixes #1090)Also adds a test that checks that sampling produces an acceptable distribution (Closes #1019)