Skip to content

Touches to StakingEscrow.sample()#1280

Merged
vepkenez merged 5 commits intonucypher:masterfrom
cygnusv:sample
Sep 3, 2019
Merged

Touches to StakingEscrow.sample()#1280
vepkenez merged 5 commits intonucypher:masterfrom
cygnusv:sample

Conversation

@cygnusv
Copy link
Member

@cygnusv cygnusv commented Aug 28, 2019

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)

}
if (sumOfLockedTokens > point) {
uint256 stakerTokens = getLockedTokens(info, currentPeriod, nextPeriod);
if (sumOfLockedTokens + stakerTokens > point) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Need to think if we need also sumOfLockedTokens <= point, otherwise all good

Copy link
Contributor

@michwill michwill left a comment

Choose a reason for hiding this comment

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

I think, it's almost off-WIP!

@cygnusv cygnusv changed the title [WIP] Touches to StakingEscrow.sample() Touches to StakingEscrow.sample() Sep 2, 2019
@cygnusv cygnusv marked this pull request as ready for review September 2, 2019 18:37
@cygnusv cygnusv mentioned this pull request Sep 2, 2019
@codecov
Copy link

codecov bot commented Sep 2, 2019

Codecov Report

Merging #1280 into master will increase coverage by 0.29%.
The diff coverage is 100%.

Impacted file tree graph

@@            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
Impacted Files Coverage Δ
nucypher/blockchain/eth/agents.py 90.22% <100%> (+5.41%) ⬆️
nucypher/policy/policies.py 85.57% <100%> (-0.24%) ⬇️
nucypher/blockchain/eth/token.py 87.95% <0%> (-1.62%) ⬇️
nucypher/blockchain/eth/actors.py 83.41% <0%> (-1.42%) ⬇️
nucypher/crypto/powers.py 94.26% <0%> (-0.32%) ⬇️
nucypher/blockchain/eth/interfaces.py 71.98% <0%> (ø) ⬆️
nucypher/config/storages.py 77.31% <0%> (ø) ⬆️
nucypher/network/nodes.py 79.5% <0%> (+0.27%) ⬆️
nucypher/characters/base.py 86.8% <0%> (+0.36%) ⬆️
... and 9 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update eda82cb...27d1109. Read the comment docs.

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}.')
Copy link
Member

Choose a reason for hiding this comment

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

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:

Suggested change
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}.')

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I think that's a good suggestion. Thanks @derekpierre !

Copy link
Member

Choose a reason for hiding this comment

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

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

@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...........
Copy link
Member

Choose a reason for hiding this comment

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

👍

Copy link
Contributor

@tuxxy tuxxy left a comment

Choose a reason for hiding this comment

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

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()
Copy link
Contributor

Choose a reason for hiding this comment

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

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)
Copy link
Contributor

Choose a reason for hiding this comment

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

👍

escrow.functions.sample([], 1).call()
with pytest.raises((TransactionFailed, ValueError)):
Copy link
Member

Choose a reason for hiding this comment

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

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.

Copy link
Member Author

Choose a reason for hiding this comment

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

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
Copy link
Member

Choose a reason for hiding this comment

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

Wondeful 👍

uint256 nextSumValue = sumOfLockedTokens.add(stakerTokens);

uint256 point = _points[pointIndex];
require(point >= previousPoint); // _points must be a sorted array
Copy link
Member

Choose a reason for hiding this comment

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

👍

@KPrasch
Copy link
Member

KPrasch commented Sep 3, 2019

I've reviewed this changeset, however I'd like to go through it with @szotov before giving approval.

@vepkenez vepkenez merged commit cae5247 into nucypher:master Sep 3, 2019
Copy link
Member

@vzotova vzotova left a comment

Choose a reason for hiding this comment

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

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
Copy link
Member

Choose a reason for hiding this comment

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

Just to clarify - no more selection buffer for federated policy, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

For N>=4, test_blockchain_ursulas_reencrypt fails with certain probability Test correct probability distribution of MinerAgent.sample()

7 participants